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(object value) { return (T)ConvertTo(value, typeof(T)); } static readonly Dictionary>> s_Converters = new Dictionary>>(); static VFXConverter() { //Register conversion that you only want in the UI here RegisterCustomConverter(t => new Vector4(t.x, t.y, t.z)); RegisterCustomConverter(t => new Vector4(t.x, t.y, 0)); RegisterCustomConverter(t => new Vector3(t.x, t.y, 0)); RegisterCustomConverter(t => new Color(t.x, t.y, 0)); RegisterCustomConverter(t => new Color(t.x, t.y, t.z)); RegisterCustomConverter(t => new Color(t.x, t.y, t.z, t.w)); RegisterCustomConverter(MakeTransformFromMatrix4x4); RegisterCustomConverter(t => t.x); RegisterCustomConverter(t => t.x); RegisterCustomConverter(t => t.x); RegisterCustomConverter(t => new Vector2(t.r, t.g)); RegisterCustomConverter(t => new Vector3(t.r, t.g, t.b)); RegisterCustomConverter(t => t.a); RegisterCustomConverter(MakeOrientedBoxFromTransform); RegisterCustomConverter(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(System.Func func) { Dictionary> converters = null; if (!s_Converters.TryGetValue(typeof(TFrom), out converters)) { converters = new Dictionary>(); 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 GetConverter(Type fromType, Type toType) { if (typeof(UnityObject).IsAssignableFrom(fromType)) { if (toType.IsAssignableFrom(fromType)) return t => ConvertUnityObject(t, toType); else return null; } Dictionary> converters = null; if (!s_Converters.TryGetValue(fromType, out converters)) { converters = new Dictionary>(); s_Converters.Add(fromType, converters); } System.Func 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 => m.Name == "op_Implicit" && m.GetParameters()[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; } } }