// This function selects an ideal viewing distance given a selection bounding box, normal, and padding value
void LLViewerMediaFocus::setCameraZoom(F32 padding_factor)
{
	LLPickInfo& pick = LLToolPie::getInstance()->getPick();

	if(LLSelectMgr::getInstance()->getSelection()->isEmpty())
	{
		pick = mPickInfo;
		setFocusFace(true, pick.getObject(), pick.mObjectFace, mMediaImpl);
	}

	if (!LLSelectMgr::getInstance()->getSelection()->isEmpty())
	{
		gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE);

		LLBBox selection_bbox = LLSelectMgr::getInstance()->getBBoxOfSelection();
		F32 height;
		F32 width;
		F32 depth;
		F32 angle_of_view;
		F32 distance;

		// We need the aspect ratio, and the 3 components of the bbox as height, width, and depth.
		F32 aspect_ratio = getBBoxAspectRatio(selection_bbox, pick.mNormal, &height, &width, &depth);
		F32 camera_aspect = LLViewerCamera::getInstance()->getAspect();

		// We will normally use the side of the volume aligned with the short side of the screen (i.e. the height for 
		// a screen in a landscape aspect ratio), however there is an edge case where the aspect ratio of the object is 
		// more extreme than the screen.  In this case we invert the logic, using the longer component of both the object
		// and the screen.  
		bool invert = (camera_aspect > 1.0f && aspect_ratio > camera_aspect) ||
			(camera_aspect < 1.0f && aspect_ratio < camera_aspect);

		// To calculate the optimum viewing distance we will need the angle of the shorter side of the view rectangle.
		// In portrait mode this is the width, and in landscape it is the height.
		// We then calculate the distance based on the corresponding side of the object bbox (width for portrait, height for landscape)
		// We will add half the depth of the bounding box, as the distance projection uses the center point of the bbox.
		if(camera_aspect < 1.0f || invert)
		{
			angle_of_view = llmax(0.1f, LLViewerCamera::getInstance()->getView() * LLViewerCamera::getInstance()->getAspect());
			distance = width * 0.5 * padding_factor / tan(angle_of_view * 0.5f );
		}
		else
		{
			angle_of_view = llmax(0.1f, LLViewerCamera::getInstance()->getView());
			distance = height * 0.5 * padding_factor / tan(angle_of_view * 0.5f );
		}

		distance += depth * 0.5;

		// Finally animate the camera to this new position and focal point
		gAgentCamera.setCameraPosAndFocusGlobal(LLSelectMgr::getInstance()->getSelectionCenterGlobal() + LLVector3d(pick.mNormal * distance), 
			LLSelectMgr::getInstance()->getSelectionCenterGlobal(), LLSelectMgr::getInstance()->getSelection()->getFirstObject()->mID );
	}
}
// This function selects an ideal viewing distance based on the focused object, pick normal, and padding value
void LLViewerMediaFocus::setCameraZoom(LLViewerObject* object, LLVector3 normal, F32 padding_factor, bool zoom_in_only)
{
	if (object)
	{
		gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE);

		LLBBox bbox = object->getBoundingBoxAgent();
		LLVector3d center = gAgent.getPosGlobalFromAgent(bbox.getCenterAgent());
		F32 height;
		F32 width;
		F32 depth;
		F32 angle_of_view;
		F32 distance;

		// We need the aspect ratio, and the 3 components of the bbox as height, width, and depth.
		F32 aspect_ratio = getBBoxAspectRatio(bbox, normal, &height, &width, &depth);
		F32 camera_aspect = LLViewerCamera::getInstance()->getAspect();
		
		lldebugs << "normal = " << normal << ", aspect_ratio = " << aspect_ratio << ", camera_aspect = " << camera_aspect << llendl;

		// We will normally use the side of the volume aligned with the short side of the screen (i.e. the height for 
		// a screen in a landscape aspect ratio), however there is an edge case where the aspect ratio of the object is 
		// more extreme than the screen.  In this case we invert the logic, using the longer component of both the object
		// and the screen.  
		bool invert = (camera_aspect > 1.0f && aspect_ratio > camera_aspect) ||
			(camera_aspect < 1.0f && aspect_ratio < camera_aspect);

		// To calculate the optimum viewing distance we will need the angle of the shorter side of the view rectangle.
		// In portrait mode this is the width, and in landscape it is the height.
		// We then calculate the distance based on the corresponding side of the object bbox (width for portrait, height for landscape)
		// We will add half the depth of the bounding box, as the distance projection uses the center point of the bbox.
		if(camera_aspect < 1.0f || invert)
		{
			angle_of_view = llmax(0.1f, LLViewerCamera::getInstance()->getView() * LLViewerCamera::getInstance()->getAspect());
			distance = width * 0.5 * padding_factor / tan(angle_of_view * 0.5f );

			lldebugs << "using width (" << width << "), angle_of_view = " << angle_of_view << ", distance = " << distance << llendl;
		}
		else
		{
			angle_of_view = llmax(0.1f, LLViewerCamera::getInstance()->getView());
			distance = height * 0.5 * padding_factor / tan(angle_of_view * 0.5f );

			lldebugs << "using height (" << height << "), angle_of_view = " << angle_of_view << ", distance = " << distance << llendl;
		}

		distance += depth * 0.5;

		// Finally animate the camera to this new position and focal point
		LLVector3d camera_pos, target_pos;
		// The target lookat position is the center of the selection (in global coords)
		target_pos = center;
		// Target look-from (camera) position is "distance" away from the target along the normal 
		LLVector3d pickNormal = LLVector3d(normal);
		pickNormal.normalize();
        camera_pos = target_pos + pickNormal * distance;
        if (pickNormal == LLVector3d::z_axis || pickNormal == LLVector3d::z_axis_neg)
        {
			// If the normal points directly up, the camera will "flip" around.
			// We try to avoid this by adjusting the target camera position a 
			// smidge towards current camera position
			// *NOTE: this solution is not perfect.  All it attempts to solve is the
			// "looking down" problem where the camera flips around when it animates
			// to that position.  You still are not guaranteed to be looking at the
			// media in the correct orientation.  What this solution does is it will
			// put the camera into position keeping as best it can the current 
			// orientation with respect to the face.  In other words, if before zoom
			// the media appears "upside down" from the camera, after zooming it will
			// still be upside down, but at least it will not flip.
            LLVector3d cur_camera_pos = LLVector3d(gAgentCamera.getCameraPositionGlobal());
            LLVector3d delta = (cur_camera_pos - camera_pos);
            F64 len = delta.length();
            delta.normalize();
            // Move 1% of the distance towards original camera location
            camera_pos += 0.01 * len * delta;
        }

		// If we are not allowing zooming out and the old camera position is closer to 
		// the center then the new intended camera position, don't move camera and return
		if (zoom_in_only &&
		    (dist_vec_squared(gAgentCamera.getCameraPositionGlobal(), target_pos) < dist_vec_squared(camera_pos, target_pos)))
		{
			return;
		}

		gAgentCamera.setCameraPosAndFocusGlobal(camera_pos, target_pos, object->getID() );

	}
	else
	{
		// If we have no object, focus back on the avatar.
		gAgentCamera.setFocusOnAvatar(TRUE, ANIMATE);
	}
}