Exemplo n.º 1
0
        //============================================================================================
        /**
        *  @brief 
        *         
        *********************************************************************************************/
        public void CopyPreProcessData(MxMPreProcessData a_preProcessData)
        {
            m_overrideTagModule = a_preProcessData.OverrideTagModule;
            m_overrideEventModule = a_preProcessData.OverrideEventModule;
            m_overrideConfigModule = a_preProcessData.OverrideConfigModule;

            List<CompositeCategory> sourceCategories = a_preProcessData.CompositeCategories;
            m_compositeCategories = new List<CompositeCategory>(sourceCategories.Count + 1);

            foreach (CompositeCategory sourceCategory in sourceCategories)
            {
                CompositeCategory newCategory = new CompositeCategory(sourceCategory, this);
                m_compositeCategories.Add(newCategory);
            }

            List<MxMAnimationIdleSet> sourceIdleSets = a_preProcessData.AnimationIdleSets;
            m_animIdleSets = new List<MxMAnimationIdleSet>(sourceIdleSets.Count + 1);

            foreach(MxMAnimationIdleSet sourceIdleSet in sourceIdleSets)
            {
                MxMAnimationIdleSet newIdleSet = ScriptableObject.CreateInstance<MxMAnimationIdleSet>();
                newIdleSet.CopyData(sourceIdleSet);
                newIdleSet.name = sourceIdleSet.name;
                newIdleSet.hideFlags = HideFlags.HideInHierarchy;
                newIdleSet.TargetAnimModule = this;
                newIdleSet.TargetPreProcess = null;

                EditorUtility.SetDirty(newIdleSet);

                AssetDatabase.AddObjectToAsset(newIdleSet, this);

                m_animIdleSets.Add(newIdleSet);
            }

            List<MxMBlendSpace> sourceBlendSpaces = a_preProcessData.BlendSpaces;
            m_blendSpaces = new List<MxMBlendSpace>(sourceBlendSpaces.Count + 1);

            foreach(MxMBlendSpace sourceBlendSpace in sourceBlendSpaces)
            {
                MxMBlendSpace newBlendSpace = ScriptableObject.CreateInstance<MxMBlendSpace>();
                newBlendSpace.CopyData(sourceBlendSpace);
                newBlendSpace.name = sourceBlendSpace.name;
                newBlendSpace.hideFlags = HideFlags.HideInHierarchy;
                newBlendSpace.TargetAnimModule = this;
                newBlendSpace.TargetPreProcess = null;

                EditorUtility.SetDirty(newBlendSpace);

                AssetDatabase.AddObjectToAsset(newBlendSpace, this);

                m_blendSpaces.Add(newBlendSpace);
            }

            EditorUtility.SetDirty(this);
        }
Exemplo n.º 2
0
        //============================================================================================

        /**
         *  @brief
         *
         *********************************************************************************************/
        public static void SetData(SerializedObject a_soAnimationModule, AnimationModule a_animModule, int a_categoryId)
        {
            if (a_soAnimationModule == null || a_animModule == null)
            {
                return;
            }

            m_data             = null;
            m_moduleData       = a_animModule;
            m_soPreProcessData = a_soAnimationModule;
            m_categoryId       = a_categoryId;
        }
Exemplo n.º 3
0
        //============================================================================================

        /**
         *  @brief
         *
         *********************************************************************************************/

        public static void SetData(SerializedObject a_soPreProcessData, MxMPreProcessData a_preProcessData, int a_categoryId)
        {
            if (a_soPreProcessData == null || a_preProcessData == null)
            {
                return;
            }

            m_data             = a_preProcessData;
            m_moduleData       = null;
            m_soPreProcessData = a_soPreProcessData;
            m_categoryId       = a_categoryId;
        }
        private void DrawSettings(Rect a_rect)
        {
            GUILayout.BeginArea(a_rect);

            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("Require", GUILayout.Width(50f));

            MxMPreProcessData preProcessData = m_spTargetPreProcessData.objectReferenceValue as MxMPreProcessData;
            AnimationModule   animModule     = m_spTargetAnimationModule.objectReferenceValue as AnimationModule;

            if (preProcessData != null)
            {
                EditorFunctions.DrawTagFlagFieldWithCustomNames(preProcessData.TagNames.ToArray(), m_spTags, 75f);
            }
            else if (animModule != null && animModule.TagNames != null)
            {
                EditorFunctions.DrawTagFlagFieldWithCustomNames(animModule.TagNames.ToArray(), m_spTags, 75f);
            }
            else
            {
                m_spTags.intValue = (int)(ETags)EditorGUILayout.EnumFlagsField((ETags)m_spTags.intValue);
            }


            EditorGUILayout.EndHorizontal();

            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("Favour", GUILayout.Width(50f));

            if (preProcessData != null)
            {
                EditorFunctions.DrawTagFlagFieldWithCustomNames(preProcessData.FavourTagNames.ToArray(), m_spFavourTags, 75f);
            }
            else if (animModule != null && animModule.FavourTagNames != null)
            {
                EditorFunctions.DrawTagFlagFieldWithCustomNames(animModule.FavourTagNames.ToArray(), m_spFavourTags, 75f);
            }
            else
            {
                m_spFavourTags.intValue = (int)(ETags)EditorGUILayout.EnumFlagsField((ETags)m_spFavourTags.intValue);
            }

            EditorGUILayout.EndHorizontal();

            EditorGUILayout.PrefixLabel("Min Loops:");
            m_spMinLoops.intValue = EditorGUILayout.IntField(m_spMinLoops.intValue);
            EditorGUILayout.PrefixLabel("Max Loops:");
            m_spMaxLoops.intValue = EditorGUILayout.IntField(m_spMaxLoops.intValue);

            GUILayout.EndArea();
        }
Exemplo n.º 5
0
        public void SetTargetPreProcessor(MxMPreProcessData a_preProcessor)
        {
            if (a_preProcessor != null)
            {
                m_targetPreProcessData = a_preProcessor;

                if (a_preProcessor.Prefab != null)
                {
                    m_targetPrefab = a_preProcessor.Prefab;
                }

                m_targetAnimModule = null;
            }
        }
