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; } } /// /// Parameter texture. /// [Serializable] public class ParameterTexture { //################################ // Public Members. //################################ /// /// Initializes a new instance of the class. /// /// Channels. /// Instance limit. /// Property name. public ParameterTexture(int channels, int instanceLimit, string propertyName) { this._propertyName = propertyName; this._channels = ((channels - 1) / 4 + 1) * 4; this._instanceLimit = ((instanceLimit - 1) / 2 + 1) * 2; this._data = new byte[this._channels * this._instanceLimit]; this._stack = new Stack(this._instanceLimit); for (int i = 1; i < this._instanceLimit + 1; i++) { this._stack.Push(i); } } /// /// Register the specified target. /// /// Target. public void Register(IParameterTexture target) { Initialize(); if (target.parameterIndex <= 0 && 0 < this._stack.Count) { target.parameterIndex = this._stack.Pop(); // Debug.LogFormat("@@@ Register {0} : {1}", target, target.parameterIndex); } } /// /// Unregister the specified target. /// /// Target. public void Unregister(IParameterTexture target) { if (0 < target.parameterIndex) { // Debug.LogFormat("@@@ Unregister {0} : {1}", target, target.parameterIndex); this._stack.Push(target.parameterIndex); target.parameterIndex = 0; } } /// /// Sets the data. /// /// Target. /// Channel identifier. /// Value. public void SetData(IParameterTexture target, int channelId, byte value) { int index = (target.parameterIndex - 1) * this._channels + channelId; if (0 < target.parameterIndex && this._data[index] != value) { this._data[index] = value; this._needUpload = true; } } /// /// Sets the data. /// /// Target. /// Channel identifier. /// Value. public void SetData(IParameterTexture target, int channelId, float value) { SetData(target, channelId, (byte) (Mathf.Clamp01(value) * 255)); } /// /// Registers the material. /// /// Mat. public void RegisterMaterial(Material mat) { if (this._propertyId == 0) { this._propertyId = Shader.PropertyToID(this._propertyName); } if (mat) { mat.SetTexture(this._propertyId, this._texture); } } /// /// Gets the index of the normalized. /// /// The normalized index. /// Target. public float GetNormalizedIndex(IParameterTexture target) { return ((float) target.parameterIndex - 0.5f) / this._instanceLimit; } //################################ // Private Members. //################################ Texture2D _texture; bool _needUpload; int _propertyId; readonly string _propertyName; readonly int _channels; readonly int _instanceLimit; readonly byte[] _data; readonly Stack _stack; static List updates; /// /// Initialize this instance. /// void Initialize() { #if UNITY_EDITOR if (!UnityEditor.EditorApplication.isPlaying && UnityEditor.EditorApplication.isPlayingOrWillChangePlaymode) { return; } #endif if (updates == null) { updates = new List(); Canvas.willRenderCanvases += () => { var count = updates.Count; for (int i = 0; i < count; i++) { updates[i].Invoke(); } }; } if (!this._texture) { bool isLinear = QualitySettings.activeColorSpace == ColorSpace.Linear; this._texture = new Texture2D(this._channels / 4, this._instanceLimit, TextureFormat.RGBA32, false, isLinear); this._texture.filterMode = FilterMode.Point; this._texture.wrapMode = TextureWrapMode.Clamp; updates.Add(UpdateParameterTexture); this._needUpload = true; } } void UpdateParameterTexture() { if (this._needUpload && this._texture) { this._needUpload = false; this._texture.LoadRawTextureData(this._data); this._texture.Apply(false, false); } } } }