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.
 
 
 
 

240 lines
8.8 KiB

using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using Type = System.Type;
using Convert = System.Convert;
using System.Linq;
using UnityObject = UnityEngine.Object;
using UnityEditor.VFX.UI;
namespace UnityEditor.VFX
{
static class VFXConverter
{
public static T ConvertTo<T>(object value)
{
return (T)ConvertTo(value, typeof(T));
}
static readonly Dictionary<System.Type, Dictionary<System.Type, System.Func<object, object>>> s_Converters = new Dictionary<System.Type, Dictionary<System.Type, System.Func<object, object>>>();
static VFXConverter()
{
//Register conversion that you only want in the UI here
RegisterCustomConverter<Vector3, Vector4>(t => new Vector4(t.x, t.y, t.z));
RegisterCustomConverter<Vector2, Vector4>(t => new Vector4(t.x, t.y, 0));
RegisterCustomConverter<Vector2, Vector3>(t => new Vector3(t.x, t.y, 0));
RegisterCustomConverter<Vector2, Color>(t => new Color(t.x, t.y, 0));
RegisterCustomConverter<Vector3, Color>(t => new Color(t.x, t.y, t.z));
RegisterCustomConverter<Vector4, Color>(t => new Color(t.x, t.y, t.z, t.w));
RegisterCustomConverter<Matrix4x4, Transform>(MakeTransformFromMatrix4x4);
RegisterCustomConverter<Vector2, float>(t => t.x);
RegisterCustomConverter<Vector3, float>(t => t.x);
RegisterCustomConverter<Vector4, float>(t => t.x);
RegisterCustomConverter<Color, Vector2>(t => new Vector2(t.r, t.g));
RegisterCustomConverter<Color, Vector3>(t => new Vector3(t.r, t.g, t.b));
RegisterCustomConverter<Color, float>(t => t.a);
RegisterCustomConverter<Transform, OrientedBox>(MakeOrientedBoxFromTransform);
RegisterCustomConverter<Matrix4x4, OrientedBox>(t => MakeOrientedBoxFromTransform(MakeTransformFromMatrix4x4(t)));
}
static Transform MakeTransformFromMatrix4x4(Matrix4x4 mat)
{
var result = new Transform
{
position = mat.MultiplyPoint(Vector3.zero),
angles = mat.rotation.eulerAngles,
scale = mat.lossyScale
};
return result;
}
static OrientedBox MakeOrientedBoxFromTransform(Transform t)
{
var result = new OrientedBox
{
center = t.position,
angles = t.angles,
size = t.scale
};
return result;
}
static void RegisterCustomConverter<TFrom, TTo>(System.Func<TFrom, TTo> func)
{
Dictionary<System.Type, System.Func<object, object>> converters = null;
if (!s_Converters.TryGetValue(typeof(TFrom), out converters))
{
converters = new Dictionary<System.Type, System.Func<object, object>>();
s_Converters.Add(typeof(TFrom), converters);
}
converters.Add(typeof(TTo), t => func((TFrom)t));
}
static object ConvertUnityObject(object value, Type toType)
{
var castedValue = (UnityObject)value;
if (castedValue == null) // null object don't have necessarly the correct type
return null;
if (toType == typeof(GraphicsBuffer))
return null; //This reference isn't serializable
if (!toType.IsInstanceOfType(value))
{
Debug.LogErrorFormat("Cannot cast from {0} to {1}", value.GetType(), toType);
return null;
}
return value;
}
static object TryConvertPrimitiveType(object value, Type toType)
{
try
{
return Convert.ChangeType(value, toType);
}
catch (InvalidCastException)
{
}
catch (OverflowException)
{
}
return System.Activator.CreateInstance(toType);
}
static System.Func<object, object> GetConverter(Type fromType, Type toType)
{
if (typeof(UnityObject).IsAssignableFrom(fromType))
{
if (toType.IsAssignableFrom(fromType))
return t => ConvertUnityObject(t, toType);
else
return null;
}
Dictionary<System.Type, System.Func<object, object>> converters = null;
if (!s_Converters.TryGetValue(fromType, out converters))
{
converters = new Dictionary<System.Type, System.Func<object, object>>();
s_Converters.Add(fromType, converters);
}
System.Func<object, object> converter = null;
if (!converters.TryGetValue(toType, out converter))
{
if (fromType == toType || toType.IsAssignableFrom(fromType))
{
converter = t => t;
}
else if (toType.IsEnum && (fromType == typeof(uint) || fromType == typeof(int)))
{
if (fromType == typeof(uint))
converter = t => Enum.ToObject(toType, (uint)t);
else
converter = t => Enum.ToObject(toType, (int)t);
}
else if (fromType.IsEnum && (toType == typeof(uint) || toType == typeof(int)))
{
converter = t => Convert.ChangeType(t, toType);
}
else
{
var implicitMethod = fromType.GetMethods(System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public)
.FirstOrDefault(m => m.Name == "op_Implicit" && m.ReturnType == toType);
if (implicitMethod != null)
{
converter = t => implicitMethod.Invoke(null, new object[] { t });
}
else
{
implicitMethod = toType.GetMethods(System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public)
.FirstOrDefault(m => {
var parameters = m.GetParameters();
return m.Name == "op_Implicit" && parameters.Length > 0 && (parameters[0].ParameterType.GetElementType() ?? parameters[0].ParameterType) == fromType && m.ReturnType == toType;
});
if (implicitMethod != null)
{
converter = t => implicitMethod.Invoke(null, new object[] { t });
}
}
if (converter == null)
{
if (toType.IsPrimitive)
{
if (fromType.IsPrimitive)
converter = t => TryConvertPrimitiveType(t, toType);
else if (toType != typeof(float))
{
var floatConverter = GetConverter(fromType, typeof(float));
if (floatConverter != null)
{
converter = t => TryConvertPrimitiveType(floatConverter(t), toType);
}
}
}
}
}
converters.Add(toType, converter);
}
return converter;
}
public static object ConvertTo(object value, Type type)
{
if (value == null)
return null;
if (value is UnityObject obj && obj == null && obj.GetInstanceID() != 0)
return obj;
if (type == typeof(GraphicsBuffer))
return null;
var fromType = value.GetType();
var converter = GetConverter(fromType, type);
if (converter == null)
{
Debug.LogErrorFormat("Cannot cast from {0} to {1}", fromType, type);
return null;
}
return converter(value);
}
public static bool TryConvertTo(object value, Type type, out object result)
{
if (value == null)
{
result = null;
return true;
}
var fromType = value.GetType();
var converter = GetConverter(fromType, type);
if (converter == null)
{
result = null;
return false;
}
result = converter(value);
return true;
}
public static bool CanConvertTo(Type from, Type to)
{
return GetConverter(from, to) != null;
}
}
}