context: using System;
  using Cinemachine.Utility;
  using UnityEngine;
  using UnityEngine.Serialization;
  namespace Cinemachine
  {
      /// <summary>
      /// A Cinemachine Camera geared towards a 3rd person camera experience.
      /// The camera orbits around its subject with three separate camera rigs defining
      /// rings around the target. Each rig has its own radius, height offset, composer,
      /// and lens settings.
      /// Depending on the camera's position along the spline connecting these three rigs,
      /// these settings are interpolated to give the final camera position and state.
      /// </summary>
      [DocumentationSorting(11, DocumentationSortingAttribute.Level.UserRef)]
      [ExecuteInEditMode, DisallowMultipleComponent]
      [AddComponentMenu("Cinemachine/CinemachineFreeLook")]
      public class CinemachineFreeLook : CinemachineVirtualCameraBase
      {
          /// <summary>Object for the camera children to look at (the aim target)</summary>
          [Tooltip("Object for the camera children to look at (the aim target).")]
          [NoSaveDuringPlay]
          public Transform m_LookAt = null;
          /// <summary>Object for the camera children wants to move with (the body target)</summary>
          [Tooltip("Object for the camera children wants to move with (the body target).")]
          [NoSaveDuringPlay]
          public Transform m_Follow = null;
          /// <summary>If enabled, this lens setting will apply to all three child rigs, otherwise the child rig lens settings will be used</summary>
          [Tooltip("If enabled, this lens setting will apply to all three child rigs, otherwise the child rig lens settings will be used")]
          [FormerlySerializedAs("m_UseCommonLensSetting")]
          public bool m_CommonLens = true;
          /// <summary>Specifies the lens properties of this Virtual Camera.  
          /// This generally mirrors the Unity Camera's lens settings, and will be used to drive 
          /// the Unity camera when the vcam is active</summary>
          [FormerlySerializedAs("m_LensAttributes")]
          [Tooltip("Specifies the lens properties of this Virtual Camera.  This generally mirrors the Unity Camera's lens settings, and will be used to drive the Unity camera when the vcam is active")]
          [LensSettingsProperty]
          public LensSettings m_Lens = LensSettings.Default;
          /// <summary>The Vertical axis.  Value is 0..1.  Chooses how to blend the child rigs</summary>
          [Header("Axis Control")]
          [Tooltip("The Vertical axis.  Value is 0..1.  Chooses how to blend the child rigs")]
          public AxisState m_YAxis = new AxisState(2f, 0.2f, 0.1f, 0.5f, "Mouse Y", false);
          /// <summary>The Horizontal axis.  Value is 0..359.  This is passed on to the rigs' OrbitalTransposer component</summary>
          [Tooltip("The Horizontal axis.  Value is 0..359.  This is passed on to the rigs' OrbitalTransposer component")]
          public AxisState m_XAxis = new AxisState(300f, 0.1f, 0.1f, 0f, "Mouse X", true);
          /// <summary>The definition of Forward.  Camera will follow behind</summary>
          [Tooltip("The definition of Forward.  Camera will follow behind.")]
          public CinemachineOrbitalTransposer.Heading m_Heading = new CinemachineOrbitalTransposer.Heading(
              CinemachineOrbitalTransposer.Heading.HeadingDefinition.TargetForward, 4, 0);
          /// <summary>Controls how automatic recentering of the X axis is accomplished</summary>
          [Tooltip("Controls how automatic recentering of the X axis is accomplished")]
          public CinemachineOrbitalTransposer.Recentering m_RecenterToTargetHeading = new CinemachineOrbitalTransposer.Recentering(false, 1, 2);
          /// <summary>The coordinate space to use when interpreting the offset from the target</summary>
          [Header("Orbits")]
          [Tooltip("The coordinate space to use when interpreting the offset from the target.  This is also used to set the camera's Up vector, which will be maintained when aiming the camera.")]
          public CinemachineOrbitalTransposer.BindingMode m_BindingMode = CinemachineOrbitalTransposer.BindingMode.SimpleFollowWithWorldUp;
          /// <summary></summary>
          [Tooltip("Controls how taut is the line that connects the rigs' orbits, which determines final placement on the Y axis")]
          [Range(0f, 1f)]
          [FormerlySerializedAs("m_SplineTension")]
          public float m_SplineCurvature = 0.2f;
          /// <summary>Defines the height and radius of the Rig orbit</summary>
          [Serializable]
          public struct Orbit
          {
              /// <summary>Height relative to target</summary>
              public float m_Height;
              /// <summary>Radius of orbit</summary>
              public float m_Radius;
              /// <summary>Constructor with specific values</summary>
              public Orbit(float h, float r)
              {
                  m_Height = h;
                  m_Radius = r;
              }
          }
          /// <summary>The radius and height of the three orbiting rigs</summary>
          [Tooltip("The radius and height of the three orbiting rigs.")]
          public Orbit[] m_Orbits = new Orbit[3]
          {
              // These are the default orbits
              new Orbit(4.5f, 1.75f),
              new Orbit(2.5f, 3f),
              new Orbit(0.4f, 1.3f)
          };
          // Legacy support
          [SerializeField][HideInInspector][FormerlySerializedAs("m_HeadingBias")]
          private float m_LegacyHeadingBias = float.MaxValue;
          bool mUseLegacyRigDefinitions = false;
          /// <summary>Enforce bounds for fields, when changed in inspector.</summary>
          protected override void OnValidate()
          {
              base.OnValidate();
              // Upgrade after a legacy deserialize
              if (m_LegacyHeadingBias != float.MaxValue)
              {
                  m_Heading.m_HeadingBias = m_LegacyHeadingBias;
                  m_LegacyHeadingBias = float.MaxValue;
                  m_RecenterToTargetHeading.LegacyUpgrade(
                      ref m_Heading.m_HeadingDefinition, ref m_Heading.m_VelocityFilterStrength);
                  mUseLegacyRigDefinitions = true;
              }
              m_YAxis.Validate();
              m_XAxis.Validate();
              m_RecenterToTargetHeading.Validate();
              m_Lens.Validate();
              InvalidateRigCache();
          }
          /// <summary>Get a child rig</summary>
          /// <param name="i">Rig index.  Can be 0, 1, or 2</param>
          /// <returns>The rig, or null if index is bad.</returns>
          public CinemachineVirtualCamera GetRig(int i)
          {
              UpdateRigCache();
              return (i < 0 || i > 2)? null : m_Rigs[i];
          }
          /// <summary>Names of the 3 child rigs</summary>
          public static string[] RigNames
          {
              get
              {
                  return new string[]
                  {
                      "TopRig",
                      "MiddleRig",
                      "BottomRig"
                  };
              }
          }
          bool mIsDestroyed = false;
          /// <summary>Updates the child rig cache</summary>
          protected override void OnEnable()
          {
              mIsDestroyed = false;
              base.OnEnable();
              InvalidateRigCache();
          }
          /// <summary>Makes sure that the child rigs get destroyed in an undo-firndly manner.
          /// Invalidates the rig cache.</summary>
          protected override void OnDestroy()
          {
              // Make the rigs visible instead of destroying - this is to keep Undo happy
              if (m_Rigs != null)
                  foreach (var rig in m_Rigs)
                      if (rig != null && rig.gameObject != null)
                          rig.gameObject.hideFlags &= ~(HideFlags.HideInHierarchy | HideFlags.HideInInspector);
              mIsDestroyed = true;
              base.OnDestroy();
          }
          /// <summary>Invalidates the rig cache</summary>
          void OnTransformChildrenChanged()
          {
              InvalidateRigCache();
          }
          void Reset()
          {
              DestroyRigs();
          }
          /// <summary>The cacmera state, which will be a blend of the child rig states</summary>
          override public CameraState State
          {
              get
              {
                  return m_State;
              }
          }
          /// <summary>Get the current LookAt target.  Returns parent's LookAt if parent
          /// is non-null and no specific LookAt defined for this camera</summary>
          override public Transform LookAt
          {
              get
              {
                  return ResolveLookAt(m_LookAt);
              }
              set
              {
                  m_LookAt = value;
              }
          }
          /// <summary>Get the current Follow target.  Returns parent's Follow if parent
          /// is non-null and no specific Follow defined for this camera</summary>
          override public Transform Follow
          {
              get
              {
                  return ResolveFollow(m_Follow);
              }
              set
              {
                  m_Follow = value;
              }
          }
          /// <summary>Returns the rig with the greatest weight</summary>
          public override ICinemachineCamera LiveChildOrSelf
          {
              get
              {
                  // Do not update the rig cache here or there will be infinite loop at creation time 
                  if (m_Rigs == null || m_Rigs.Length != 3)
                      return this;
                  if (m_YAxis.Value < 0.33f)
                      return m_Rigs[2];
                  if (m_YAxis.Value > 0.66f)
                      return m_Rigs[0];
                  return m_Rigs[1];
              }
          }
          /// <summary>Check whether the vcam a live child of this camera.  
          /// Returns true if the child is currently contributing actively to the camera state.</summary>
          /// <param name="vcam">The Virtual Camera to check</param>
          /// <returns>True if the vcam is currently actively influencing the state of this vcam</returns>
          public override bool IsLiveChild(ICinemachineCamera vcam)
          {
              // Do not update the rig cache here or there will be infinite loop at creation time 
              if (m_Rigs == null || m_Rigs.Length != 3)
                  return false;
              if (m_YAxis.Value < 0.33f)
                  return vcam == (ICinemachineCamera)m_Rigs[2];
              if (m_YAxis.Value > 0.66f)
                  return vcam == (ICinemachineCamera)m_Rigs[0];
              return vcam == (ICinemachineCamera)m_Rigs[1];
          }
          /// <summary>Remove a Pipeline stage hook callback.
          /// Make sure it is removed from all the children.</summary>
          /// <param name="d">The delegate to remove.</param>
          public override void RemovePostPipelineStageHook(OnPostPipelineStageDelegate d)
          {
              base.RemovePostPipelineStageHook(d);
              UpdateRigCache();
              if (m_Rigs != null)
                  foreach (var vcam in m_Rigs)
                      if (vcam != null)
                          vcam.RemovePostPipelineStageHook(d);
          }
          /// <summary>Called by CinemachineCore at designated update time
          /// so the vcam can position itself and track its targets.  All 3 child rigs are updated,
          /// and a blend calculated, depending on the value of the Y axis.</summary>
          /// <param name="worldUp">Default world Up, set by the CinemachineBrain</param>
          /// <param name="deltaTime">Delta time for time-based effects (ignore if less than 0)</param>
          override public void UpdateCameraState(Vector3 worldUp, float deltaTime)
          {
              //UnityEngine.Profiling.Profiler.BeginSample("CinemachineFreeLook.UpdateCameraState");
              if (!PreviousStateIsValid)
                  deltaTime = -1;
              UpdateRigCache();
              // Reset the base camera state, in case the game object got moved in the editor
              if (deltaTime < 0)
                  m_State = PullStateFromVirtualCamera(worldUp); // Not in gameplay
              // Update the current state by invoking the component pipeline
              m_State = CalculateNewState(worldUp, deltaTime);
              // Push the raw position back to the game object's transform, so it
              // moves along with the camera.  Leave the orientation alone, because it
              // screws up camera dragging when there is a LookAt behaviour.
              if (Follow != null)
              {
                  Vector3 delta = State.RawPosition - transform.position;
                  transform.position = State.RawPosition;
                  m_Rigs[0].transform.position -= delta;
                  m_Rigs[1].transform.position -= delta;
                  m_Rigs[2].transform.position -= delta;
              }
              PreviousStateIsValid = true;
              // Set up for next frame
              bool activeCam = (deltaTime >= 0)|| CinemachineCore.Instance.IsLive(this);
              if (activeCam)
                  m_YAxis.Update(deltaTime);
              PushSettingsToRigs();
              //UnityEngine.Profiling.Profiler.EndSample();
          }
          /// <summary>If we are transitioning from another FreeLook, grab the axis values from it.</summary>
          /// <param name="fromCam">The camera being deactivated.  May be null.</param>
          /// <param name="worldUp">Default world Up, set by the CinemachineBrain</param>
          /// <param name="deltaTime">Delta time for time-based effects (ignore if less than or equal to 0)</param>
          public override void OnTransitionFromCamera(
              ICinemachineCamera fromCam, Vector3 worldUp, float deltaTime)
          {
              base.OnTransitionFromCamera(fromCam, worldUp, deltaTime);
              if ((fromCam != null)&& (fromCam is CinemachineFreeLook))
              {
                  CinemachineFreeLook freeLookFrom = fromCam as CinemachineFreeLook;
                  if (freeLookFrom.Follow == Follow)
                  {
                      m_XAxis.Value = freeLookFrom.m_XAxis.Value;
                      m_YAxis.Value = freeLookFrom.m_YAxis.Value;
                      UpdateCameraState(worldUp, deltaTime);
                  }
              }
          }
          CameraState m_State = CameraState.Default; // Current state this frame
          /// Serialized in order to support copy/paste
          [SerializeField][HideInInspector][NoSaveDuringPlay] private CinemachineVirtualCamera[] m_Rigs = new CinemachineVirtualCamera[3];
          void InvalidateRigCache()
          {
              mOrbitals = null;
          }
          CinemachineOrbitalTransposer[] mOrbitals = null;
          CinemachineBlend mBlendA;
          CinemachineBlend mBlendB;
          /// <summary>
          /// Override component pipeline creation.
          /// This needs to be done by the editor to support Undo.
          /// The override must do exactly the same thing as the CreatePipeline method in this class.
          /// </summary>
          public static CreateRigDelegate CreateRigOverride;
          /// <summary>
          /// Override component pipeline creation.
          /// This needs to be done by the editor to support Undo.
          /// The override must do exactly the same thing as the CreatePipeline method in this class.
          /// </summary>
          public delegate CinemachineVirtualCamera CreateRigDelegate(
              CinemachineFreeLook vcam, string name, CinemachineVirtualCamera copyFrom);
          /// <summary>
          /// Override component pipeline destruction.
          /// This needs to be done by the editor to support Undo.
          /// </summary>
          public static DestroyRigDelegate DestroyRigOverride;
          /// <summary>
          /// Override component pipeline destruction.
          /// This needs to be done by the editor to support Undo.
          /// </summary>
          public delegate void DestroyRigDelegate(GameObject rig);
          private void DestroyRigs()
          {
              CinemachineVirtualCamera[] oldRigs = new CinemachineVirtualCamera[RigNames.Length];
  
gt:             for (int i = 0; i < RigNames.Length; ++i)