using System;
using System.Collections.Generic;
using UnityEngine;
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);
}
}
}
}