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; } } /// /// Parameter texture. /// [System.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) { _propertyName = propertyName; _channels = ((channels - 1) / 4 + 1) * 4; _instanceLimit = ((instanceLimit - 1) / 2 + 1) * 2; _data = new byte[_channels * _instanceLimit]; _stack = new Stack(_instanceLimit); for (int i = 1; i < _instanceLimit + 1; i++) { _stack.Push(i); } } /// /// Register the specified target. /// /// Target. public void Register(IParameterTexture target) { Initialize(); if (target.parameterIndex <= 0 && 0 < _stack.Count) { target.parameterIndex = _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); _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) * _channels + channelId; if (0 < target.parameterIndex && _data[index] != value) { _data[index] = value; _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 (_propertyId == 0) { _propertyId = Shader.PropertyToID(_propertyName); } if (mat) { mat.SetTexture(_propertyId, _texture); } } /// /// Gets the index of the normalized. /// /// The normalized index. /// Target. 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 _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 (!_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); } } } }