ParameterTexture.cs 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using UnityEngine.Rendering;
  5. using System;
  6. namespace Coffee.UIEffects
  7. {
  8. public interface IParameterTexture
  9. {
  10. int parameterIndex { get; set; }
  11. ParameterTexture paramTex { get; }
  12. }
  13. /// <summary>
  14. /// Parameter texture.
  15. /// </summary>
  16. [System.Serializable]
  17. public class ParameterTexture
  18. {
  19. //################################
  20. // Public Members.
  21. //################################
  22. /// <summary>
  23. /// Initializes a new instance of the <see cref="Coffee.UIEffects.ParameterTexture"/> class.
  24. /// </summary>
  25. /// <param name="channels">Channels.</param>
  26. /// <param name="instanceLimit">Instance limit.</param>
  27. /// <param name="propertyName">Property name.</param>
  28. public ParameterTexture(int channels, int instanceLimit, string propertyName)
  29. {
  30. _propertyName = propertyName;
  31. _channels = ((channels - 1) / 4 + 1) * 4;
  32. _instanceLimit = ((instanceLimit - 1) / 2 + 1) * 2;
  33. _data = new byte[_channels * _instanceLimit];
  34. _stack = new Stack<int>(_instanceLimit);
  35. for (int i = 1; i < _instanceLimit + 1; i++)
  36. {
  37. _stack.Push(i);
  38. }
  39. }
  40. /// <summary>
  41. /// Register the specified target.
  42. /// </summary>
  43. /// <param name="target">Target.</param>
  44. public void Register(IParameterTexture target)
  45. {
  46. Initialize();
  47. if (target.parameterIndex <= 0 && 0 < _stack.Count)
  48. {
  49. target.parameterIndex = _stack.Pop();
  50. // Debug.LogFormat("<color=green>@@@ Register {0} : {1}</color>", target, target.parameterIndex);
  51. }
  52. }
  53. /// <summary>
  54. /// Unregister the specified target.
  55. /// </summary>
  56. /// <param name="target">Target.</param>
  57. public void Unregister(IParameterTexture target)
  58. {
  59. if (0 < target.parameterIndex)
  60. {
  61. // Debug.LogFormat("<color=red>@@@ Unregister {0} : {1}</color>", target, target.parameterIndex);
  62. _stack.Push(target.parameterIndex);
  63. target.parameterIndex = 0;
  64. }
  65. }
  66. /// <summary>
  67. /// Sets the data.
  68. /// </summary>
  69. /// <param name="target">Target.</param>
  70. /// <param name="channelId">Channel identifier.</param>
  71. /// <param name="value">Value.</param>
  72. public void SetData(IParameterTexture target, int channelId, byte value)
  73. {
  74. int index = (target.parameterIndex - 1) * _channels + channelId;
  75. if (0 < target.parameterIndex && _data[index] != value)
  76. {
  77. _data[index] = value;
  78. _needUpload = true;
  79. }
  80. }
  81. /// <summary>
  82. /// Sets the data.
  83. /// </summary>
  84. /// <param name="target">Target.</param>
  85. /// <param name="channelId">Channel identifier.</param>
  86. /// <param name="value">Value.</param>
  87. public void SetData(IParameterTexture target, int channelId, float value)
  88. {
  89. SetData(target, channelId, (byte) (Mathf.Clamp01(value) * 255));
  90. }
  91. /// <summary>
  92. /// Registers the material.
  93. /// </summary>
  94. /// <param name="mat">Mat.</param>
  95. public void RegisterMaterial(Material mat)
  96. {
  97. if (_propertyId == 0)
  98. {
  99. _propertyId = Shader.PropertyToID(_propertyName);
  100. }
  101. if (mat)
  102. {
  103. mat.SetTexture(_propertyId, _texture);
  104. }
  105. }
  106. /// <summary>
  107. /// Gets the index of the normalized.
  108. /// </summary>
  109. /// <returns>The normalized index.</returns>
  110. /// <param name="target">Target.</param>
  111. public float GetNormalizedIndex(IParameterTexture target)
  112. {
  113. return ((float) target.parameterIndex - 0.5f) / _instanceLimit;
  114. }
  115. //################################
  116. // Private Members.
  117. //################################
  118. Texture2D _texture;
  119. bool _needUpload;
  120. int _propertyId;
  121. readonly string _propertyName;
  122. readonly int _channels;
  123. readonly int _instanceLimit;
  124. readonly byte[] _data;
  125. readonly Stack<int> _stack;
  126. static List<Action> updates;
  127. /// <summary>
  128. /// Initialize this instance.
  129. /// </summary>
  130. void Initialize()
  131. {
  132. #if UNITY_EDITOR
  133. if (!UnityEditor.EditorApplication.isPlaying && UnityEditor.EditorApplication.isPlayingOrWillChangePlaymode)
  134. {
  135. return;
  136. }
  137. #endif
  138. if (updates == null)
  139. {
  140. updates = new List<Action>();
  141. Canvas.willRenderCanvases += () =>
  142. {
  143. var count = updates.Count;
  144. for (int i = 0; i < count; i++)
  145. {
  146. updates[i].Invoke();
  147. }
  148. };
  149. }
  150. if (!_texture)
  151. {
  152. bool isLinear = QualitySettings.activeColorSpace == ColorSpace.Linear;
  153. _texture = new Texture2D(_channels / 4, _instanceLimit, TextureFormat.RGBA32, false, isLinear);
  154. _texture.filterMode = FilterMode.Point;
  155. _texture.wrapMode = TextureWrapMode.Clamp;
  156. updates.Add(UpdateParameterTexture);
  157. _needUpload = true;
  158. }
  159. }
  160. void UpdateParameterTexture()
  161. {
  162. if (_needUpload && _texture)
  163. {
  164. _needUpload = false;
  165. _texture.LoadRawTextureData(_data);
  166. _texture.Apply(false, false);
  167. }
  168. }
  169. }
  170. }