public void Update(RTSceneGizmoCamera sceneGizmoCamera)
        {
            SceneGizmoLookAndFeel lookAndFeel = _sceneGizmo.LookAndFeel;
            Vector2 screenOffset              = lookAndFeel.ScreenOffset;
            Rect    sceneCameraViewRect       = sceneGizmoCamera.SceneCamera.pixelRect;
            Vector2 camPrjSwitchLabelRectSize = lookAndFeel.CalculateMaxPrjSwitchLabelRectSize();
            bool    usesPrjSwitchLabel        = lookAndFeel.IsCamPrjSwitchLabelVisible;
            float   screenSize = SceneGizmoLookAndFeel.ScreenSize;

            if (lookAndFeel.ScreenCorner == SceneGizmoScreenCorner.TopRight)
            {
                sceneGizmoCamera.Camera.pixelRect = new Rect(sceneCameraViewRect.xMax - screenSize + screenOffset.x, sceneCameraViewRect.yMax - screenSize + screenOffset.y, screenSize, screenSize);
            }
            else
            if (lookAndFeel.ScreenCorner == SceneGizmoScreenCorner.TopLeft)
            {
                sceneGizmoCamera.Camera.pixelRect = new Rect(sceneCameraViewRect.xMin + screenOffset.x, sceneCameraViewRect.yMax - screenSize + screenOffset.y, screenSize, screenSize);
            }
            else
            if (lookAndFeel.ScreenCorner == SceneGizmoScreenCorner.BottomRight)
            {
                sceneGizmoCamera.Camera.pixelRect = new Rect(sceneCameraViewRect.xMax - screenSize + screenOffset.x,
                                                             sceneCameraViewRect.yMin + (usesPrjSwitchLabel ? camPrjSwitchLabelRectSize.y + 1.0f : 0.0f) + screenOffset.y, screenSize, screenSize);
            }
            else
            {
                sceneGizmoCamera.Camera.pixelRect = new Rect(sceneCameraViewRect.xMin + screenOffset.x,
                                                             sceneCameraViewRect.yMin + (usesPrjSwitchLabel ? camPrjSwitchLabelRectSize.y + 1.0f : 0.0f) + screenOffset.y, screenSize, screenSize);
            }
        }
        public override void Render(Camera camera)
        {
            SceneGizmoLookAndFeel sgLookAndFeel    = _sceneGizmo.LookAndFeel;
            RTSceneGizmoCamera    sceneGizmoCamera = _sceneGizmo.SceneGizmoCamera;

            _cap.Render(camera);

            if (_axisDesc.IsPositive)
            {
                GizmoLabelMaterial labelMaterial = GizmoLabelMaterial.Get;
                labelMaterial.SetZWriteEnabled(false);
                labelMaterial.SetZTestLessEqual();
                labelMaterial.SetColor(ColorEx.KeepAllButAlpha(sgLookAndFeel.AxesLabelTint, _color.Value.a));
                labelMaterial.SetTexture(_labelTexture);
                labelMaterial.SetPass(0);

                Vector3 gizmoAxis  = _sceneGizmo.Gizmo.Transform.GetAxis3D(_axisDesc);
                Vector3 labelScale = Vector3Ex.FromValue(sgLookAndFeel.GetAxesLabelWorldSize(sceneGizmoCamera.Camera, _cap.Position));
                Vector3 labelPos   = _cap.Position + gizmoAxis * (labelScale.x * 0.5f);

                Vector2 labelScreenPos   = sceneGizmoCamera.Camera.WorldToScreenPoint(labelPos);
                Vector2 midAxisScreenPos = sceneGizmoCamera.Camera.WorldToScreenPoint(_sceneGizmo.SceneGizmoCamera.LookAtPoint);
                Vector2 labelScreenDir   = (labelScreenPos - midAxisScreenPos).normalized;

                float absDotCamLook = Mathf.Abs(Vector3Ex.AbsDot(sceneGizmoCamera.Look, gizmoAxis));
                labelScreenPos = labelScreenPos + Vector2.Scale(labelScreenDir, Vector2Ex.FromValue(sgLookAndFeel.AxisLabelScreenSize)) * absDotCamLook;
                labelPos       = sceneGizmoCamera.Camera.ScreenToWorldPoint(new Vector3(labelScreenPos.x, labelScreenPos.y, (labelPos - sceneGizmoCamera.WorldPosition).magnitude));

                Quaternion labelRotation     = Quaternion.LookRotation(sceneGizmoCamera.Look, sceneGizmoCamera.Up);
                Matrix4x4  labelTransformMtx = Matrix4x4.TRS(labelPos, labelRotation, labelScale);

                Graphics.DrawMeshNow(MeshPool.Get.UnitQuadXY, labelTransformMtx);
            }
        }
        public void OnGUI()
        {
            SceneGizmoLookAndFeel sgLookAndFeel = _sceneGizmo.LookAndFeel;
            Camera gizmoCamera = _sceneGizmo.SceneGizmoCamera.Camera;

            if (sgLookAndFeel.IsCamPrjSwitchLabelVisible)
            {
                if (_sceneGizmo.SceneGizmoCamera.SceneCamera != RTFocusCamera.Get.TargetCamera ||
                    !RTFocusCamera.Get.IsDoingProjectionSwitch)
                {
                    Texture2D labelTexture = gizmoCamera.orthographic ? sgLookAndFeel.CamOrthoModeLabelTexture : sgLookAndFeel.CamPerspModeLabelTexture;
                    GUIEx.PushColor(sgLookAndFeel.CamPrjSwitchLabelTint);

                    Rect drawRect = RectEx.FromTexture2D(labelTexture).PlaceBelowCenterHrz(gizmoCamera.pixelRect).InvertScreenY();
                    drawRect.center = new Vector2(drawRect.center.x, Screen.height - 1 - _labelQuad.Center.y);

                    GUI.DrawTexture(drawRect, labelTexture);
                    GUIEx.PopColor();
                }
                else
                {
                    Texture2D destLabelTexture   = sgLookAndFeel.CamOrthoModeLabelTexture;
                    Texture2D sourceLabelTexture = sgLookAndFeel.CamPerspModeLabelTexture;
                    if (RTFocusCamera.Get.PrjSwitchTransitionType == CameraPrjSwitchTransition.Type.ToPerspective)
                    {
                        destLabelTexture   = sgLookAndFeel.CamPerspModeLabelTexture;
                        sourceLabelTexture = sgLookAndFeel.CamOrthoModeLabelTexture;
                    }

                    AnimationCurve srcAnimCurve  = AnimationCurve.EaseInOut(0.0f, sgLookAndFeel.CamPrjSwitchLabelTint.a, 1.0f, 0.0f);
                    AnimationCurve destAnimCurve = AnimationCurve.EaseInOut(0.0f, 0.0f, 1.0f, sgLookAndFeel.CamPrjSwitchLabelTint.a);

                    float destAlpha = destAnimCurve.Evaluate(RTFocusCamera.Get.PrjSwitchProgress);
                    float srcAlpha  = srcAnimCurve.Evaluate(RTFocusCamera.Get.PrjSwitchProgress);

                    GUIEx.PushColor(ColorEx.KeepAllButAlpha(sgLookAndFeel.CamPrjSwitchLabelTint, srcAlpha));
                    Rect drawRect = RectEx.FromTexture2D(sourceLabelTexture).PlaceBelowCenterHrz(gizmoCamera.pixelRect).InvertScreenY();
                    drawRect.center = new Vector2(drawRect.center.x, Screen.height - 1 - _labelQuad.Center.y);
                    GUI.DrawTexture(drawRect, sourceLabelTexture);
                    GUIEx.PopColor();

                    GUIEx.PushColor(ColorEx.KeepAllButAlpha(sgLookAndFeel.CamPrjSwitchLabelTint, destAlpha));
                    drawRect        = RectEx.FromTexture2D(destLabelTexture).PlaceBelowCenterHrz(gizmoCamera.pixelRect).InvertScreenY();
                    drawRect.center = new Vector2(drawRect.center.x, Screen.height - 1 - _labelQuad.Center.y);
                    GUI.DrawTexture(drawRect, destLabelTexture);
                    GUIEx.PopColor();
                }
            }
        }
        private void UpdateTransform()
        {
            SceneGizmoLookAndFeel sgLookAndFeel = _sceneGizmo.LookAndFeel;
            Camera gizmoCamera = _sceneGizmo.SceneGizmoCamera.Camera;

            Texture2D labelTexture = gizmoCamera.orthographic ? sgLookAndFeel.CamOrthoModeLabelTexture : sgLookAndFeel.CamPerspModeLabelTexture;
            Rect      labelRect    = RectEx.FromTexture2D(labelTexture);

            // Note: Use the maximum texture size to account for textures of different sizes. When
            //       drawing the label, we will keep the original texture size to avoid stretching
            //       but we will place its center at '_labelQuad.Center' to avoid sudden changes in
            //       position when doing projection switches.
            labelRect.size = sgLookAndFeel.CalculateMaxPrjSwitchLabelRectSize();
            labelRect      = labelRect.PlaceBelowCenterHrz(_sceneGizmo.SceneGizmoCamera.Camera.pixelRect);

            _labelQuad.Center = labelRect.center;
            _labelQuad.Size   = labelRect.size;
        }
        private void UpdateColor()
        {
            SceneGizmoLookAndFeel sgLookAndFeel = _sceneGizmo.LookAndFeel;
            Color lookAndFeelColor = sgLookAndFeel.GetAxisCapColor(_axisDesc.Index, _axisDesc.Sign);

            if (_cap.IsHovered)
            {
                lookAndFeelColor = sgLookAndFeel.HoveredColor;
            }
            ColorTransition.State ctState = _colorTransition.TransitionState;

            Vector3 axis      = _sceneGizmo.Gizmo.Transform.GetAxis3D(_axisDesc);
            float   alignment = Vector3Ex.AbsDot(axis, _sceneGizmo.SceneGizmoCamera.Look);

            if (alignment > sgLookAndFeel.AxisCamAlignFadeOutThreshold)
            {
                if (ctState != ColorTransition.State.CompleteFadeOut &&
                    ctState != ColorTransition.State.FadingOut)
                {
                    _colorTransition.DurationInSeconds = sgLookAndFeel.AxisCamAlignFadeOutDuration;
                    _colorTransition.FadeOutColor      = ColorEx.KeepAllButAlpha(lookAndFeelColor, sgLookAndFeel.AxisCamAlignFadeOutAlpha);
                    _colorTransition.BeginFadeOut(true);
                }
            }
            else
            {
                if (ctState != ColorTransition.State.FadingIn &&
                    ctState != ColorTransition.State.CompleteFadeIn &&
                    ctState != ColorTransition.State.Ready)
                {
                    _colorTransition.DurationInSeconds = sgLookAndFeel.AxisCamAlignFadeOutDuration;
                    _colorTransition.FadeInColor       = lookAndFeelColor;
                    _colorTransition.BeginFadeIn(true);
                }
                else
                {
                    _color.Value = lookAndFeelColor;
                }
            }

            _colorTransition.Update(Time.deltaTime);
            _cap.OverrideColor.IsActive = true;
            _cap.OverrideColor.Color    = _color.Value;
        }