#if VFX_HAS_TIMELINE using System; using System.Collections.Generic; using UnityEngine; using UnityEngine.Playables; using UnityEngine.VFX.Utility; namespace UnityEngine.VFX { [Serializable] struct EventAttributes { [SerializeReference] public EventAttribute[] content; } [Serializable] abstract class EventAttribute { public ExposedProperty id; public abstract bool ApplyToVFX(VFXEventAttribute eventAttribute); } [Serializable] abstract class EventAttributeValue : EventAttribute { private readonly Func m_HasFunc; private readonly Action m_ApplyFunc; protected EventAttributeValue(Func hasFunc, Action applyFunc) { m_HasFunc = hasFunc; m_ApplyFunc = applyFunc; } public sealed override bool ApplyToVFX(VFXEventAttribute eventAttribute) { if (!m_HasFunc(eventAttribute, id)) return false; m_ApplyFunc(eventAttribute, id, value);; return true; } public T value; } [Serializable] class EventAttributeFloat : EventAttributeValue { public EventAttributeFloat() : base((e, id) => e.HasFloat(id), (e, id, value) => e.SetFloat(id, value)) { } } [Serializable] class EventAttributeVector2 : EventAttributeValue { public EventAttributeVector2() : base((e, id) => e.HasVector2(id), (e, id, value) => e.SetVector2(id, value)) { } } [Serializable] class EventAttributeVector3 : EventAttributeValue { public EventAttributeVector3() : base((e, id) => e.HasVector3(id), (e, id, value) => e.SetVector3(id, value)) { } } [Serializable] class EventAttributeColor : EventAttributeVector3 {} [Serializable] class EventAttributeVector4 : EventAttributeValue { public EventAttributeVector4() : base((e, id) => e.HasVector4(id), (e, id, value) => e.SetVector4(id, value)) { } } [Serializable] class EventAttributeInt : EventAttributeValue { public EventAttributeInt() : base((e, id) => e.HasInt(id), (e, id, value) => e.SetInt(id, value)) { } } [Serializable] class EventAttributeUInt : EventAttributeValue { public EventAttributeUInt() : base((e, id) => e.HasUint(id), (e, id, value) => e.SetUint(id, value)) { } } [Serializable] class EventAttributeBool : EventAttributeValue { public EventAttributeBool() : base((e, id) => e.HasBool(id), (e, id, value) => e.SetBool(id, value)) { } } static class VFXTimeSpaceHelper { public static IEnumerable GetEventNormalizedSpace(PlayableTimeSpace space, VisualEffectControlPlayableBehaviour source) { return GetEventNormalizedSpace(space, source.events, source.clipStart, source.clipEnd); } private static IEnumerable CollectClipEvents(VisualEffectControlClip source) { if (source.clipEvents != null) { foreach (var clip in source.clipEvents) { var eventEnter = (VisualEffectPlayableSerializedEvent)clip.enter; var eventExit = (VisualEffectPlayableSerializedEvent)clip.exit; eventEnter.editorColor = eventExit.editorColor = clip.editorColor; yield return eventEnter; yield return eventExit; } } } public static IEnumerable GetEventNormalizedSpace(PlayableTimeSpace space, VisualEffectControlClip source, bool clipEvents) { IEnumerable sourceEvents; if (clipEvents) sourceEvents = CollectClipEvents(source); else sourceEvents = source.singleEvents; return GetEventNormalizedSpace(space, sourceEvents, source.clipStart, source.clipEnd); } private static IEnumerable GetEventNormalizedSpace(PlayableTimeSpace space, IEnumerable events, double clipStart, double clipEnd) { foreach (var itEvent in events) { var copy = itEvent; copy.timeSpace = space; copy.time = GetTimeInSpace(itEvent.timeSpace, itEvent.time, space, clipStart, clipEnd); yield return copy; } } public static double GetTimeInSpace(PlayableTimeSpace srcSpace, double srcTime, PlayableTimeSpace dstSpace, double clipStart, double clipEnd) { if (srcSpace == dstSpace) return srcTime; if (dstSpace == PlayableTimeSpace.AfterClipStart) { switch (srcSpace) { case PlayableTimeSpace.BeforeClipEnd: return clipEnd - srcTime - clipStart; case PlayableTimeSpace.Percentage: return (clipEnd - clipStart) * (srcTime / 100.0); case PlayableTimeSpace.Absolute: return srcTime - clipStart; } } else if (dstSpace == PlayableTimeSpace.BeforeClipEnd) { switch (srcSpace) { case PlayableTimeSpace.AfterClipStart: return clipEnd - srcTime - clipStart; case PlayableTimeSpace.Percentage: return clipEnd - clipStart - (clipEnd - clipStart) * (srcTime / 100.0); case PlayableTimeSpace.Absolute: return clipEnd - srcTime; } } else if (dstSpace == PlayableTimeSpace.Percentage) { switch (srcSpace) { case PlayableTimeSpace.AfterClipStart: return 100.0 * (srcTime) / (clipEnd - clipStart); case PlayableTimeSpace.BeforeClipEnd: return 100.0 * (clipEnd - srcTime - clipStart) / (clipEnd - clipStart); case PlayableTimeSpace.Absolute: return 100.0 * (srcTime - clipStart) / (clipEnd - clipStart); } } else if (dstSpace == PlayableTimeSpace.Absolute) { switch (srcSpace) { case PlayableTimeSpace.AfterClipStart: return clipStart + srcTime; case PlayableTimeSpace.BeforeClipEnd: return clipEnd - srcTime; case PlayableTimeSpace.Percentage: return clipStart + (clipEnd - clipStart) * (srcTime / 100.0); } } //Other conversion throw new NotImplementedException(srcSpace + " to " + dstSpace); } } enum PlayableTimeSpace { AfterClipStart, BeforeClipEnd, Percentage, Absolute } [Serializable] struct VisualEffectPlayableSerializedEvent { public Color editorColor; public double time; public PlayableTimeSpace timeSpace; public ExposedProperty name; public EventAttributes eventAttributes; } [Serializable] struct VisualEffectPlayableSerializedEventNoColor { public double time; public PlayableTimeSpace timeSpace; public ExposedProperty name; public EventAttributes eventAttributes; public static implicit operator VisualEffectPlayableSerializedEvent(VisualEffectPlayableSerializedEventNoColor evt) { return new VisualEffectPlayableSerializedEvent() { time = evt.time, timeSpace = evt.timeSpace, name = evt.name, eventAttributes = evt.eventAttributes }; } } class VisualEffectControlPlayableBehaviour : PlayableBehaviour { public double clipStart { get; set; } public double clipEnd { get; set; } public bool scrubbing { get; set; } public bool reinitEnter { get; set; } public bool reinitExit { get; set; } public uint startSeed { get; set; } public VisualEffectPlayableSerializedEvent[] events { get; set; } public uint clipEventsCount { get; set; } public uint prewarmStepCount { get; set; } public float prewarmDeltaTime { get; set; } public ExposedProperty prewarmEvent { get; set; } } } #endif