diff options
author | chai <chaifix@163.com> | 2021-04-07 21:33:14 +0800 |
---|---|---|
committer | chai <chaifix@163.com> | 2021-04-07 21:33:14 +0800 |
commit | c47b92e92cf33ae8bf2f38929e137294397e4735 (patch) | |
tree | c67ae3419eaf15e84f1679186e107f598de33978 /Assets/Scripts/Common |
Diffstat (limited to 'Assets/Scripts/Common')
-rw-r--r-- | Assets/Scripts/Common/BaseMaterialEffect.cs | 193 | ||||
-rw-r--r-- | Assets/Scripts/Common/BaseMaterialEffect.cs.meta | 12 | ||||
-rw-r--r-- | Assets/Scripts/Common/BaseMeshEffect.cs | 229 | ||||
-rw-r--r-- | Assets/Scripts/Common/BaseMeshEffect.cs.meta | 11 | ||||
-rw-r--r-- | Assets/Scripts/Common/EffectPlayer.cs | 154 | ||||
-rw-r--r-- | Assets/Scripts/Common/EffectPlayer.cs.meta | 12 | ||||
-rw-r--r-- | Assets/Scripts/Common/GraphicConnector.cs | 151 | ||||
-rw-r--r-- | Assets/Scripts/Common/GraphicConnector.cs.meta | 11 | ||||
-rw-r--r-- | Assets/Scripts/Common/MaterialCache.cs | 77 | ||||
-rw-r--r-- | Assets/Scripts/Common/MaterialCache.cs.meta | 12 | ||||
-rw-r--r-- | Assets/Scripts/Common/Matrix2x3.cs | 33 | ||||
-rw-r--r-- | Assets/Scripts/Common/Matrix2x3.cs.meta | 12 | ||||
-rw-r--r-- | Assets/Scripts/Common/Packer.cs | 61 | ||||
-rw-r--r-- | Assets/Scripts/Common/Packer.cs.meta | 12 | ||||
-rw-r--r-- | Assets/Scripts/Common/ParameterTexture.cs | 190 | ||||
-rw-r--r-- | Assets/Scripts/Common/ParameterTexture.cs.meta | 12 |
16 files changed, 1182 insertions, 0 deletions
diff --git a/Assets/Scripts/Common/BaseMaterialEffect.cs b/Assets/Scripts/Common/BaseMaterialEffect.cs new file mode 100644 index 0000000..0cf2d7a --- /dev/null +++ b/Assets/Scripts/Common/BaseMaterialEffect.cs @@ -0,0 +1,193 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using UnityEngine; +using UnityEngine.UI; + +namespace Coffee.UIEffects +{ + /// <summary> + /// Abstract effect base for UI. + /// </summary> + [DisallowMultipleComponent] + public abstract class BaseMaterialEffect : BaseMeshEffect, IParameterTexture, IMaterialModifier + { + protected static readonly Hash128 k_InvalidHash = new Hash128(); + protected static readonly List<UIVertex> s_TempVerts = new List<UIVertex>(); + private static readonly StringBuilder s_StringBuilder = new StringBuilder(); + + Hash128 _effectMaterialHash; + + /// <summary> + /// Gets or sets the parameter index. + /// </summary> + public int parameterIndex { get; set; } + + /// <summary> + /// Gets the parameter texture. + /// </summary> + public virtual ParameterTexture paramTex + { + get { return null; } + } + + /// <summary> + /// Mark the vertices as dirty. + /// </summary> + public void SetMaterialDirty() + { + connector.SetMaterialDirty(graphic); + + foreach (var effect in syncEffects) + { + effect.SetMaterialDirty(); + } + } + + public virtual Hash128 GetMaterialHash(Material baseMaterial) + { + return k_InvalidHash; + } + + public Material GetModifiedMaterial(Material baseMaterial) + { + return GetModifiedMaterial(baseMaterial, graphic); + } + + public virtual Material GetModifiedMaterial(Material baseMaterial, Graphic graphic) + { + if (!isActiveAndEnabled) return baseMaterial; + + var oldHash = _effectMaterialHash; + _effectMaterialHash = GetMaterialHash(baseMaterial); + var modifiedMaterial = baseMaterial; + if (_effectMaterialHash.isValid) + { + modifiedMaterial = MaterialCache.Register(baseMaterial, _effectMaterialHash, ModifyMaterial, graphic); + } + + MaterialCache.Unregister(oldHash); + + return modifiedMaterial; + } + + // protected bool isTMProMobile (Material material) + // { + // return material && material.shader && material.shader.name.StartsWith ("TextMeshPro/Mobile/", StringComparison.Ordinal); + // } + + public virtual void ModifyMaterial(Material newMaterial, Graphic graphic) + { + if (isActiveAndEnabled && paramTex != null) + paramTex.RegisterMaterial(newMaterial); + } + + protected void SetShaderVariants(Material newMaterial, params object[] variants) + { + // Set shader keywords as variants + var keywords = variants.Where(x => 0 < (int) x) + .Select(x => x.ToString().ToUpper()) + .Concat(newMaterial.shaderKeywords) + .Distinct() + .ToArray(); + newMaterial.shaderKeywords = keywords; + + // Add variant name + s_StringBuilder.Length = 0; + s_StringBuilder.Append(Path.GetFileName(newMaterial.shader.name)); + foreach (var keyword in keywords) + { + s_StringBuilder.Append("-"); + s_StringBuilder.Append(keyword); + } + + newMaterial.name = s_StringBuilder.ToString(); + } + +#if UNITY_EDITOR + protected override void Reset() + { + if (!isActiveAndEnabled) return; + SetMaterialDirty(); + SetVerticesDirty(); + SetEffectParamsDirty(); + } + + protected override void OnValidate() + { + if (!isActiveAndEnabled) return; + SetVerticesDirty(); + SetEffectParamsDirty(); + } +#endif + + /// <summary> + /// This function is called when the object becomes enabled and active. + /// </summary> + protected override void OnEnable() + { + base.OnEnable(); + + if (paramTex != null) + { + paramTex.Register(this); + } + + SetMaterialDirty(); + SetEffectParamsDirty(); + + // foreach (var mr in GetComponentsInChildren<UIEffectMaterialResolver> ()) + // { + // mr.GetComponent<Graphic> ().SetMaterialDirty (); + // mr.GetComponent<Graphic> ().SetVerticesDirty (); + // } + } + + /// <summary> + /// This function is called when the behaviour becomes disabled () or inactive. + /// </summary> + protected override void OnDisable() + { + base.OnDisable(); + + SetMaterialDirty(); + + if (paramTex != null) + { + paramTex.Unregister(this); + } + + MaterialCache.Unregister(_effectMaterialHash); + _effectMaterialHash = k_InvalidHash; + } + + // protected override void OnDidApplyAnimationProperties() + // { + // SetEffectParamsDirty(); + // } + + // protected override void OnTextChanged (UnityEngine.Object obj) + // { + // base.OnTextChanged (obj); + // + // + // foreach (var sm in GetComponentsInChildren<TMPro.TMP_SubMeshUI> ()) + // { + // if(!sm.GetComponent<UIEffectMaterialResolver>()) + // { + // var mr = sm.gameObject.AddComponent<UIEffectMaterialResolver> (); + // + // targetGraphic.SetAllDirty (); + // //targetGraphic.SetVerticesDirty (); + // + // //mr.GetComponent<Graphic> ().SetMaterialDirty (); + // //mr.GetComponent<Graphic> ().SetVerticesDirty (); + // + // + // } + // } + // } + } +} diff --git a/Assets/Scripts/Common/BaseMaterialEffect.cs.meta b/Assets/Scripts/Common/BaseMaterialEffect.cs.meta new file mode 100644 index 0000000..7b7e351 --- /dev/null +++ b/Assets/Scripts/Common/BaseMaterialEffect.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: e8b7ed62cf1444b4ebfc5e5338bc6682 +timeCreated: 1485321967 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Common/BaseMeshEffect.cs b/Assets/Scripts/Common/BaseMeshEffect.cs new file mode 100644 index 0000000..40d4e66 --- /dev/null +++ b/Assets/Scripts/Common/BaseMeshEffect.cs @@ -0,0 +1,229 @@ +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.EventSystems; +using UnityEngine.UI; + +namespace Coffee.UIEffects +{ + /// <summary> + /// Base class for effects that modify the generated Mesh. + /// It works well not only for standard Graphic components (Image, RawImage, Text, etc.) but also for TextMeshPro and TextMeshProUGUI. + /// </summary> + [RequireComponent(typeof(Graphic))] + [RequireComponent(typeof(RectTransform))] + [ExecuteInEditMode] + public abstract class BaseMeshEffect : UIBehaviour, IMeshModifier + { + RectTransform _rectTransform; + Graphic _graphic; + GraphicConnector _connector; + + /// <summary> + /// The Graphic attached to this GameObject. + /// </summary> + protected GraphicConnector connector + { + get { return _connector ?? (_connector = GraphicConnector.FindConnector(graphic)); } + } + + /// <summary> + /// The Graphic attached to this GameObject. + /// </summary> + public Graphic graphic + { + get { return _graphic ? _graphic : _graphic = GetComponent<Graphic>(); } + } + + /// <summary> + /// The RectTransform attached to this GameObject. + /// </summary> + protected RectTransform rectTransform + { + get { return _rectTransform ? _rectTransform : _rectTransform = GetComponent<RectTransform>(); } + } + + internal readonly List<UISyncEffect> syncEffects = new List<UISyncEffect>(0); + + /// <summary> + /// Call used to modify mesh. (legacy) + /// </summary> + /// <param name="mesh">Mesh.</param> + public virtual void ModifyMesh(Mesh mesh) + { + } + + /// <summary> + /// Call used to modify mesh. + /// </summary> + /// <param name="vh">VertexHelper.</param> + public virtual void ModifyMesh(VertexHelper vh) + { + ModifyMesh(vh, graphic); + } + + public virtual void ModifyMesh(VertexHelper vh, Graphic graphic) + { + } + + /// <summary> + /// Mark the vertices as dirty. + /// </summary> + protected virtual void SetVerticesDirty() + { + connector.SetVerticesDirty(graphic); + + foreach (var effect in syncEffects) + { + effect.SetVerticesDirty(); + } + +// #if TMP_PRESENT +// if (textMeshPro) +// { +// foreach (var info in textMeshPro.textInfo.meshInfo) +// { +// var mesh = info.mesh; +// if (mesh) +// { +// mesh.Clear(); +// mesh.vertices = info.vertices; +// mesh.uv = info.uvs0; +// mesh.uv2 = info.uvs2; +// mesh.colors32 = info.colors32; +// mesh.normals = info.normals; +// mesh.tangents = info.tangents; +// mesh.triangles = info.triangles; +// } +// } +// +// if (canvasRenderer) +// { +// canvasRenderer.SetMesh(textMeshPro.mesh); +// +// GetComponentsInChildren(false, s_SubMeshUIs); +// foreach (var sm in s_SubMeshUIs) +// { +// sm.canvasRenderer.SetMesh(sm.mesh); +// } +// +// s_SubMeshUIs.Clear(); +// } +// +// textMeshPro.havePropertiesChanged = true; +// } +// else +// #endif +// if (graphic) +// { +// graphic.SetVerticesDirty(); +// } + } + + + //################################ + // Protected Members. + //################################ + /// <summary> + /// Should the effect modify the mesh directly for TMPro? + /// </summary> + // protected virtual bool isLegacyMeshModifier + // { + // get { return false; } + // } +// protected virtual void Initialize() +// { +// if (_initialized) return; +// +// _initialized = true; +// _graphic = _graphic ? _graphic : GetComponent<Graphic>(); +// +// _connector = GraphicConnector.FindConnector(_graphic); +// +// // _canvasRenderer = _canvasRenderer ?? GetComponent<CanvasRenderer> (); +// _rectTransform = _rectTransform ? _rectTransform : GetComponent<RectTransform>(); +// // #if TMP_PRESENT +// // _textMeshPro = _textMeshPro ?? GetComponent<TMP_Text> (); +// // #endif +// } + + /// <summary> + /// This function is called when the object becomes enabled and active. + /// </summary> + protected override void OnEnable() + { + connector.OnEnable(graphic); + SetVerticesDirty(); + + // SetVerticesDirty(); +// #if TMP_PRESENT + // if (textMeshPro) + // { + // TMPro_EventManager.TEXT_CHANGED_EVENT.Add (OnTextChanged); + // } + // #endif + // + // #if UNITY_EDITOR && TMP_PRESENT + // if (graphic && textMeshPro) + // { + // GraphicRebuildTracker.TrackGraphic (graphic); + // } + // #endif + // + // #if UNITY_5_6_OR_NEWER + // if (graphic) + // { + // AdditionalCanvasShaderChannels channels = requiredChannels; + // var canvas = graphic.canvas; + // if (canvas && (canvas.additionalShaderChannels & channels) != channels) + // { + // Debug.LogWarningFormat (this, "Enable {1} of Canvas.additionalShaderChannels to use {0}.", GetType ().Name, channels); + // } + // } + // #endif + } + + /// <summary> + /// This function is called when the behaviour becomes disabled () or inactive. + /// </summary> + protected override void OnDisable() + { + connector.OnDisable(graphic); + SetVerticesDirty(); + } + + /// <summary> + /// Mark the effect parameters as dirty. + /// </summary> + protected virtual void SetEffectParamsDirty() + { + if (!isActiveAndEnabled) return; + SetVerticesDirty(); + } + + /// <summary> + /// Callback for when properties have been changed by animation. + /// </summary> + protected override void OnDidApplyAnimationProperties() + { + if (!isActiveAndEnabled) return; + SetEffectParamsDirty(); + } + +#if UNITY_EDITOR + protected override void Reset() + { + if (!isActiveAndEnabled) return; + SetVerticesDirty(); + } + + /// <summary> + /// This function is called when the script is loaded or a value is changed in the inspector (Called in the editor only). + /// </summary> + protected override void OnValidate() + { + if (!isActiveAndEnabled) return; + SetEffectParamsDirty(); + } +#endif + } +} diff --git a/Assets/Scripts/Common/BaseMeshEffect.cs.meta b/Assets/Scripts/Common/BaseMeshEffect.cs.meta new file mode 100644 index 0000000..1d3c8d1 --- /dev/null +++ b/Assets/Scripts/Common/BaseMeshEffect.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 229ee7044e2514b0e9bd9fd40a2baa3a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Common/EffectPlayer.cs b/Assets/Scripts/Common/EffectPlayer.cs new file mode 100644 index 0000000..f60165a --- /dev/null +++ b/Assets/Scripts/Common/EffectPlayer.cs @@ -0,0 +1,154 @@ +using UnityEngine; +using System; +using System.Collections.Generic; + +namespace Coffee.UIEffects +{ + /// <summary> + /// Effect player. + /// </summary> + [Serializable] + public class EffectPlayer + { + //################################ + // Public Members. + //################################ + /// <summary> + /// Gets or sets a value indicating whether is playing. + /// </summary> + [Header("Effect Player")] [Tooltip("Playing.")] + public bool play = false; + + /// <summary> + /// Gets or sets the delay before looping. + /// </summary> + [Tooltip("Initial play delay.")] [Range(0f, 10f)] + public float initialPlayDelay = 0; + + /// <summary> + /// Gets or sets the duration. + /// </summary> + [Tooltip("Duration.")] [Range(0.01f, 10f)] + public float duration = 1; + + /// <summary> + /// Gets or sets a value indicating whether can loop. + /// </summary> + [Tooltip("Loop.")] public bool loop = false; + + /// <summary> + /// Gets or sets the delay before looping. + /// </summary> + [Tooltip("Delay before looping.")] [Range(0f, 10f)] + public float loopDelay = 0; + + /// <summary> + /// Gets or sets the update mode. + /// </summary> + [Tooltip("Update mode")] public AnimatorUpdateMode updateMode = AnimatorUpdateMode.Normal; + + static List<Action> s_UpdateActions; + + /// <summary> + /// Register player. + /// </summary> + public void OnEnable(Action<float> callback = null) + { + if (s_UpdateActions == null) + { + s_UpdateActions = new List<Action>(); + Canvas.willRenderCanvases += () => + { + var count = s_UpdateActions.Count; + for (int i = 0; i < count; i++) + { + s_UpdateActions[i].Invoke(); + } + }; + } + + s_UpdateActions.Add(OnWillRenderCanvases); + + if (play) + { + _time = -initialPlayDelay; + } + else + { + _time = 0; + } + + _callback = callback; + } + + /// <summary> + /// Unregister player. + /// </summary> + public void OnDisable() + { + _callback = null; + s_UpdateActions.Remove(OnWillRenderCanvases); + } + + /// <summary> + /// Start playing. + /// </summary> + public void Play(bool reset, Action<float> callback = null) + { + if (reset) + { + _time = 0; + } + + play = true; + if (callback != null) + { + _callback = callback; + } + } + + /// <summary> + /// Stop playing. + /// </summary> + public void Stop(bool reset) + { + if (reset) + { + _time = 0; + if (_callback != null) + { + _callback(_time); + } + } + + play = false; + } + + //################################ + // Private Members. + //################################ + float _time = 0; + Action<float> _callback; + + void OnWillRenderCanvases() + { + if (!play || !Application.isPlaying || _callback == null) + { + return; + } + + _time += updateMode == AnimatorUpdateMode.UnscaledTime + ? Time.unscaledDeltaTime + : Time.deltaTime; + var current = _time / duration; + + if (duration <= _time) + { + play = loop; + _time = loop ? -loopDelay : 0; + } + + _callback(current); + } + } +} diff --git a/Assets/Scripts/Common/EffectPlayer.cs.meta b/Assets/Scripts/Common/EffectPlayer.cs.meta new file mode 100644 index 0000000..661e073 --- /dev/null +++ b/Assets/Scripts/Common/EffectPlayer.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 1656fb67110cd44298010d95c324e87a +timeCreated: 1528296875 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Common/GraphicConnector.cs b/Assets/Scripts/Common/GraphicConnector.cs new file mode 100644 index 0000000..3046297 --- /dev/null +++ b/Assets/Scripts/Common/GraphicConnector.cs @@ -0,0 +1,151 @@ +using UnityEngine; +using UnityEngine.UI; +using System; +using System.Collections.Generic; + +namespace Coffee.UIEffects +{ + public class GraphicConnector + { + private static readonly List<GraphicConnector> s_Connectors = new List<GraphicConnector>(); + + private static readonly Dictionary<Type, GraphicConnector> s_ConnectorMap = + new Dictionary<Type, GraphicConnector>(); + + private static readonly GraphicConnector s_EmptyConnector = new GraphicConnector(); + +#if UNITY_EDITOR + [UnityEditor.InitializeOnLoadMethod] +#endif + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] + private static void Init() + { + AddConnector(new GraphicConnector()); + } + + protected static void AddConnector(GraphicConnector connector) + { + s_Connectors.Add(connector); + s_Connectors.Sort((x, y) => y.priority - x.priority); + } + + public static GraphicConnector FindConnector(Graphic graphic) + { + if (!graphic) return s_EmptyConnector; + + var type = graphic.GetType(); + GraphicConnector connector = null; + if (s_ConnectorMap.TryGetValue(type, out connector)) return connector; + + foreach (var c in s_Connectors) + { + if (!c.IsValid(graphic)) continue; + + s_ConnectorMap.Add(type, c); + return c; + } + + return s_EmptyConnector; + } + + /// <summary> + /// Connector priority. + /// </summary> + protected virtual int priority + { + get { return -1; } + } + + /// <summary> + /// Extra channel. + /// </summary> + public virtual AdditionalCanvasShaderChannels extraChannel + { + get { return AdditionalCanvasShaderChannels.TexCoord1; } + } + + /// <summary> + /// The connector is valid for the component. + /// </summary> + protected virtual bool IsValid(Graphic graphic) + { + return true; + } + + /// <summary> + /// Find effect shader. + /// </summary> + public virtual Shader FindShader(string shaderName) + { + return Shader.Find("Hidden/" + shaderName); + } + + /// <summary> + /// This function is called when the object becomes enabled and active. + /// </summary> + public virtual void OnEnable(Graphic graphic) + { + } + + /// <summary> + /// This function is called when the behaviour becomes disabled () or inactive. + /// </summary> + public virtual void OnDisable(Graphic graphic) + { + } + + /// <summary> + /// Mark the vertices as dirty. + /// </summary> + public virtual void SetVerticesDirty(Graphic graphic) + { + if (graphic) + graphic.SetVerticesDirty(); + } + + /// <summary> + /// Mark the material as dirty. + /// </summary> + public virtual void SetMaterialDirty(Graphic graphic) + { + if (graphic) + graphic.SetMaterialDirty(); + } + + /// <summary> + /// Gets position factor for area. + /// </summary> + public virtual void GetPositionFactor(EffectArea area, int index, Rect rect, Vector2 position, out float x, out float y) + { + if (area == EffectArea.Fit) + { + x = Mathf.Clamp01((position.x - rect.xMin) / rect.width); + y = Mathf.Clamp01((position.y - rect.yMin) / rect.height); + } + else + { + x = Mathf.Clamp01(position.x / rect.width + 0.5f); + y = Mathf.Clamp01(position.y / rect.height + 0.5f); + } + } + + public virtual bool IsText(Graphic graphic) + { + return graphic && graphic is Text; + } + + public virtual void SetExtraChannel(ref UIVertex vertex, Vector2 value) + { + vertex.uv1 = value; + } + + /// <summary> + /// Normalize vertex position by local matrix. + /// </summary> + public virtual void GetNormalizedFactor(EffectArea area, int index, Matrix2x3 matrix, Vector2 position, + out Vector2 normalizedPos) + { + normalizedPos = matrix * position; + } + } +} diff --git a/Assets/Scripts/Common/GraphicConnector.cs.meta b/Assets/Scripts/Common/GraphicConnector.cs.meta new file mode 100644 index 0000000..5652017 --- /dev/null +++ b/Assets/Scripts/Common/GraphicConnector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 66636f82e05e6453781a33c8b7da8b93 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Common/MaterialCache.cs b/Assets/Scripts/Common/MaterialCache.cs new file mode 100644 index 0000000..8d8ed93 --- /dev/null +++ b/Assets/Scripts/Common/MaterialCache.cs @@ -0,0 +1,77 @@ +using System.Collections.Generic; +using System.Linq; +using System; +using UnityEngine; +using System.Text; +using UnityEngine.UI; + +namespace Coffee.UIEffects +{ + public class MaterialCache + { + static Dictionary<Hash128, MaterialEntry> materialMap = new Dictionary<Hash128, MaterialEntry>(); + + private class MaterialEntry + { + public Material material; + public int referenceCount; + + public void Release() + { + if (material) + { + UnityEngine.Object.DestroyImmediate(material, false); + } + + material = null; + } + } + +#if UNITY_EDITOR + [UnityEditor.InitializeOnLoadMethod] + private static void ClearCache() + { + foreach (var entry in materialMap.Values) + { + entry.Release(); + } + + materialMap.Clear(); + } +#endif + + public static Material Register(Material baseMaterial, Hash128 hash, + System.Action<Material, Graphic> onModifyMaterial, Graphic graphic) + { + if (!hash.isValid) return null; + + MaterialEntry entry; + if (!materialMap.TryGetValue(hash, out entry)) + { + entry = new MaterialEntry() + { + material = new Material(baseMaterial) + { + hideFlags = HideFlags.HideAndDontSave, + }, + }; + + onModifyMaterial(entry.material, graphic); + materialMap.Add(hash, entry); + } + + entry.referenceCount++; + return entry.material; + } + + public static void Unregister(Hash128 hash) + { + MaterialEntry entry; + if (!hash.isValid || !materialMap.TryGetValue(hash, out entry)) return; + if (--entry.referenceCount > 0) return; + + entry.Release(); + materialMap.Remove(hash); + } + } +} diff --git a/Assets/Scripts/Common/MaterialCache.cs.meta b/Assets/Scripts/Common/MaterialCache.cs.meta new file mode 100644 index 0000000..434e1ff --- /dev/null +++ b/Assets/Scripts/Common/MaterialCache.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 2160d2c55a6100642b6c7ba09df935da +timeCreated: 1528509206 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Common/Matrix2x3.cs b/Assets/Scripts/Common/Matrix2x3.cs new file mode 100644 index 0000000..ec2cb69 --- /dev/null +++ b/Assets/Scripts/Common/Matrix2x3.cs @@ -0,0 +1,33 @@ +using UnityEngine; + +namespace Coffee.UIEffects +{ + /// <summary> + /// Matrix2x3. + /// </summary> + public struct Matrix2x3 + { + public float m00, m01, m02, m10, m11, m12; + + public Matrix2x3(Rect rect, float cos, float sin) + { + const float center = 0.5f; + float dx = -rect.xMin / rect.width - center; + float dy = -rect.yMin / rect.height - center; + m00 = cos / rect.width; + m01 = -sin / rect.height; + m02 = dx * cos - dy * sin + center; + m10 = sin / rect.width; + m11 = cos / rect.height; + m12 = dx * sin + dy * cos + center; + } + + public static Vector2 operator *(Matrix2x3 m, Vector2 v) + { + return new Vector2( + (m.m00 * v.x) + (m.m01 * v.y) + m.m02, + (m.m10 * v.x) + (m.m11 * v.y) + m.m12 + ); + } + } +} diff --git a/Assets/Scripts/Common/Matrix2x3.cs.meta b/Assets/Scripts/Common/Matrix2x3.cs.meta new file mode 100644 index 0000000..70ee757 --- /dev/null +++ b/Assets/Scripts/Common/Matrix2x3.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 5a9b962044ca64867b713425f7e5daab +timeCreated: 1527590245 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Common/Packer.cs b/Assets/Scripts/Common/Packer.cs new file mode 100644 index 0000000..ffdb64f --- /dev/null +++ b/Assets/Scripts/Common/Packer.cs @@ -0,0 +1,61 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +public static class Packer +{ + /// <summary> + /// Pack 4 low-precision [0-1] floats values to a float. + /// Each value [0-1] has 64 steps(6 bits). + /// </summary> + public static float ToFloat(float x, float y, float z, float w) + { + x = x < 0 ? 0 : 1 < x ? 1 : x; + y = y < 0 ? 0 : 1 < y ? 1 : y; + z = z < 0 ? 0 : 1 < z ? 1 : z; + w = w < 0 ? 0 : 1 < w ? 1 : w; + const int PRECISION = (1 << 6) - 1; + return (Mathf.FloorToInt(w * PRECISION) << 18) + + (Mathf.FloorToInt(z * PRECISION) << 12) + + (Mathf.FloorToInt(y * PRECISION) << 6) + + Mathf.FloorToInt(x * PRECISION); + } + + /// <summary> + /// Pack 4 low-precision [0-1] floats values to a float. + /// Each value [0-1] has 64 steps(6 bits). + /// </summary> + public static float ToFloat(Vector4 factor) + { + return ToFloat(Mathf.Clamp01(factor.x), Mathf.Clamp01(factor.y), Mathf.Clamp01(factor.z), + Mathf.Clamp01(factor.w)); + } + + /// <summary> + /// Pack 1 middle-precision & 2 low-precision [0-1] floats values to a float. + /// z value [0-1] has 4096 steps(12 bits) and xy value [0-1] has 64 steps(6 bits). + /// </summary> + public static float ToFloat(float x, float y, float z) + { + x = x < 0 ? 0 : 1 < x ? 1 : x; + y = y < 0 ? 0 : 1 < y ? 1 : y; + z = z < 0 ? 0 : 1 < z ? 1 : z; + const int PRECISION = (1 << 8) - 1; + return (Mathf.FloorToInt(z * PRECISION) << 16) + + (Mathf.FloorToInt(y * PRECISION) << 8) + + Mathf.FloorToInt(x * PRECISION); + } + + /// <summary> + /// Pack 2 low-precision [0-1] floats values to a float. + /// Each value [0-1] has 4096 steps(12 bits). + /// </summary> + public static float ToFloat(float x, float y) + { + x = x < 0 ? 0 : 1 < x ? 1 : x; + y = y < 0 ? 0 : 1 < y ? 1 : y; + const int PRECISION = (1 << 12) - 1; + return (Mathf.FloorToInt(y * PRECISION) << 12) + + Mathf.FloorToInt(x * PRECISION); + } +} diff --git a/Assets/Scripts/Common/Packer.cs.meta b/Assets/Scripts/Common/Packer.cs.meta new file mode 100644 index 0000000..4105720 --- /dev/null +++ b/Assets/Scripts/Common/Packer.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: b4970b3a69d3b472b8d66c1d92ec7bad +timeCreated: 1527590285 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Common/ParameterTexture.cs b/Assets/Scripts/Common/ParameterTexture.cs new file mode 100644 index 0000000..3249828 --- /dev/null +++ b/Assets/Scripts/Common/ParameterTexture.cs @@ -0,0 +1,190 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Rendering; +using System; + +namespace Coffee.UIEffects +{ + public interface IParameterTexture + { + int parameterIndex { get; set; } + + ParameterTexture paramTex { get; } + } + + /// <summary> + /// Parameter texture. + /// </summary> + [System.Serializable] + public class ParameterTexture + { + //################################ + // Public Members. + //################################ + + /// <summary> + /// Initializes a new instance of the <see cref="Coffee.UIEffects.ParameterTexture"/> class. + /// </summary> + /// <param name="channels">Channels.</param> + /// <param name="instanceLimit">Instance limit.</param> + /// <param name="propertyName">Property name.</param> + public ParameterTexture(int channels, int instanceLimit, string propertyName) + { + _propertyName = propertyName; + _channels = ((channels - 1) / 4 + 1) * 4; + _instanceLimit = ((instanceLimit - 1) / 2 + 1) * 2; + _data = new byte[_channels * _instanceLimit]; + + _stack = new Stack<int>(_instanceLimit); + for (int i = 1; i < _instanceLimit + 1; i++) + { + _stack.Push(i); + } + } + + + /// <summary> + /// Register the specified target. + /// </summary> + /// <param name="target">Target.</param> + public void Register(IParameterTexture target) + { + Initialize(); + if (target.parameterIndex <= 0 && 0 < _stack.Count) + { + target.parameterIndex = _stack.Pop(); +// Debug.LogFormat("<color=green>@@@ Register {0} : {1}</color>", target, target.parameterIndex); + } + } + + /// <summary> + /// Unregister the specified target. + /// </summary> + /// <param name="target">Target.</param> + public void Unregister(IParameterTexture target) + { + if (0 < target.parameterIndex) + { +// Debug.LogFormat("<color=red>@@@ Unregister {0} : {1}</color>", target, target.parameterIndex); + _stack.Push(target.parameterIndex); + target.parameterIndex = 0; + } + } + + /// <summary> + /// Sets the data. + /// </summary> + /// <param name="target">Target.</param> + /// <param name="channelId">Channel identifier.</param> + /// <param name="value">Value.</param> + public void SetData(IParameterTexture target, int channelId, byte value) + { + int index = (target.parameterIndex - 1) * _channels + channelId; + if (0 < target.parameterIndex && _data[index] != value) + { + _data[index] = value; + _needUpload = true; + } + } + + /// <summary> + /// Sets the data. + /// </summary> + /// <param name="target">Target.</param> + /// <param name="channelId">Channel identifier.</param> + /// <param name="value">Value.</param> + public void SetData(IParameterTexture target, int channelId, float value) + { + SetData(target, channelId, (byte) (Mathf.Clamp01(value) * 255)); + } + + /// <summary> + /// Registers the material. + /// </summary> + /// <param name="mat">Mat.</param> + public void RegisterMaterial(Material mat) + { + if (_propertyId == 0) + { + _propertyId = Shader.PropertyToID(_propertyName); + } + + if (mat) + { + mat.SetTexture(_propertyId, _texture); + } + } + + /// <summary> + /// Gets the index of the normalized. + /// </summary> + /// <returns>The normalized index.</returns> + /// <param name="target">Target.</param> + public float GetNormalizedIndex(IParameterTexture target) + { + return ((float) target.parameterIndex - 0.5f) / _instanceLimit; + } + + + //################################ + // Private Members. + //################################ + + Texture2D _texture; + bool _needUpload; + int _propertyId; + readonly string _propertyName; + readonly int _channels; + readonly int _instanceLimit; + readonly byte[] _data; + readonly Stack<int> _stack; + static List<Action> updates; + + /// <summary> + /// Initialize this instance. + /// </summary> + void Initialize() + { +#if UNITY_EDITOR + if (!UnityEditor.EditorApplication.isPlaying && UnityEditor.EditorApplication.isPlayingOrWillChangePlaymode) + { + return; + } +#endif + if (updates == null) + { + updates = new List<Action>(); + Canvas.willRenderCanvases += () => + { + var count = updates.Count; + for (int i = 0; i < count; i++) + { + updates[i].Invoke(); + } + }; + } + + if (!_texture) + { + bool isLinear = QualitySettings.activeColorSpace == ColorSpace.Linear; + _texture = new Texture2D(_channels / 4, _instanceLimit, TextureFormat.RGBA32, false, isLinear); + _texture.filterMode = FilterMode.Point; + _texture.wrapMode = TextureWrapMode.Clamp; + + updates.Add(UpdateParameterTexture); + _needUpload = true; + } + } + + void UpdateParameterTexture() + { + if (_needUpload && _texture) + { + _needUpload = false; + _texture.LoadRawTextureData(_data); + _texture.Apply(false, false); + } + } + } +} diff --git a/Assets/Scripts/Common/ParameterTexture.cs.meta b/Assets/Scripts/Common/ParameterTexture.cs.meta new file mode 100644 index 0000000..8b718d0 --- /dev/null +++ b/Assets/Scripts/Common/ParameterTexture.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 65eafa89b3a3a494a99e185423ba6cad +timeCreated: 1533006319 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: |