Exemplo n.º 6
0
        public void SetTargetAnimModule(AnimationModule a_animModule)
        {
            if(a_animModule != null)
            {
                m_targetAnimModule = a_animModule;

                if(a_animModule.Prefab != null)
                {
                    m_targetPrefab = a_animModule.Prefab;
                }

                m_targetPreProcessData = null;
            }
        }
        public void CopyData(MxMAnimationIdleSet a_copy)
        {
            PrimaryClip = a_copy.PrimaryClip;
            SecondaryClips = new List<AnimationClip>(a_copy.SecondaryClips);
            TransitionClips = new List<AnimationClip>(a_copy.TransitionClips);
            Tags = a_copy.Tags;
            FavourTags = a_copy.FavourTags;
            MinLoops = a_copy.MinLoops;
            MaxLoops = a_copy.MaxLoops;

            m_targetPreProcessData = a_copy.m_targetPreProcessData;
            m_targetAnimModule = a_copy.m_targetAnimModule;

            PoseList = null;
        }
        private void NextComposite()
        {
            MxMPreProcessData preProcessData = m_spTargetPreProcessData.objectReferenceValue as MxMPreProcessData;
            AnimationModule   animModule     = m_spTargetAnimModule.objectReferenceValue as AnimationModule;

            List <MxMAnimationClipComposite> compList = null;

            if (preProcessData != null)
            {
                compList = preProcessData.GetCompositeCategoryList(m_data.CategoryId);
            }
            else if (animModule != null)
            {
                compList = animModule.GetCompositeCategoryList(m_data.CategoryId);
            }

            if (compList != null)
            {
                for (int i = 0; i < compList.Count; ++i)
                {
                    if (compList[i] == m_data)
                    {
                        if (i < compList.Count - 1)
                        {
                            compList[i + 1].ValidateBaseData();
                            SetData(compList[i + 1]);
                        }
                        else
                        {
                            compList[0].ValidateBaseData();
                            SetData(compList[0]);
                        }

                        if (MxMTaggingWindow.Exists())
                        {
                            MxMTaggingWindow.Inst().ClipChanged();
                        }

                        break;
                    }
                }
            }
        }
        public CompositeCategory(CompositeCategory a_copy, ScriptableObject a_parentObj)
        {
            CatagoryName = a_copy.CatagoryName;
            Composites   = new List <MxMAnimationClipComposite>(a_copy.Composites.Count + 1);

            IgnoreEdges_default       = a_copy.IgnoreEdges_default;
            Extrapolate_default       = a_copy.Extrapolate_default;
            FlattenTrajectory_default = a_copy.FlattenTrajectory_default;
            RuntimeSplicing_default   = a_copy.RuntimeSplicing_default;
            RequireTags_default       = a_copy.RequireTags_default;
            FavourTags_default        = a_copy.FavourTags_default;

            foreach (MxMAnimationClipComposite sourceComposite in a_copy.Composites)
            {
                MxMAnimationClipComposite newComposite = ScriptableObject.CreateInstance <MxMAnimationClipComposite>();
                newComposite.CopyData(sourceComposite);
                newComposite.name      = sourceComposite.name;
                newComposite.hideFlags = HideFlags.HideInHierarchy;

                MxMPreProcessData targetPreProcess = a_parentObj as MxMPreProcessData;
                AnimationModule   targetAnimModule = a_parentObj as AnimationModule;

                if (targetPreProcess != null)
                {
                    newComposite.TargetPreProcess = targetPreProcess;
                    newComposite.TargetAnimModule = null;
                }
                else if (targetAnimModule != null)
                {
                    newComposite.TargetPreProcess = null;
                    newComposite.TargetAnimModule = targetAnimModule;
                }

                EditorUtility.SetDirty(newComposite);

                if (a_parentObj != null)
                {
                    AssetDatabase.AddObjectToAsset(newComposite, a_parentObj);
                }

                Composites.Add(newComposite);
            }
        }
        //===========================================================================================

        /**
         *  @brief
         *
         *********************************************************************************************/
        private void NextBlendSpace()
        {
            MxMPreProcessData preProcessData = m_spTargetPreProcessData.objectReferenceValue as MxMPreProcessData;
            AnimationModule   animModule     = m_spTargetAnimModule.objectReferenceValue as AnimationModule;

            List <MxMBlendSpace> blendSpaceList = null;


            if (preProcessData != null)
            {
                blendSpaceList = preProcessData.BlendSpaces;
            }
            else if (animModule != null)
            {
                blendSpaceList = animModule.BlendSpaces;
            }

            if (blendSpaceList != null)
            {
                for (int i = 0; i < blendSpaceList.Count; ++i)
                {
                    if (blendSpaceList[i] == m_data)
                    {
                        if (i < blendSpaceList.Count - 1)
                        {
                            blendSpaceList[i + 1].ValidateBaseData();
                            SetData(blendSpaceList[i + 1]);
                        }
                        else
                        {
                            blendSpaceList[0].ValidateBaseData();
                            SetData(blendSpaceList[0]);
                        }

                        break;
                    }
                }
            }
        }
        private void LastComposite()
        {
            MxMPreProcessData preProcessData = m_spTargetPreProcessData.objectReferenceValue as MxMPreProcessData;
            AnimationModule   animModule     = m_spTargetAnimModule.objectReferenceValue as AnimationModule;

            List <MxMAnimationClipComposite> compList = null;

            if (preProcessData != null)
            {
                compList = preProcessData.GetCompositeCategoryList(m_data.CategoryId);
            }
            else if (animModule != null)
            {
                compList = animModule.GetCompositeCategoryList(m_data.CategoryId);
            }

            if (compList != null)
            {
                for (int i = 0; i < compList.Count; ++i)
                {
                    if (compList[i] == m_data)
                    {
                        if (i == 0)
                        {
                            compList[compList.Count - 1].ValidateBaseData();
                            SetData(compList[compList.Count - 1]);
                        }
                        else
                        {
                            compList[i - 1].ValidateBaseData();
                            SetData(compList[i - 1]);
                        }

                        break;
                    }
                }
            }
        }
 public void GenerateModifiedAnimation(MxMPreProcessData a_preProcessData, string a_directory) { }
Exemplo n.º 13
0
        public void GenerateModifiedAnimation(MxMPreProcessData a_preProcessData, string a_directory)
        {
            EditorUtility.DisplayProgressBar("Generate Modified Animations", "Scraping Old Anims", 0f);

            if (a_preProcessData != null)
                m_targetPreProcessData = a_preProcessData;

            ScrapGeneratedClips();

            List<MotionSection> motionList = MotionModifier.MotionSections;
            MotionTimingPresets presets = m_targetPreProcessData.MotionTimingPresets;



            if (UseSpeedMods && m_clips != null && m_targetPreProcessData != null)
            {
                int blendSpaceId = 0;
                for (int i = 0; i < m_targetPreProcessData.BlendSpaces.Count; ++i)
                {
                    if(this == m_targetPreProcessData.BlendSpaces[i])
                    {
                        blendSpaceId = i;
                        break;
                    }
                }

                float cumTimeShift = 0f; //This is the cumulative amount of time shift at the point of modification;
                float curStartTime = 0f; //The start time for the current motion section
                //Loop clips and generate ndes ones
                foreach (AnimationClip clip in m_clips)
                {
                    EditorUtility.DisplayProgressBar("Generate Modified Animation", "Copying Clip " + clip.name, 0f);

                    var generatedClip = new AnimationClip();
                    EditorUtility.CopySerialized(clip, generatedClip);
                    generatedClip.name = clip.name + "_MxM_MOD_" + blendSpaceId;

                    var curveBindings = AnimationUtility.GetCurveBindings(generatedClip);
                    List<AnimationCurve> workingCurves = new List<AnimationCurve>(curveBindings.Length + 1);
                    List<AnimationEvent> newEvents = new List<AnimationEvent>();

                    //Create curves but don't add keys
                    for (int i = 0; i < curveBindings.Length; ++i)
                    {
                        workingCurves.Add(new AnimationCurve());
                    }

                    cumTimeShift = 0f;
                    curStartTime = 0f;
                    int[] startKeyIndex = new int[workingCurves.Count]; //The start key for the current motion section
                    for (int i = 0; i < motionList.Count; ++i)
                    {
                        EditorUtility.DisplayProgressBar("Generate Modified Animation",
                            "Modifying Section " + i + " of " + clip.name, ((float)i) / ((float)motionList.Count));

                        MotionSection motionSection = motionList[i];

                        float startWarpTime = curStartTime;
                        float endWarpTime = motionSection.EndTime;
                        float warpScale = motionSection.GetSpeedMod(curStartTime, presets, this);

                        float localTimeShift = (endWarpTime - startWarpTime) - (endWarpTime - startWarpTime) * warpScale;

                        //Shift Curve Keys
                        for (int k = 0; k < curveBindings.Length; ++k)
                        {
                            EditorCurveBinding binding = curveBindings[k];
                            AnimationCurve originalCurve = AnimationUtility.GetEditorCurve(clip, binding);
                            AnimationCurve workingCurve = workingCurves[k];

                            //Make a cut at the end only
                            int endKeyIndex = originalCurve.AddKey(endWarpTime, originalCurve.Evaluate(endWarpTime));

                            if (endKeyIndex == -1)
                                endKeyIndex = originalCurve.keys.Length - 1;

                            //Add in the intermediate keys scaled relative to the start and shifted by the cumulative time shift
                            for (int keyIndex = startKeyIndex[k]; i < motionList.Count - 1 ? keyIndex < endKeyIndex : keyIndex <= endKeyIndex; ++keyIndex)
                            {
                                Keyframe key = originalCurve.keys[keyIndex];
                                key.time = startWarpTime + ((key.time - startWarpTime) * warpScale) - cumTimeShift;
                                key.inTangent /= warpScale;
                                key.outTangent /= warpScale;

                                workingCurve.AddKey(key);
                            }

                            startKeyIndex[k] = endKeyIndex;
                        }

                        //Shift Animation Clip EventsEvents
                        foreach (AnimationEvent evt in generatedClip.events)
                        {
                            if (evt.time > startWarpTime && evt.time < endWarpTime)
                            {
                                //Scale & Shift
                                evt.time = startWarpTime + ((evt.time - startWarpTime) * warpScale) - cumTimeShift;
                            }

                            newEvents.Add(evt);
                        }
                    }

                    for (int i = 0; i < workingCurves.Count; ++i)
                    {
                        EditorUtility.DisplayProgressBar("Generate Modified Animation",
                            "Generating Curves for clip: " + clip.name, ((float)i) / ((float)workingCurves.Count));

                        AnimationUtility.SetEditorCurve(generatedClip, curveBindings[i], workingCurves[i]);
                    }

                    AnimationUtility.SetAnimationEvents(generatedClip, newEvents.ToArray());
                    EditorUtility.SetDirty(generatedClip);

                    AssetDatabase.CreateAsset(generatedClip, a_directory + "/" + generatedClip.name + ".anim");

                    AssetDatabase.ImportAsset(AssetDatabase.GetAssetPath(generatedClip));
                    GeneratedClips.Add(generatedClip);
                }
                //End loop clips. Generations is complete

                //Go through Motion Sections again and modify tag tracks and events
                cumTimeShift = 0f; //This is the cumulative amount of time shift at the point of modification;
                curStartTime = 0f; //The start time for the current motion section
                for (int i = 0; i < motionList.Count; ++i)
                {
                    MotionSection motionSection = motionList[i];

                    float startWarpTime = curStartTime;
                    float endWarpTime = motionSection.EndTime;
                    float warpScale = motionSection.GetSpeedMod(curStartTime, presets, this);

                    float localTimeShift = (endWarpTime - startWarpTime) - (endWarpTime - startWarpTime) * warpScale;

                    //Shift MXM Tag Points
                    foreach (TagTrack track in TagTracks)
                    {
                        TagTrack newTrack = new TagTrack(track);
                        List<Vector2> tagList = newTrack.Tags;

                        for (int k = 0; k < tagList.Count; ++k)
                        {
                            Vector2 newTag = tagList[k];

                            if (newTag.x > startWarpTime && newTag.x < endWarpTime)
                            {
                                newTag.x = startWarpTime + ((newTag.x - startWarpTime) * warpScale) - cumTimeShift;
                            }

                            if (newTag.y > startWarpTime && newTag.y < endWarpTime)
                            {
                                newTag.y = startWarpTime + ((newTag.y - startWarpTime) * warpScale) - cumTimeShift;
                            }

                            tagList[k] = newTag;
                        }

                        GeneratedTagTracks.Add(newTrack);
                    }

                    cumTimeShift += localTimeShift;
                    curStartTime = endWarpTime;
                }  
            }

            EditorUtility.SetDirty(this);
            EditorUtility.ClearProgressBar();
        }
