/// <summary>
    /// undo all replace operations
    /// </summary>
    public static void UndoAllReplace(CutsceneController cc)
    {
        for (var ie = cc.m_ReplRecord.GetEnumerator(); ie.MoveNext();)
        {
            var        pr    = ie.Current;
            GameObject extGO = pr.Key;
            //Transform extTr = extGO.transform;
            ReplData rData = pr.Value;

            //Dbg.Log("Undo Replace: extGO: {0}", rData.m_ExtGOOrigName);

            //1
            extGO.name = rData.m_ExtGOOrigName;


            //3
            if (rData.m_ExtGOOrigParent)
            {
                Misc.AddChild(rData.m_ExtGOOrigParent, extGO);
            }
            else
            {
                extGO.transform.parent = null;
            }

            //2
            if (rData.m_RevertPose)
            {
                _ExecuteRevertPose(rData);
            }

            //4
            if (rData.m_IntGO)
            {
                if (cc.m_BlendOutTime < 0)
                {
                    rData.m_IntGO.SetActive(true);
                }
                rData.m_IntGO.name = rData.m_IntGO.name.Substring(1);
            }

            //5
            if (rData.m_ReEnableAnimator)
            {
                _SetAnimatorEnableState(extGO, true);
            }

            //6. prepare blend-out
            if (cc.m_BlendOutTime >= 0)
            {
                BlendOutData boData = new BlendOutData();
                boData.m_InternalGO      = rData.m_IntGO;
                cc.m_BlendOutCtrl[extGO] = boData;
                cc._PrepareBlend(extGO.transform, boData.m_BlendDataLst);
            }
        }

        cc.m_ReplRecord.Clear();
        cc.m_ToSwapObjPairs.Clear();
    }
    // public method

    /// <summary>
    /// given an external GO (X) outside the CC,
    /// replace the GO (Y) inside CC with X, and change X's name to be Y's name
    ///
    /// this could be used to change the character appearance during cut-scene playing
    /// </summary>
    public void SwapGO(GameObject extGO, GameObject intGO, bool bRevertPoseAtEnd, bool bReEnableAnimator)
    {
        Transform extTr = extGO.transform;
        ReplData  rData = new ReplData();

        rData.m_ExtGOOrigName    = extGO.name;
        rData.m_ExtGOOrigParent  = extTr.parent;
        rData.m_IntGO            = intGO;
        rData.m_RevertPose       = bRevertPoseAtEnd;
        rData.m_ReEnableAnimator = bReEnableAnimator;
        var blendInDataBasedOnCC = rData.m_ExtGOTrDataBasedOnCC = new XformData();

        m_ReplRecord.Add(extGO, rData);

        intGO.SetActive(false);
        extGO.name = intGO.name;
        intGO.name = "_" + intGO.name; //make intGO a different name

        if (m_BlendInTime > 0 || rData.m_RevertPose)
        {
            _PrepareBlend(extTr, rData.m_ExtGOBlendData);
        }

        Misc.AddChild(intGO.transform.parent, extGO); // but UndoAllReplace needs localPosition based on old parent's transform

        blendInDataBasedOnCC.CopyFrom(extTr);         // blend-in needs localposition based on CC's transform
        extGO.transform.CopyLocal(intGO.transform);

        _SetAnimatorEnableState(extGO, false);
    }
 private static void _ExecuteRevertPose(ReplData rData)
 {
     for (int idx = 0; idx < rData.m_ExtGOBlendData.Count; ++idx)
     {
         BlendData bdata = rData.m_ExtGOBlendData[idx];
         bdata.DoRevert();
     }
 }
    /// <summary>
    /// execute blend-in
    /// </summary>
    private static void _ExecuteBlendIn(CutsceneController cc)
    {
        if (cc.m_ReplRecord.Count == 0)
        {
            return;
        }

        float curAnimTime = cc.m_AnimState.time;

        if (curAnimTime > cc.m_BlendInTime)
        {
            return;
        }

        float t = curAnimTime / cc.m_BlendInTime;

        for (var ie = cc.m_ReplRecord.GetEnumerator(); ie.MoveNext();)
        {
            ReplData  rData = ie.Current.Value;
            Transform extTr = ie.Current.Key.transform;
            for (int idx = 0; idx < rData.m_ExtGOBlendData.Count; ++idx)
            {
                BlendData bdata = rData.m_ExtGOBlendData[idx];
                if (bdata.m_Tr == extTr)
                {
                    XformData origBasedOnCC = rData.m_ExtGOTrDataBasedOnCC;
                    extTr.localPosition = Vector3.Lerp(origBasedOnCC.pos, extTr.localPosition, t);
                    extTr.localRotation = Quaternion.Slerp(origBasedOnCC.rot, extTr.localRotation, t);
                    extTr.localScale    = Vector3.Lerp(origBasedOnCC.scale, extTr.localScale, t);
                }
                else
                {
                    bdata.DoBlend(t);
                }
            }
        }
    }