/*public void OrbitTargetUpDownNatural( double theta_degrees )
         *      {
         *              float fn = Forward.Val % NaturalUp.Val;
         *              if( ( theta_degrees < 0.0 && fn >= 0.95f ) || ( theta_degrees > 0.0 && fn <= -0.95f ) ) return;
         *
         *              double theta = theta_degrees * Math.PI / 180.0;
         *              Vec3f posreltar = Position.Val - Target.Val;
         *              Vec3f right = Forward.Val ^ NaturalUp.Val;
         *              float dist = (Target.Val - Position.Val).Length;
         *
         *              Properties.DeferPropertyChanged = true;
         *              bIgnoreChanges = true;
         *              Position.Set( Target.Val + Vec3f.Normalize( VecExtensions.RotateVectorAroundAxis( posreltar, right, (float) theta ) ) * dist );
         *              Up.Set( VecExtensions.RotateVectorAroundAxis( Up.Val, right, (float) theta ) );
         *              bIgnoreChanges = false;
         *              Target.Set( Target.Val );
         *              Properties.DeferPropertyChanged = false;
         *      }*/

        public void OrbitTargetUpDown(double theta_degrees, bool clampflips)
        {
            double theta  = theta_degrees * Math.PI / 180.0;
            Quatf  newrot = qrot * Quatf.AxisAngleToQuatf(GetRight(), (float)theta);

            if (clampflips)
            {
                // prevent camera from flipping over!
                Vec3f newup = Vec3f.Normalize(newrot.Rotate(Vec3f.Y));
                float dot   = FMath.PI / 2.0f - Vec3f.AngleBetween(newup, NaturalUp.Val);
                if (dot < 0)
                {
                    Vec3f newforward = Vec3f.Normalize(newrot.Rotate(-Vec3f.Z));
                    Vec3f newright   = newforward ^ newup;
                    float sign       = -Math.Sign(newforward % NaturalUp.Val);
                    newrot = newrot * Quatf.RotAxisAngleToQuatf(newright, dot * sign);
                }
            }

            Set(Target.Val, newrot, dist);
        }