Exemplo n.º 14
0
        public static void DetectFootsteps(IMxMAnim a_mxmAnim, GameObject a_targetModel, MxMPreProcessData a_preProcessData,
                                           AnimationModule a_animModule, float a_groundingThreshold, float a_minSpacing, float a_minDuration, float a_maxFootSpeed)
        {
            if ((a_preProcessData == null && a_animModule == null) || a_mxmAnim == null)
            {
                return;
            }

            AnimationClip targetClip = a_mxmAnim.TargetClip;

            if (targetClip == null)
            {
                return;
            }

            if (a_targetModel == null)
            {
                if (a_preProcessData == null)
                {
                    a_targetModel = a_preProcessData.Prefab;
                }
                else if (a_animModule == null)
                {
                    a_targetModel = a_animModule.Prefab;
                }

                if (a_targetModel == null)
                {
                    Debug.LogError("MxM Footstep Detection - The MxMAnim you are trying to detect footsteps for has no target" +
                                   "model. This could occur if your target model is not set on the pre-processor, or your animation module" +
                                   "doesn't have a MotionMatch Config referenced.");
                    return;
                }
            }

            List <FootStepData> leftFootStepData      = new List <FootStepData>();
            List <Vector2>      leftFootStepPositions = new List <Vector2>();

            List <FootStepData> rightFootStepData      = new List <FootStepData>();
            List <Vector2>      rightFootStepPositions = new List <Vector2>();

            GameObject model = GameObject.Instantiate(a_targetModel);

            model.transform.SetPositionAndRotation(Vector3.zero, Quaternion.identity);

            Animator animator = model.GetComponent <Animator>();

            if (animator == null)
            {
                animator = model.AddComponent <Animator>();
            }

            animator.applyRootMotion = true;
            animator.cullingMode     = AnimatorCullingMode.AlwaysAnimate;

            Transform leftToeJoint  = null;
            Transform rightToeJoint = null;

            bool getBonesByName = false;

            if (a_preProcessData != null)
            {
                getBonesByName = a_preProcessData.GetBonesByName;
            }
            else if (a_animModule != null)
            {
                getBonesByName = a_animModule.GetBonesByName;
            }

            if (!getBonesByName)
            {
                leftToeJoint  = animator.GetBoneTransform(HumanBodyBones.LeftToes);
                rightToeJoint = animator.GetBoneTransform(HumanBodyBones.RightToes);
            }
            else
            {
                //Get generic joints?
                Debug.LogWarning("Automatic detection of footsteps is not currently supported for generic rigs");
                return;
            }

            PlayableGraph playableGraph = PlayableGraph.Create();

            playableGraph.SetTimeUpdateMode(DirectorUpdateMode.Manual);
            var playableOutput = AnimationPlayableOutput.Create(playableGraph, "Animation", animator);
            var animationMixer = AnimationMixerPlayable.Create(playableGraph, 1, true);

            playableOutput.SetSourcePlayable(animationMixer);

            var clipPlayable = AnimationClipPlayable.Create(playableGraph, targetClip);

            animationMixer.ConnectInput(0, clipPlayable, 0);
            animationMixer.SetInputWeight(0, 1f);

            clipPlayable.SetTime(0.0);
            clipPlayable.SetTime(0.0);
            playableGraph.Evaluate(0f);
            model.transform.SetPositionAndRotation(Vector3.zero, Quaternion.identity);

            const float SixtyHz = 1f / 60f;

            float leftFootLowestY  = leftToeJoint.position.y;
            float rightFootLowestY = rightToeJoint.position.y;

            for (float time = 0f; time <= targetClip.length; time += SixtyHz)
            {
                float leftFootY  = leftToeJoint.position.y;
                float rightFootY = rightToeJoint.position.y;

                if (leftFootY < leftFootLowestY)
                {
                    leftFootLowestY = leftFootY;
                }

                if (rightFootY < rightFootLowestY)
                {
                    rightFootLowestY = rightFootY;
                }

                playableGraph.Evaluate(SixtyHz);
            }

            clipPlayable.SetTime(0.0);
            clipPlayable.SetTime(0.0);
            playableGraph.Evaluate(0f);
            bool leftFootGrounded  = false;
            bool rightFootGrounded = false;

            float leftStepStartTime = 0f;
            float leftStepEndTime   = 0f;

            float rightStepStartTime = 0f;
            float rightStepEndTime   = 0f;

            model.transform.SetPositionAndRotation(Vector3.zero, Quaternion.identity);

            float leftToeSpeed  = 0f;
            float rightToeSpeed = 0f;

            Vector3 leftToeLastPos  = leftToeJoint.position;
            Vector3 rightToeLastPos = rightToeJoint.position;

            for (float time = 0f; time <= targetClip.length; time += SixtyHz)
            {
                //Velocities
                leftToeSpeed    = Vector3.Distance(leftToeLastPos, leftToeJoint.position) / SixtyHz;
                rightToeSpeed   = Vector3.Distance(rightToeLastPos, rightToeJoint.position) / SixtyHz;
                leftToeLastPos  = leftToeJoint.position;
                rightToeLastPos = rightToeJoint.position;

                //LEFT FOOT
                float leftFootDif = leftToeJoint.position.y - leftFootLowestY;
                if (leftFootDif < a_groundingThreshold && leftToeSpeed < a_maxFootSpeed)
                {
                    if (leftFootGrounded == false)
                    {
                        leftStepStartTime = time;
                    }

                    leftFootGrounded = true;
                }
                else
                {
                    if (leftFootGrounded == true)
                    {
                        leftStepEndTime = time;

                        leftFootStepData.Add(new FootStepData());
                        leftFootStepPositions.Add(new Vector2(leftStepStartTime, leftStepEndTime));
                    }

                    leftFootGrounded = false;
                }

                //RIGHT FOOT
                float rightFootDif = rightToeJoint.position.y - rightFootLowestY;

                if (rightFootDif < a_groundingThreshold && rightToeSpeed < a_maxFootSpeed)
                {
                    if (rightFootGrounded == false)
                    {
                        rightStepStartTime = time;
                    }

                    rightFootGrounded = true;
                }
                else
                {
                    if (rightFootGrounded == true)
                    {
                        rightStepEndTime = time;

                        rightFootStepData.Add(new FootStepData());
                        rightFootStepPositions.Add(new Vector2(rightStepStartTime, rightStepEndTime));
                    }

                    rightFootGrounded = false;
                }

                playableGraph.Evaluate(SixtyHz);
            }

            List <TagTrackBase> genericTagTracks = a_mxmAnim.GenericTagTracks;
            FootStepTagTrack    leftFootTagTrack = genericTagTracks[0] as FootStepTagTrack;

            leftFootTagTrack.RemoveAllTags();

            for (int i = 0; i < leftFootStepPositions.Count; ++i)
            {
                Vector2 footStepPosition = leftFootStepPositions[i];

                //Combine footsteps that are too close to be real (This should be recursive)
                if (i + 1 < leftFootStepPositions.Count)
                {
                    for (int k = i + 1; k < leftFootStepPositions.Count; ++k)
                    {
                        Vector2 nextFootStepPos = leftFootStepPositions[k];

                        if (nextFootStepPos.x - footStepPosition.y < a_minSpacing)
                        {
                            footStepPosition.y = nextFootStepPos.y;
                            leftFootStepPositions.RemoveAt(k);
                            --k;
                        }
                        else
                        {
                            break;
                        }
                    }
                }

                //Ignore footsteps that are too short to be real
                if (footStepPosition.y - footStepPosition.x < a_minDuration)
                {
                    continue;
                }

                leftFootTagTrack.AddTag(footStepPosition.x, footStepPosition.y);
            }

            FootStepTagTrack rightFootTagTrack = genericTagTracks[1] as FootStepTagTrack;

            rightFootTagTrack.RemoveAllTags();

            for (int i = 0; i < rightFootStepPositions.Count; ++i)
            {
                Vector3 footStepPosition = rightFootStepPositions[i];

                //Combine footsteps that are too close to be real (This should be recursive)
                if (i + 1 < rightFootStepPositions.Count)
                {
                    for (int k = i + 1; k < rightFootStepPositions.Count; ++k)
                    {
                        Vector2 nextFootStepPos = rightFootStepPositions[k];

                        if (nextFootStepPos.x - footStepPosition.y < a_minSpacing)
                        {
                            footStepPosition.y = nextFootStepPos.y;
                            rightFootStepPositions.RemoveAt(k);
                            --k;
                        }
                        else
                        {
                            break;
                        }
                    }
                }

                //Ignore footsteps that are too short to be real
                if (footStepPosition.y - footStepPosition.x < a_minDuration)
                {
                    continue;
                }

                rightFootTagTrack.AddTag(footStepPosition.x, footStepPosition.y);
            }

            GameObject.DestroyImmediate(model);
        }
        public void CopyData(MxMAnimationClipComposite a_copy)
        {
            PrimaryClip = a_copy.PrimaryClip;
            BeforeClips = new List<AnimationClip>(a_copy.BeforeClips);
            AfterClips = new List<AnimationClip>(a_copy.AfterClips);

            Looping= a_copy.Looping;
            IgnoreEdges = a_copy.IgnoreEdges;
            ExtrapolateTrajectory = a_copy.ExtrapolateTrajectory;
            FlattenTrajectory = a_copy.FlattenTrajectory;
            RuntimeSplicing = a_copy.RuntimeSplicing;
            UseSpeedMods = a_copy.UseSpeedMods;

            GlobalTags = a_copy.GlobalTags;
            GlobalFavourTags = a_copy.GlobalFavourTags;

            TagTracks = new List<TagTrack>(a_copy.TagTracks.Count + 1);
            foreach(TagTrack track in a_copy.TagTracks)
            {
                TagTracks.Add(new TagTrack(track));
            }

            for (int i = 0; i < a_copy.TagTracks.Count; ++i)
            {
                TagTracks.Add(new TagTrack(a_copy.TagTracks[i]));
            }

            FavourTagTracks = new List<TagTrack>(a_copy.FavourTagTracks.Count + 1);
            foreach(TagTrack track  in a_copy.FavourTagTracks)
            {
                FavourTagTracks.Add(new TagTrack(track));
            }

            UserBoolTracks = new List<TagTrackBase>(a_copy.UserBoolTracks.Count + 1);
            foreach(TagTrackBase track in a_copy.UserBoolTracks)
            {
                UserBoolTracks.Add(new TagTrackBase(track));
            }

            Events = new List<EventMarker>(a_copy.Events.Count + 1);
            foreach(EventMarker marker in a_copy.Events)
            {
                Events.Add(new EventMarker(marker));
            }

            m_targetPreProcessData = a_copy.m_targetPreProcessData;
            m_targetAnimModule = a_copy.m_targetAnimModule;
            m_targetPrefab = a_copy.m_targetPrefab;

            PoseList = null;

            LeftFootStepTrack = new FootStepTagTrack(a_copy.LeftFootStepTrack);
            RightFootStepTrack = new FootStepTagTrack(a_copy.RightFootStepTrack);
            WarpPositionTrack = new TagTrackBase(a_copy.WarpPositionTrack);
            WarpRotationTrack = new TagTrackBase(a_copy.WarpRotationTrack);
            EnableRootMotionTrack = new TagTrackBase(a_copy.EnableRootMotionTrack);
            PoseFavourTrack = new FloatTagTrack(a_copy.PoseFavourTrack);
            WarpTrajLatTrack = new TagTrackBase(a_copy.WarpTrajLatTrack);
            WarpTrajLongTrack = new TagTrackBase(a_copy.WarpTrajLongTrack);

            MotionModifier = new MotionModifyData(a_copy.MotionModifier, this);
        }
        //===========================================================================================

        /**
         *  @brief
         *
         *********************************************************************************************/
        public void OnGUI(Rect a_position)
        {
            if (m_data == null)
            {
                MxMSettings settings = MxMSettings.Instance();
                if (settings != null)
                {
                    m_data = settings.ActiveBlendSpace;

                    if (m_data != null)
                    {
                        SetData(m_data);
                    }
                }
            }

            if (m_data != null)
            {
                Event evt = Event.current;

                float labelWidth = EditorGUIUtility.labelWidth;

                if (evt.type == EventType.Repaint)
                {
                    if (m_queueDeleteIndex >= 0 && m_queueDeleteIndex < m_spClips.arraySize)
                    {
                        if (m_selectId == m_queueDeleteIndex)
                        {
                            m_selectId = -1;
                        }

                        if (m_spClips.GetArrayElementAtIndex(m_queueDeleteIndex).objectReferenceValue != null)
                        {
                            m_spClips.DeleteArrayElementAtIndex(m_queueDeleteIndex);
                        }

                        m_spClips.DeleteArrayElementAtIndex(m_queueDeleteIndex);
                        m_spPositions.DeleteArrayElementAtIndex(m_queueDeleteIndex);

                        m_queueDeleteIndex = -1;
                    }
                }

                EditorGUILayout.BeginVertical();
                EditorGUILayout.BeginHorizontal(EditorStyles.toolbar, GUILayout.Height(20f), GUILayout.ExpandWidth(true));

                EditorGUI.BeginChangeCheck();
                m_previewActive = GUILayout.Toggle(m_previewActive, "Preview", EditorStyles.toolbarButton, GUILayout.Width(60f));
                if (EditorGUI.EndChangeCheck())
                {
                    if (m_previewActive)
                    {
                        BeginPreview();
                    }
                    else
                    {
                        EndPreview();
                    }
                }



                if (m_previewActive && MxMPreviewScene.IsSceneLoaded)
                {
                    EditorGUIUtility.labelWidth = 20f;

                    EditorGUI.BeginChangeCheck();
                    m_previewPos.x = EditorGUILayout.FloatField("X: ", m_previewPos.x, EditorStyles.toolbarTextField);
                    m_previewPos.y = EditorGUILayout.FloatField("Y: ", m_previewPos.y, EditorStyles.toolbarTextField);
                    if (EditorGUI.EndChangeCheck())
                    {
                        m_previewPos.x = Mathf.Clamp(m_previewPos.x, -1f, 1f);
                        m_previewPos.y = Mathf.Clamp(m_previewPos.y, -1f, 1f);

                        CalculateBlendWeights();
                        ApplyBlendWeights();
                    }
                    EditorGUIUtility.labelWidth = labelWidth;

                    UpdatePreview();
                    MxMAnimConfigWindow.Inst().Repaint();
                }

                GUILayout.FlexibleSpace();

                m_spNormalizeTime.boolValue = GUILayout.Toggle(m_spNormalizeTime.boolValue, "Normalize Time",
                                                               EditorStyles.toolbarButton, GUILayout.Width(90f));

                EditorGUILayout.LabelField("Type:", GUILayout.Width(40f));
                m_spScatterSpace.enumValueIndex = (int)(EBlendSpaceType)EditorGUILayout.EnumPopup(
                    (EBlendSpaceType)m_spScatterSpace.enumValueIndex, GUILayout.Width(70f));
                GUILayout.Space(5f);

                switch ((EBlendSpaceType)m_spScatterSpace.enumValueIndex)
                {
                case EBlendSpaceType.Standard:
                {
                    EditorGUILayout.LabelField("Magnitude ", GUILayout.Width(62f));
                    m_spMagnitude.vector2Value = EditorGUILayout.Vector2Field("", m_spMagnitude.vector2Value, GUILayout.Width(100f));
                    EditorGUILayout.LabelField("Smoothing ", GUILayout.Width(65f));
                    m_spSmoothing.vector2Value = EditorGUILayout.Vector2Field("", m_spSmoothing.vector2Value, GUILayout.Width(100f));
                }
                break;

                case EBlendSpaceType.Scatter:
                {
                    EditorGUILayout.LabelField("Spacing", GUILayout.Width(50f));
                    m_spScatterSpacing.vector2Value = EditorGUILayout.Vector2Field("", m_spScatterSpacing.vector2Value, GUILayout.Width(100f));
                }
                break;

                case EBlendSpaceType.ScatterX:
                {
                    EditorGUILayout.LabelField("Spacing X", GUILayout.Width(60f));
                    float spacingX = EditorGUILayout.FloatField(m_spScatterSpacing.vector2Value.x, GUILayout.Width(35f));

                    m_spScatterSpacing.vector2Value = new Vector2(spacingX, m_spScatterSpacing.vector2Value.y);
                }
                break;

                case EBlendSpaceType.ScatterY:
                {
                    EditorGUILayout.LabelField("Spacing Y", GUILayout.Width(60f));
                    float spacingY = EditorGUILayout.FloatField(m_spScatterSpacing.vector2Value.y, GUILayout.Width(35f));

                    m_spScatterSpacing.vector2Value = new Vector2(m_spScatterSpacing.vector2Value.x, spacingY);
                }
                break;
                }



                GUILayout.Space(2f);
                m_showClipNames = GUILayout.Toggle(m_showClipNames, "Show Clips", EditorStyles.toolbarButton, GUILayout.Width(80f));
                GUILayout.Space(5f);
                m_snapActive = GUILayout.Toggle(m_snapActive, "Snap", EditorStyles.toolbarButton, GUILayout.Width(40f));

                if (m_snapActive)
                {
                    m_snapInterval = EditorGUILayout.FloatField(m_snapInterval, EditorStyles.toolbarTextField, GUILayout.Width(30f));
                }

                EditorGUILayout.EndHorizontal();
                GUILayout.FlexibleSpace();

                EditorGUILayout.BeginHorizontal(EditorStyles.toolbar, GUILayout.Height(20f), GUILayout.ExpandWidth(true));

                if (m_selectId >= 0 && m_selectId < m_spClips.arraySize)
                {
                    AnimationClip      clip       = m_spClips.GetArrayElementAtIndex(m_selectId).objectReferenceValue as AnimationClip;
                    SerializedProperty spPosition = m_spPositions.GetArrayElementAtIndex(m_selectId);

                    if (clip != null && spPosition != null)
                    {
                        EditorGUILayout.LabelField(clip.name, GUILayout.Width(GUI.skin.label.CalcSize(new GUIContent(clip.name)).x + 4f));

                        EditorGUI.BeginChangeCheck();
                        spPosition.vector2Value = EditorGUILayout.Vector2Field("", spPosition.vector2Value);
                        if (EditorGUI.EndChangeCheck())
                        {
                            if (m_previewActive && MxMPreviewScene.IsSceneLoaded)
                            {
                                CalculateBlendWeights();
                                ApplyBlendWeights();
                            }
                        }
                    }
                }

                EditorGUILayout.LabelField("Require", GUILayout.Width(50f));
                MxMPreProcessData preProcessData = m_spTargetPreProcessData.objectReferenceValue as MxMPreProcessData;
                AnimationModule   animModule     = m_spTargetAnimModule.objectReferenceValue as AnimationModule;

                if (preProcessData != null)
                {
                    EditorFunctions.DrawTagFlagFieldWithCustomNames(preProcessData.TagNames.ToArray(), m_spGlobalTags, 100f);
                }
                else if (animModule != null && animModule.TagNames != null)
                {
                    EditorFunctions.DrawTagFlagFieldWithCustomNames(animModule.TagNames.ToArray(), m_spGlobalTags, 100f);
                }
                else
                {
                    m_spGlobalTags.intValue = (int)(ETags)EditorGUILayout.EnumFlagsField((ETags)m_spGlobalTags.intValue);
                }

                EditorGUILayout.LabelField("Favour", GUILayout.Width(45f));

                if (preProcessData != null)
                {
                    EditorFunctions.DrawTagFlagFieldWithCustomNames(preProcessData.FavourTagNames.ToArray(), m_spGlobalFavourTags, 100f);
                }
                else if (animModule != null && animModule.FavourTagNames != null)
                {
                    EditorFunctions.DrawTagFlagFieldWithCustomNames(animModule.FavourTagNames.ToArray(), m_spGlobalFavourTags, 100f);
                }
                else
                {
                    m_spGlobalFavourTags.intValue = (int)(ETags)EditorGUILayout.EnumFlagsField((ETags)m_spGlobalFavourTags.intValue);
                }

                GUILayout.FlexibleSpace();

                if (GUILayout.Button(new GUIContent("Open Timeline"), EditorStyles.toolbarButton))
                {
                    MxMTaggingWindow.ShowWindow();
                }

                GUILayout.Space(5f);

                if (m_spTargetPreProcessData.objectReferenceValue != null ||
                    m_spTargetAnimModule.objectReferenceValue != null)
                {
                    if (GUILayout.Button(EditorGUIUtility.IconContent("back").image, EditorStyles.toolbarButton))
                    {
                        LastBlendSpace();
                    }

                    if (GUILayout.Button(EditorGUIUtility.IconContent("forward").image, EditorStyles.toolbarButton))
                    {
                        NextBlendSpace();
                    }
                }

                EditorGUI.BeginDisabledGroup(true);

                EditorGUIUtility.labelWidth = 110f;
                if (preProcessData != null)
                {
                    EditorGUILayout.ObjectField(m_spTargetPreProcessData, new GUIContent("Target PreProcess"));
                }
                else if (animModule != null)
                {
                    EditorGUILayout.ObjectField(m_spTargetAnimModule, new GUIContent("Target Anim Module"));
                }

                EditorGUIUtility.labelWidth = 95f;
                EditorGUILayout.ObjectField(m_spTargetPrefab, new GUIContent("Preview Prefab"));

                EditorGUI.EndDisabledGroup();

                EditorGUIUtility.labelWidth = labelWidth;

                EditorGUILayout.EndHorizontal();
                EditorGUILayout.EndVertical();

                Rect blendSpaceRect = new Rect(30f, 40f, a_position.width - 60f, a_position.height - 90f);

                GUI.Box(blendSpaceRect, "");

                Rect labelRect = new Rect(blendSpaceRect.x - 18f, blendSpaceRect.y, 18f, 18f);

                GUI.Label(labelRect, "1");
                labelRect.y += blendSpaceRect.height / 2f - 9f;
                GUI.Label(labelRect, "0");
                labelRect.y = blendSpaceRect.y + blendSpaceRect.height - 18f;
                GUI.Label(labelRect, "-1");
                labelRect.y += labelRect.height;
                labelRect.x += labelRect.width;
                GUI.Label(labelRect, "-1");
                labelRect.x += blendSpaceRect.width / 2f - 9f;
                GUI.Label(labelRect, "0");
                labelRect.x = blendSpaceRect.x + blendSpaceRect.width - 18f;
                GUI.Label(labelRect, "1");

                float spacingH = blendSpaceRect.width / 10f;
                float spacingV = blendSpaceRect.height / 10f;

                float top    = blendSpaceRect.y;
                float bottom = blendSpaceRect.y + blendSpaceRect.height;
                float left   = blendSpaceRect.x;
                float right  = blendSpaceRect.x + blendSpaceRect.width;

                Handles.color = Color.grey;
                for (int i = 1; i < 10; ++i)
                {
                    float horizontal = i * spacingH + blendSpaceRect.x;
                    float vertical   = i * spacingV + blendSpaceRect.y;

                    Handles.DrawLine(new Vector3(horizontal, top), new Vector3(horizontal, bottom));
                    Handles.DrawLine(new Vector3(left, vertical), new Vector3(right, vertical));
                }

                Handles.color = Color.black;
                Handles.DrawLine(new Vector3(blendSpaceRect.x + blendSpaceRect.width / 2f, top),
                                 new Vector3(blendSpaceRect.x + blendSpaceRect.width / 2f, bottom));

                Handles.DrawLine(new Vector3(left, blendSpaceRect.y + blendSpaceRect.height / 2f),
                                 new Vector3(right, blendSpaceRect.y + blendSpaceRect.height / 2f));

                Rect    animDrawRect    = new Rect(0f, 0f, 18f, 18f);
                Vector2 blendSpaceRatio = new Vector2(2f / blendSpaceRect.width, 2f / blendSpaceRect.height);

                Texture blendKey         = EditorGUIUtility.IconContent("blendKey").image;
                Texture blendKeySelected = EditorGUIUtility.IconContent("blendKeySelected").image;
                Texture previewPointTex  = EditorGUIUtility.IconContent("d_P4_AddedLocal").image;

                Vector2 centerPos = blendSpaceRect.position;
                centerPos.x += blendSpaceRect.width / 2f;
                centerPos.y += blendSpaceRect.height / 2f;

                //Draw Points
                for (int i = 0; i < m_spClips.arraySize; ++i)
                {
                    Vector2 normalizedPos = m_spPositions.GetArrayElementAtIndex(i).vector2Value;
                    normalizedPos.y *= -1f;

                    animDrawRect.position = (normalizedPos / blendSpaceRatio) + centerPos;

                    animDrawRect.size = new Vector2(14f, 14f);

                    if (m_previewActive && MxMPreviewScene.IsSceneLoaded)
                    {
                        float size = 9f + 5f * m_blendWeights[i];
                        animDrawRect.size = new Vector2(size, size);
                    }
                    else
                    {
                        animDrawRect.size = new Vector2(14f, 14f);
                    }

                    animDrawRect.position -= (animDrawRect.size / 2f);

                    if (m_selectId == i)
                    {
                        GUI.DrawTexture(animDrawRect, blendKeySelected);
                    }
                    else
                    {
                        GUI.DrawTexture(animDrawRect, blendKey);
                    }

                    if (m_showClipNames)
                    {
                        AnimationClip clip = m_spClips.GetArrayElementAtIndex(i).objectReferenceValue as AnimationClip;

                        Vector2 labelSize = GUI.skin.label.CalcSize(new GUIContent(clip.name));

                        Rect clipNameRect = new Rect(animDrawRect.x + (animDrawRect.width / 2f) - labelSize.x / 2f,
                                                     animDrawRect.y - labelSize.y, labelSize.x, labelSize.y);

                        GUI.Label(clipNameRect, clip.name);
                    }

                    if (evt.type == EventType.MouseDown && evt.button == 0)
                    {
                        if (animDrawRect.Contains(evt.mousePosition))
                        {
                            m_selectId       = i;
                            m_dragging       = true;
                            m_cumulativeDrag = m_spPositions.GetArrayElementAtIndex(i).vector2Value;

                            if (evt.clickCount >= 2)
                            {
                                EditorGUIUtility.PingObject(m_spClips.GetArrayElementAtIndex(i).objectReferenceValue);
                            }

                            evt.Use();
                            MxMAnimConfigWindow.Inst().Repaint();
                        }
                    }
                }

                //Draw Preview Point
                if (m_previewActive && MxMPreviewScene.IsSceneLoaded)
                {
                    Vector3 previewDrawPos = m_previewPos;
                    previewDrawPos.y *= -1f;

                    animDrawRect.size     = new Vector2(18f, 18f);
                    animDrawRect.position = (previewDrawPos / blendSpaceRatio) + centerPos - (animDrawRect.size / 2f);

                    GUI.DrawTexture(animDrawRect, previewPointTex);
                }

                switch (evt.type)
                {
                case EventType.MouseDown:
                {
                    if (m_previewActive && blendSpaceRect.Contains(evt.mousePosition) && MxMPreviewScene.IsSceneLoaded)
                    {
                        Vector2 blendSpacePos = evt.mousePosition - (blendSpaceRect.position + (blendSpaceRect.size / 2f));
                        m_previewPos    = blendSpacePos * blendSpaceRatio;
                        m_previewPos.y *= -1f;

                        m_previewPos.x = Mathf.Clamp(m_previewPos.x, -1f, 1f);
                        m_previewPos.y = Mathf.Clamp(m_previewPos.y, -1f, 1f);

                        CalculateBlendWeights();
                        ApplyBlendWeights();


                        m_draggingPreview = true;
                    }

                    m_dragging = false;
                    m_selectId = -1;
                    evt.Use();
                }
                break;

                case EventType.MouseUp:
                {
                    if (m_dragging || m_draggingPreview)
                    {
                        m_draggingPreview = false;
                        m_dragging        = false;
                        m_cumulativeDrag  = Vector2.zero;
                        evt.Use();
                    }
                }
                break;

                case EventType.MouseDrag:
                {
                    if (m_dragging)
                    {
                        if (m_selectId >= 0 && m_selectId < m_spPositions.arraySize)
                        {
                            SerializedProperty spPosition = m_spPositions.GetArrayElementAtIndex(m_selectId);
                            Vector2            moveDelta  = evt.delta;
                            moveDelta.y *= -1f;

                            if (m_snapActive)
                            {
                                m_cumulativeDrag += moveDelta * blendSpaceRatio;

                                m_cumulativeDrag.x = Mathf.Clamp(m_cumulativeDrag.x, -1f, 1f);
                                m_cumulativeDrag.y = Mathf.Clamp(m_cumulativeDrag.y, -1f, 1f);

                                spPosition.vector2Value = m_cumulativeDrag;
                                SnapClip(m_selectId);
                            }
                            else
                            {
                                Vector2 newPos = spPosition.vector2Value + moveDelta * blendSpaceRatio;

                                newPos.x = Mathf.Clamp(newPos.x, -1f, 1f);
                                newPos.y = Mathf.Clamp(newPos.y, -1f, 1f);
                                spPosition.vector2Value = newPos;
                            }

                            if (m_previewActive && MxMPreviewScene.IsSceneLoaded)
                            {
                                CalculateBlendWeights();
                                ApplyBlendWeights();
                            }

                            evt.Use();
                        }
                        else
                        {
                            m_dragging = false;
                        }
                    }
                    else if (m_previewActive && m_draggingPreview && MxMPreviewScene.IsSceneLoaded)
                    {
                        Vector2 blendSpacePos = evt.mousePosition - (blendSpaceRect.position + (blendSpaceRect.size / 2f));
                        m_previewPos    = blendSpacePos * blendSpaceRatio;
                        m_previewPos.y *= -1f;

                        m_previewPos.x = Mathf.Clamp(m_previewPos.x, -1f, 1f);
                        m_previewPos.y = Mathf.Clamp(m_previewPos.y, -1f, 1f);

                        CalculateBlendWeights();
                        ApplyBlendWeights();

                        if (m_snapActive)
                        {
                            SnapPreview();
                        }

                        evt.Use();
                    }
                }
                break;

                case EventType.KeyDown:
                {
                    if (m_selectId >= 0 && m_selectId < m_spClips.arraySize)
                    {
                        if (evt.keyCode == KeyCode.Delete)
                        {
                            m_queueDeleteIndex = m_selectId;
                            MxMAnimConfigWindow.Inst().Repaint();
                            evt.Use();
                        }
                    }
                }
                break;
                }

                DragDropAnimations(blendSpaceRect);

                if (m_soData != null)
                {
                    m_soData.ApplyModifiedProperties();
                }
            }
            else
            {
                GUILayout.Space(18f);
                EditorGUILayout.BeginHorizontal();
                GUILayout.FlexibleSpace();
                EditorGUILayout.LabelField("No Blend Space Selected.", EditorStyles.boldLabel);
                GUILayout.FlexibleSpace();
                EditorGUILayout.EndHorizontal();
            }
        }
        public void GenerateModifiedAnimation(MxMPreProcessData a_preProcessData, string a_directory)
        {
            EditorUtility.DisplayProgressBar("Generate Modified Animation", "Scraping Old Anims", 0f);

            if (a_preProcessData != null)
                m_targetPreProcessData = a_preProcessData;

            ScrapGeneratedClips();

            if (UseSpeedMods)
            {
                if (PrimaryClip != null && m_targetPreProcessData != null)
                {

                    EditorUtility.DisplayProgressBar("Generate Modified Animation", "Copying Clip " + PrimaryClip.name, 0f);

                    GeneratedClip = new AnimationClip();
                    EditorUtility.CopySerialized(PrimaryClip, GeneratedClip);
                    GeneratedClip.name = PrimaryClip.name + "_MxM_MOD";

                    var curveBindings = AnimationUtility.GetCurveBindings(GeneratedClip);
                    List<AnimationCurve> workingCurves = new List<AnimationCurve>(curveBindings.Length + 1);
                    List<AnimationEvent> newEvents = new List<AnimationEvent>();
                    List<MotionSection> motionList = MotionModifier.MotionSections;
                    MotionTimingPresets presets = m_targetPreProcessData.MotionTimingPresets;

                    GeneratedTagTracks = new List<TagTrack>(TagTracks);
                    GeneratedFavourTagTracks = new List<TagTrack>(TagTracks);
                    GeneratedUserBoolTracks = new List<TagTrackBase>(UserBoolTracks);
                    GeneratedLeftFootStepTrack = new FootStepTagTrack(LeftFootStepTrack);
                    GeneratedRightFootStepTrack = new FootStepTagTrack(RightFootStepTrack);
                    GeneratedWarpPositionTrack = new TagTrackBase(WarpPositionTrack);
                    GeneratedWarpRotationTrack = new TagTrackBase(WarpRotationTrack);
                    GeneratedEnableRootMotionTrack = new TagTrackBase(EnableRootMotionTrack);
                    GeneratedPoseFavourTrack = new FloatTagTrack(PoseFavourTrack);
                    GeneratedWarpTrajLatTrack = new TagTrackBase(WarpTrajLatTrack);
                    GeneratedWarpTrajLongTrack = new TagTrackBase(WarpTrajLongTrack);

                    //Create curves but don't add keys
                    for (int i = 0; i < curveBindings.Length; ++i)
                    {
                        workingCurves.Add(new AnimationCurve());
                    }

                    float cumTimeShift = 0f; //This is the cumulative amount of time shift at the point of modification;
                    float curStartTime = 0f; //The start time for the current motion section
                    int[] startKeyIndex = new int[workingCurves.Count]; //The start key for the current motion section
                    for (int i = 0; i < motionList.Count; ++i)
                    {
                        EditorUtility.DisplayProgressBar("Generate Modified Animation",
                            "Modifying Section " + i + " of " + PrimaryClip.name, ((float)i) / ((float)motionList.Count));

                        MotionSection motionSection = motionList[i];

                        float startWarpTime = curStartTime;
                        float endWarpTime = motionSection.EndTime;
                        float warpScale = motionSection.GetSpeedMod(curStartTime, presets, this);

                        float localTimeShift = (endWarpTime - startWarpTime) - (endWarpTime - startWarpTime) * warpScale;

                        //Shift Curve Keys
                        for (int k = 0; k < curveBindings.Length; ++k)
                        {
                            EditorCurveBinding binding = curveBindings[k];
                            AnimationCurve originalCurve = AnimationUtility.GetEditorCurve(PrimaryClip, binding);
                            AnimationCurve workingCurve = workingCurves[k];

                            //Make a cut at the end only
                            int endKeyIndex = originalCurve.AddKey(endWarpTime, originalCurve.Evaluate(endWarpTime));

                            if (endKeyIndex == -1)
                                endKeyIndex = originalCurve.keys.Length - 1;

                            //Add in the intermediate keys scaled relative to the start and shifted by the cumulative time shift
                            for (int keyIndex = startKeyIndex[k]; i < motionList.Count - 1 ? keyIndex < endKeyIndex : keyIndex <= endKeyIndex; ++keyIndex)
                            {
                                Keyframe key = originalCurve.keys[keyIndex];
                                key.time = startWarpTime + ((key.time - startWarpTime) * warpScale) - cumTimeShift;
                                key.inTangent /= warpScale;
                                key.outTangent /= warpScale;

                                workingCurve.AddKey(key);
                            }

                            startKeyIndex[k] = endKeyIndex;
                        }

                        //Shift Events
                        foreach (AnimationEvent evt in GeneratedClip.events)
                        {
                            if (evt.time > startWarpTime && evt.time < endWarpTime)
                            {
                                //Scale & Shift
                                evt.time = startWarpTime + ((evt.time - startWarpTime) * warpScale) - cumTimeShift;
                            }

                            newEvents.Add(evt);
                        }

                        //Shift MxM Events
                        foreach (EventMarker evt in Events)
                        {
                            EventMarker newMarker = new EventMarker(evt);

                            if (newMarker.EventTime > startWarpTime && evt.EventTime < endWarpTime)
                            {
                                evt.EventTime = startWarpTime + ((evt.EventTime - startWarpTime) * warpScale) - cumTimeShift;
                            }

                            GeneratedEvents.Add(newMarker);
                        }

                        //Shift MXM Tag Points
                        foreach (TagTrack track in GeneratedTagTracks)
                        {
                            List<Vector2> tagList = track.Tags;

                            for (int k = 0; k < tagList.Count; ++k)
                            {
                                Vector2 newTag = tagList[k];

                                if (newTag.x > startWarpTime && newTag.x < endWarpTime)
                                {
                                    newTag.x = startWarpTime + ((newTag.x - startWarpTime) * warpScale) - cumTimeShift;
                                }

                                if (newTag.y > startWarpTime && newTag.y < endWarpTime)
                                {
                                    newTag.y = startWarpTime + ((newTag.y - startWarpTime) * warpScale) - cumTimeShift;
                                }

                                tagList[k] = newTag;
                            }
                        }

                        //Shift MXM FavourTag Points
                        foreach (TagTrack track in GeneratedFavourTagTracks)
                        {
                            List<Vector2> tagList = track.Tags;

                            for (int k = 0; k < tagList.Count; ++k)
                            {
                                Vector2 newTag = tagList[k];

                                if (newTag.x > startWarpTime && newTag.x < endWarpTime)
                                {
                                    newTag.x = startWarpTime + ((newTag.x - startWarpTime) * warpScale) - cumTimeShift;
                                }

                                if (newTag.y > startWarpTime && newTag.y < endWarpTime)
                                {
                                    newTag.y = startWarpTime + ((newTag.y - startWarpTime) * warpScale) - cumTimeShift;
                                }

                                tagList[k] = newTag;
                            }
                        }

                        //Shift MxM User Tags
                        foreach (TagTrackBase track in GeneratedUserBoolTracks)
                        {
                            ShiftTrackTags(track, startWarpTime, endWarpTime, warpScale, cumTimeShift);
                        }

                        //Shift MxM Utility Tags
                        ShiftTrackTags(GeneratedLeftFootStepTrack, startWarpTime, endWarpTime, warpScale, cumTimeShift);
                        ShiftTrackTags(GeneratedRightFootStepTrack, startWarpTime, endWarpTime, warpScale, cumTimeShift);
                        ShiftTrackTags(GeneratedWarpPositionTrack, startWarpTime, endWarpTime, warpScale, cumTimeShift);
                        ShiftTrackTags(GeneratedWarpRotationTrack, startWarpTime, endWarpTime, warpScale, cumTimeShift);
                        ShiftTrackTags(GeneratedEnableRootMotionTrack, startWarpTime, endWarpTime, warpScale, cumTimeShift);
                        ShiftTrackTags(GeneratedPoseFavourTrack, startWarpTime, endWarpTime, warpScale, cumTimeShift);
                        ShiftTrackTags(GeneratedWarpTrajLatTrack, startWarpTime, endWarpTime, warpScale, cumTimeShift);
                        ShiftTrackTags(GeneratedWarpTrajLongTrack, startWarpTime, endWarpTime, warpScale, cumTimeShift);

                        cumTimeShift += localTimeShift;
                        curStartTime = endWarpTime;
                    }

                    for (int i = 0; i < workingCurves.Count; ++i)
                    {
                        EditorUtility.DisplayProgressBar("Generate Modified Animation",
                            "Generating Curves for clip: " + PrimaryClip.name, ((float)i) / ((float)workingCurves.Count));

                        AnimationUtility.SetEditorCurve(GeneratedClip, curveBindings[i], workingCurves[i]);
                    }

                    AnimationUtility.SetAnimationEvents(GeneratedClip, newEvents.ToArray());
                    EditorUtility.SetDirty(GeneratedClip);

                    AssetDatabase.CreateAsset(GeneratedClip, a_directory + "/" + GeneratedClip.name + ".anim");

                    //AssetDatabase.AddObjectToAsset(GeneratedClip, m_targetPreProcessData);
                    AssetDatabase.ImportAsset(AssetDatabase.GetAssetPath(GeneratedClip));

                    EditorUtility.SetDirty(this);

                    EditorUtility.ClearProgressBar();

                }
                else
                {
                    Debug.LogWarning("Warning: Cannot generate modified animation with no PrimaryClip in MxMAnimationClipComposite");
                }
            }
        }
        private void DrawSettings(Rect a_rect)
        {
            GUILayout.BeginArea(a_rect);

            m_spLooping.boolValue = EditorGUILayout.ToggleLeft(new GUIContent(
                                                                   "Loop", "Check if this animation loops"), m_spLooping.boolValue);

            if (!m_spLooping.boolValue)
            {
                m_spIgnoreEdges.boolValue = EditorGUILayout.ToggleLeft(new GUIContent(
                                                                           "Ignore Edges", "Clip edges will be marked as DoNotUse"), m_spIgnoreEdges.boolValue);

                if (!m_spIgnoreEdges.boolValue)
                {
                    m_spExtrapolateTrajectory.boolValue = EditorGUILayout.ToggleLeft(new GUIContent(
                                                                                         "Extrapolate", "Trajectory will be extrapolated"), m_spExtrapolateTrajectory.boolValue);
                }
            }

            m_spFlattenTrajectory.boolValue = EditorGUILayout.ToggleLeft(new GUIContent(
                                                                             "Flatten Trajectory", "Flatten the trejectory so that the 'y' axis component is always zero"),
                                                                         m_spFlattenTrajectory.boolValue);

            if (m_spAfterClips.arraySize > 0)
            {
                m_spRuntimeSplicing.boolValue = EditorGUILayout.ToggleLeft(new GUIContent(
                                                                               "Runtime Splicing", "Splice together the primary clip and first after clip at runtime to ensure continuity"),
                                                                           m_spRuntimeSplicing.boolValue);
            }

            MxMPreProcessData preProcessData = m_spTargetPreProcessData.objectReferenceValue as MxMPreProcessData;
            AnimationModule   animModule     = m_spTargetAnimModule.objectReferenceValue as AnimationModule;


            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("Require", GUILayout.Width(50f));
            if (preProcessData != null)
            {
                EditorFunctions.DrawTagFlagFieldWithCustomNames(preProcessData.TagNames.ToArray(), m_spGlobalTags, 75f);
            }
            else if (animModule != null && animModule.FavourTagNames != null)
            {
                EditorFunctions.DrawTagFlagFieldWithCustomNames(animModule.TagNames.ToArray(), m_spGlobalTags, 75f);
            }
            else
            {
                m_spGlobalTags.intValue = (int)(ETags)EditorGUILayout.EnumFlagsField((ETags)m_spGlobalTags.intValue);
            }

            EditorGUILayout.EndHorizontal();

            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("Favour", GUILayout.Width(50f));
            if (preProcessData != null)
            {
                EditorFunctions.DrawTagFlagFieldWithCustomNames(preProcessData.FavourTagNames.ToArray(), m_spGlobalFavourTags, 75f);
            }
            else if (animModule != null && animModule.FavourTagNames != null)
            {
                EditorFunctions.DrawTagFlagFieldWithCustomNames(animModule.FavourTagNames.ToArray(), m_spGlobalFavourTags, 75f);
            }
            else
            {
                m_spGlobalFavourTags.intValue = (int)(ETags)EditorGUILayout.EnumFlagsField((ETags)m_spGlobalFavourTags.intValue);
            }

            EditorGUILayout.EndHorizontal();

            GUILayout.EndArea();
        }