using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Rendering; using System; namespace Coffee.UIExtensions { public interface IParameterTexture { int parameterIndex { get; set; } ParameterTexture ptex { get; } } /// <summary> /// Parameter texture. /// </summary> [System.Serializable] public class ParameterTexture { //################################ // Public Members. //################################ /// <summary> /// Initializes a new instance of the <see cref="Coffee.UIExtensions.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); } } } }