You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

647 lines
25 KiB

using System;
using System.Linq;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.VFX;
namespace UnityEditor.VFX
{
abstract class VFXOperatorDynamicOperand : VFXOperator
{
/* Global rules (these function are too general, should be a separated utility) */
//output depends on all input type applying float > uint > int > bool (http://c0x.coding-guidelines.com/6.3.1.8.html)
public static readonly Type[] kExpectedTypeOrdering = new[]
{
typeof(Vector4),
typeof(Position),
typeof(Vector),
typeof(DirectionType),
typeof(Vector3),
typeof(Vector2),
typeof(float),
typeof(uint),
typeof(int),
};
public static readonly Dictionary<Type, Type[]> kTypeAffinity = new Dictionary<Type, Type[]>
{
{ typeof(Matrix4x4), new Type[] {} },
{ typeof(Vector4), new[] {typeof(Color), typeof(Vector3), typeof(Position), typeof(DirectionType), typeof(Vector), typeof(Vector2), typeof(float), typeof(int), typeof(uint)} },
{ typeof(Color), new[] {typeof(Vector4), typeof(Vector3), typeof(Position), typeof(Vector), typeof(Vector2), typeof(float), typeof(int), typeof(uint)} },
{ typeof(Vector3), new[] {typeof(Position), typeof(DirectionType), typeof(Vector), typeof(Color), typeof(Vector2), typeof(float), typeof(int), typeof(uint)} },
{ typeof(Position), new[] {typeof(Vector3), typeof(Vector)} },
{ typeof(DirectionType), new[] {typeof(Vector3), typeof(Position), typeof(Vector)} },
{ typeof(Vector), new[] {typeof(Vector3), typeof(Position), typeof(DirectionType) } },
{ typeof(Vector2), new[] {typeof(float), typeof(int), typeof(uint)} },
{ typeof(float), new[] {typeof(int), typeof(uint), typeof(Vector2), typeof(Vector3), typeof(Position), typeof(Vector), typeof(Vector4), typeof(Color)} },
{ typeof(int), new[] {typeof(uint), typeof(float), typeof(Vector2), typeof(Vector3), typeof(Position), typeof(Vector), typeof(Vector4), typeof(Color)} },
{ typeof(uint), new[] {typeof(int), typeof(float), typeof(Vector2), typeof(Vector3), typeof(Position), typeof(Vector), typeof(Vector4), typeof(Color)} },
};
static public IEnumerable<Type> GetTypeAffinityList(Type type)
{
Type[] affinity = null;
if (!kTypeAffinity.TryGetValue(type, out affinity))
{
return Enumerable.Empty<Type>();
}
return affinity;
}
public Type GetBestAffinityType(Type type)
{
if (validTypes.Contains(type))
{
return type;
}
Type[] affinity = null;
if (!kTypeAffinity.TryGetValue(type, out affinity))
{
return null;
}
var bestAffinity = affinity.Where(o => validTypes.Contains(o)).FirstOrDefault();
return bestAffinity; //Can be null
}
public abstract IEnumerable<Type> validTypes { get; }
protected abstract Type defaultValueType { get; }
protected virtual object GetDefaultValueForType(Type type)
{
return VFXTypeExtension.GetDefaultField(type);
}
protected virtual object GetIdentityValueForType(Type type)
{
return GetDefaultValueForType(type);
}
}
abstract class VFXOperatorDynamicType : VFXOperatorDynamicOperand, IVFXOperatorUniform
{
[VFXSetting(VFXSettingAttribute.VisibleFlags.None), SerializeField]
protected SerializableType m_Type;
public override void OnEnable()
{
if (m_Type == null) // Lazy init at this stage is suitable because inputProperties access is done with SyncSlot
{
m_Type = defaultValueType;
}
base.OnEnable();
}
public Type GetOperandType()
{
return m_Type;
}
public void SetOperandType(Type type)
{
if (!validTypes.Contains(type))
throw new InvalidOperationException();
m_Type = type;
Invalidate(InvalidationCause.kSettingChanged);
}
abstract public IEnumerable<int> staticSlotIndex { get; }
}
abstract class VFXOperatorNumeric : VFXOperatorDynamicOperand
{
protected sealed override Type defaultValueType
{
get
{
return typeof(float);
}
}
[Flags]
protected enum ValidTypeRule
{
allowVector4Type = 1 << 1,
allowVector3Type = 1 << 2,
allowVector2Type = 1 << 3,
allowOneDimensionType = 1 << 4,
allowSignedInteger = 1 << 5,
allowUnsignedInteger = 1 << 6,
allowSpaceableNotNormalized = 1 << 7,
allowSpaceableNormalized = 1 << 8,
allowSpaceable = allowSpaceableNotNormalized | allowSpaceableNormalized,
allowInteger = allowSignedInteger | allowUnsignedInteger,
allowVectorType = allowSpaceable | allowVector4Type | allowVector3Type | allowVector2Type,
allowEverything = allowVectorType | allowOneDimensionType | allowInteger,
allowEverythingExceptInteger = allowEverything & ~allowInteger,
allowEverythingExceptIntegerAndDirection = allowEverything & ~(allowInteger | allowSpaceableNormalized),
allowEverythingExceptUnsignedInteger = allowEverything & ~allowUnsignedInteger,
allowEverythingExceptIntegerAndVector4 = allowEverything & ~(allowInteger | allowVector4Type),
allowEverythingExceptOneDimension = allowEverything & ~allowOneDimensionType
};
private static readonly Type[] kSpaceableNormalizedType = new Type[] { typeof(DirectionType) };
private static readonly Type[] kSpaceableNotNormalizedType = new Type[] { typeof(Position), typeof(Vector) };
private static readonly Type[] kVector4Type = new Type[] { typeof(Vector4) };
private static readonly Type[] kVector3Type = new Type[] { typeof(Vector3) };
private static readonly Type[] kVector2Type = new Type[] { typeof(Vector2) };
private static readonly Type[] kOneDimensionType = new Type[] { typeof(float), typeof(uint), typeof(int) };
private static readonly Type[] kSIntegerType = new Type[] { typeof(int) };
private static readonly Type[] kUIntegerType = new Type[] { typeof(uint) };
protected virtual ValidTypeRule typeFilter { get { return ValidTypeRule.allowEverything; } }
public sealed override IEnumerable<Type> validTypes
{
get
{
IEnumerable<Type> types = kExpectedTypeOrdering;
if ((typeFilter & ValidTypeRule.allowSpaceableNormalized) != ValidTypeRule.allowSpaceableNormalized)
types = types.Except(kSpaceableNormalizedType);
if ((typeFilter & ValidTypeRule.allowSpaceableNotNormalized) != ValidTypeRule.allowSpaceableNotNormalized)
types = types.Except(kSpaceableNotNormalizedType);
if ((typeFilter & ValidTypeRule.allowVectorType) != ValidTypeRule.allowVectorType)
types = types.Except(kVector4Type);
if ((typeFilter & ValidTypeRule.allowVector3Type) != ValidTypeRule.allowVector3Type)
types = types.Except(kVector3Type);
if ((typeFilter & ValidTypeRule.allowVector2Type) != ValidTypeRule.allowVector2Type)
types = types.Except(kVector2Type);
if ((typeFilter & ValidTypeRule.allowOneDimensionType) != ValidTypeRule.allowOneDimensionType)
types = types.Except(kOneDimensionType);
if ((typeFilter & ValidTypeRule.allowSignedInteger) != ValidTypeRule.allowSignedInteger)
types = types.Except(kSIntegerType);
if ((typeFilter & ValidTypeRule.allowUnsignedInteger) != ValidTypeRule.allowUnsignedInteger)
types = types.Except(kUIntegerType);
return types;
}
}
protected virtual Type GetExpectedOutputTypeOfOperation(IEnumerable<Type> inputTypes)
{
if (!inputTypes.Any())
return defaultValueType;
var minIndex = inputTypes.Select(o => Array.IndexOf(kExpectedTypeOrdering, o)).Min();
if (minIndex == -1)
throw new IndexOutOfRangeException("Unexpected type");
return kExpectedTypeOrdering[minIndex];
}
protected virtual string operatorName => string.Empty;
public override /*sealed*/ string name
{
get
{
var r = operatorName;
if (outputSlots.Any())
{
var refSlot = outputSlots[0];
if (refSlot.spaceable)
{
r += string.Format(" ({0} - {1})", refSlot.property.type.UserFriendlyName(), refSlot.space);
}
else
{
r += string.Format(" ({0})", refSlot.property.type.UserFriendlyName());
}
}
return r;
}
}
protected virtual string expectedOutputName { get { return string.Empty; } }
protected virtual VFXPropertyAttributes expectedOutputAttributes { get { return new VFXPropertyAttributes(); } }
protected override sealed IEnumerable<VFXPropertyWithValue> outputProperties
{
get
{
if (base.outputProperties.Any())
{
//Behavior when "OutputProperties" as been declared (length, dot, square length...)
foreach (var outputProperty in base.outputProperties)
yield return outputProperty;
}
else
{
//Most common behavior : output of an operation depend of input type
var slotType = GetExpectedOutputTypeOfOperation(inputSlots.Select(o => o.property.type));
if (slotType != null)
yield return new VFXPropertyWithValue(new VFXProperty(slotType, expectedOutputName, expectedOutputAttributes));
}
}
}
protected override sealed object GetDefaultValueForType(Type vtype)
{
var type = VFXExpression.GetVFXValueTypeFromType(vtype);
switch (type)
{
case VFXValueType.Float:
return defaultValueFloat;
case VFXValueType.Float2:
return Vector2.one * defaultValueFloat;
case VFXValueType.Float3:
return Vector3.one * defaultValueFloat;
case VFXValueType.Float4:
return Vector4.one * defaultValueFloat;
case VFXValueType.Int32:
return defaultValueInt;
case VFXValueType.Uint32:
return defaultValueUint;
}
return null;
}
protected override IEnumerable<VFXExpression> ApplyPatchInputExpression(IEnumerable<VFXExpression> inputExpression)
{
var minIndex = inputExpression.Select(o => Array.IndexOf(kExpectedTypeOrdering, VFXExpression.TypeToType(o.valueType))).Min();
var unifiedType = VFXExpression.GetVFXValueTypeFromType(kExpectedTypeOrdering[minIndex]);
foreach (var expression in inputExpression)
{
if (expression.valueType == unifiedType)
{
yield return expression;
continue;
}
var currentExpression = expression;
if (VFXExpression.IsFloatValueType(unifiedType))
{
if (VFXExpression.IsUIntValueType(expression.valueType))
{
currentExpression = new VFXExpressionCastUintToFloat(currentExpression);
}
else if (VFXExpression.IsIntValueType(expression.valueType))
{
currentExpression = new VFXExpressionCastIntToFloat(currentExpression);
}
currentExpression = VFXOperatorUtility.CastFloat(currentExpression, unifiedType, identityValueFloat);
}
else if (VFXExpression.IsIntValueType(unifiedType))
{
if (VFXExpression.IsUIntValueType(currentExpression.valueType))
{
currentExpression = new VFXExpressionCastUintToInt(currentExpression);
}
else if (VFXExpression.IsFloatValueType(currentExpression.valueType))
{
currentExpression = new VFXExpressionCastFloatToInt(VFXOperatorUtility.ExtractComponents(currentExpression).First());
}
}
else if (VFXExpression.IsUIntValueType(unifiedType))
{
if (VFXExpression.IsIntValueType(currentExpression.valueType))
{
currentExpression = new VFXExpressionCastIntToUint(currentExpression);
}
else if (VFXExpression.IsFloatValueType(expression.valueType))
{
currentExpression = new VFXExpressionCastFloatToUint(VFXOperatorUtility.ExtractComponents(expression).First());
}
}
yield return currentExpression;
}
}
protected abstract double defaultValueDouble { get; }
protected virtual float defaultValueFloat { get { return (float)defaultValueDouble; } }
protected virtual int defaultValueInt { get { return (int)defaultValueDouble; } }
protected virtual uint defaultValueUint { get { return (uint)defaultValueDouble; } }
protected virtual double identityValueDouble { get { return defaultValueDouble; } }
protected virtual float identityValueFloat { get { return defaultValueFloat; } }
protected virtual int identityValueInt { get { return defaultValueInt; } }
protected virtual uint identityValueUint { get { return defaultValueUint; } }
}
interface IVFXOperatorUniform
{
Type GetOperandType();
void SetOperandType(Type type);
IEnumerable<int> staticSlotIndex { get; }
}
abstract class VFXOperatorNumericUniform : VFXOperatorNumeric, IVFXOperatorUniform
{
[VFXSetting(VFXSettingAttribute.VisibleFlags.None), SerializeField]
SerializableType m_Type;
protected override double defaultValueDouble //Most common case for this kind of operator (still overridable)
{
get
{
return 0.0;
}
}
public Type GetOperandType()
{
return m_Type;
}
public void SetOperandType(Type type)
{
if (!validTypes.Contains(type))
throw new InvalidOperationException();
m_Type = type;
Invalidate(InvalidationCause.kSettingChanged);
}
public IEnumerable<int> staticSlotIndex
{
get
{
return Enumerable.Empty<int>();
}
}
protected sealed override IEnumerable<VFXPropertyWithValue> inputProperties
{
get
{
var baseInputProperties = base.inputProperties;
if (m_Type == null) // Lazy init at this stage is suitable because inputProperties access is done with SyncSlot
{
var typeEnumeration = baseInputProperties.Select(o => o.property.type);
if (typeEnumeration.Any(o => !validTypes.Contains(o)))
throw new InvalidOperationException("Forbidden type");
if (typeEnumeration.Distinct().Count() != 1)
throw new InvalidOperationException("Uniform type expected");
m_Type = typeEnumeration.First();
}
foreach (var property in baseInputProperties)
{
if (property.property.type == (Type)m_Type)
yield return property;
else
yield return new VFXPropertyWithValue(new VFXProperty((Type)m_Type, property.property.name, property.property.attributes), GetDefaultValueForType(m_Type));
}
}
}
}
interface IVFXOperatorNumericUnified
{
int operandCount { get; }
Type GetOperandType(int index);
void SetOperandType(int index, Type type);
}
interface IVFXOperatorNumericUnifiedConstrained
{
IEnumerable<int> slotIndicesThatMustHaveSameType { get; }
IEnumerable<int> slotIndicesThatCanBeScalar { get; }
}
abstract class VFXOperatorNumericUnified : VFXOperatorNumeric, IVFXOperatorNumericUnified
{
[VFXSetting(VFXSettingAttribute.VisibleFlags.None), SerializeField]
SerializableType[] m_Type;
protected override double defaultValueDouble //Most common case for this kind of operator (still overridable)
{
get
{
return 0.0;
}
}
public int operandCount
{
get { return m_Type.Length; }
}
public Type GetOperandType(int index)
{
return m_Type[index];
}
public void SetOperandType(int index, Type type)
{
if (!validTypes.Contains(type))
throw new InvalidOperationException();
m_Type[index] = type;
Invalidate(InvalidationCause.kSettingChanged);
}
protected sealed override IEnumerable<VFXPropertyWithValue> inputProperties
{
get
{
var baseType = base.inputProperties;
if (m_Type == null) // Lazy init at this stage is suitable because inputProperties access is done with SyncSlot
{
var typeArray = baseType.Select(o => o.property.type).ToArray();
if (typeArray.Any(o => !validTypes.Contains(o)))
throw new InvalidOperationException("Forbidden type");
m_Type = typeArray.Select(o => new SerializableType(o)).ToArray();
}
if (baseType.Count() != m_Type.Length)
throw new InvalidOperationException();
var itSlot = baseType.GetEnumerator();
var itType = m_Type.Cast<SerializableType>().GetEnumerator();
while (itSlot.MoveNext() && itType.MoveNext())
{
if (itSlot.Current.property.type == (Type)itType.Current)
yield return itSlot.Current;
else
yield return new VFXPropertyWithValue(new VFXProperty((Type)itType.Current, itSlot.Current.property.name, itSlot.Current.property.attributes), GetDefaultValueForType(itType.Current));
}
}
}
}
abstract class VFXOperatorNumericCascadedUnified : VFXOperatorNumeric, IVFXOperatorNumericUnified
{
[Serializable]
public struct Operand
{
public string name;
public SerializableType type;
}
[VFXSetting(VFXSettingAttribute.VisibleFlags.None), SerializeField]
Operand[] m_Operands;
protected string GetDefaultName(int index)
{
return VFXCodeGeneratorHelper.GeneratePrefix((uint)index);
}
protected Operand GetDefaultOperand(int index, Type type = null)
{
return new Operand() { name = GetDefaultName(index), type = type != null ? type : defaultValueType };
}
protected sealed override IEnumerable<VFXPropertyWithValue> inputProperties
{
get
{
if (m_Operands == null) //Lazy init at this stage is suitable because inputProperties access is done with SyncSlot
{
m_Operands = Enumerable.Range(0, MinimalOperandCount).Select(i => GetDefaultOperand(i)).ToArray();
}
foreach (var operand in m_Operands)
yield return new VFXPropertyWithValue(new VFXProperty(operand.type, operand.name), GetDefaultValueForType(operand.type));
}
}
public virtual int MinimalOperandCount
{
get
{
return 2;
}
}
public void AddOperand(Type type = null)
{
if (type != null && !validTypes.Contains(type))
throw new InvalidOperationException("Unexpected type : " + type);
int oldCount = m_Operands.Length;
var infos = new Operand[oldCount + 1];
Array.Copy(m_Operands, infos, oldCount);
infos[oldCount] = GetDefaultOperand(oldCount, type);
m_Operands = infos;
Invalidate(InvalidationCause.kSettingChanged);
}
public void RemoveOperand(int index)
{
OperandMoved(index, operandCount - 1);
RemoveOperand();
}
public void RemoveOperand()
{
if (m_Operands.Length == 0)
return;
int oldCount = m_Operands.Length;
var infos = new Operand[oldCount - 1];
Array.Copy(m_Operands, infos, oldCount - 1);
m_Operands = infos;
inputSlots.Last().UnlinkAll(true);
Invalidate(InvalidationCause.kSettingChanged);
}
public int operandCount
{
get { return m_Operands != null ? m_Operands.Length : 0; }
}
public string GetOperandName(int index)
{
return m_Operands[index].name;
}
public void SetOperandName(int index, string name)
{
m_Operands[index].name = name;
Invalidate(InvalidationCause.kSettingChanged);
}
public Type GetOperandType(int index)
{
return m_Operands[index].type;
}
public void SetOperandType(int index, Type type)
{
if (!validTypes.Contains(type))
{
Debug.LogError("Invalid type : " + type);
return;
}
if (!m_Operands[index].type.Equals(type))
{
m_Operands[index].type = type;
Invalidate(InvalidationCause.kSettingChanged);
}
}
public void OperandMoved(int movedIndex, int targetIndex)
{
if (movedIndex == targetIndex) return;
var newOperands = new Operand[m_Operands.Length];
if (movedIndex < targetIndex)
{
Array.Copy(m_Operands, newOperands, movedIndex);
Array.Copy(m_Operands, movedIndex + 1, newOperands, movedIndex, targetIndex - movedIndex);
newOperands[targetIndex] = m_Operands[movedIndex];
Array.Copy(m_Operands, targetIndex + 1, newOperands, targetIndex + 1, m_Operands.Length - targetIndex - 1);
}
else
{
Array.Copy(m_Operands, newOperands, targetIndex);
newOperands[targetIndex] = m_Operands[movedIndex];
Array.Copy(m_Operands, targetIndex, newOperands, targetIndex + 1, movedIndex - targetIndex);
Array.Copy(m_Operands, movedIndex + 1, newOperands, movedIndex + 1, m_Operands.Length - movedIndex - 1);
}
m_Operands = newOperands;
//Move the slots ahead of time sot that the SyncSlot does not result in links lost.
MoveSlots(VFXSlot.Direction.kInput, movedIndex, targetIndex);
Invalidate(InvalidationCause.kSettingChanged);
}
protected override VFXExpression[] BuildExpression(VFXExpression[] inputExpression)
{
if (inputExpression.Length == 0)
{
return new[] { VFXValue.Constant(defaultValueFloat) };
}
//Process aggregate two by two element until result
var outputExpression = new Stack<VFXExpression>(inputExpression.Reverse());
while (outputExpression.Count > 1)
{
var a = outputExpression.Pop();
var b = outputExpression.Pop();
var compose = ComposeExpression(a, b);
outputExpression.Push(compose);
}
return outputExpression.ToArray();
}
protected abstract VFXExpression ComposeExpression(VFXExpression a, VFXExpression b);
}
}