From b815dc9aa4dc60bf405c10e426579950570d5436 Mon Sep 17 00:00:00 2001
From: Richard Linden <none@none>
Date: Thu, 10 Mar 2011 20:20:17 -0800
Subject: SOCIAL-530 WIP When double clicking a nearby location I want my
 avatar to walk to that spot Initial mouse-based steering and single click to
 walk

---
 indra/newview/lltoolpie.cpp | 221 ++++++++++++++++++++++++++++++++++++--------
 indra/newview/lltoolpie.h   |  15 ++-
 2 files changed, 195 insertions(+), 41 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp
index 19d7b70101..e539174a4b 100644
--- a/indra/newview/lltoolpie.cpp
+++ b/indra/newview/lltoolpie.cpp
@@ -79,7 +79,7 @@ static ECursorType cursor_from_parcel_media(U8 click_action);
 
 LLToolPie::LLToolPie()
 :	LLTool(std::string("Pie")),
-	mGrabMouseButtonDown( FALSE ),
+	mMouseButtonDown( FALSE ),
 	mMouseOutsideSlop( FALSE ),
 	mClickAction(0),
 	mClickActionBuyEnabled( gSavedSettings.getBOOL("ClickActionBuyEnabled") ),
@@ -99,12 +99,18 @@ BOOL LLToolPie::handleAnyMouseClick(S32 x, S32 y, MASK mask, EClickType clicktyp
 
 BOOL LLToolPie::handleMouseDown(S32 x, S32 y, MASK mask)
 {
+	mMouseOutsideSlop = FALSE;
+	mMouseDownX = x;
+	mMouseDownY = y;
+	mLastYaw = 0.f;
 	//left mouse down always picks transparent
 	mPick = gViewerWindow->pickImmediate(x, y, TRUE);
 	mPick.mKeyMask = mask;
-	mGrabMouseButtonDown = TRUE;
+
+	mDragPick = mPick;
+	mMouseButtonDown = TRUE;
 	
-	pickLeftMouseDownCallback();
+	handleLeftClickPick();
 
 	return TRUE;
 }
@@ -119,7 +125,7 @@ BOOL LLToolPie::handleRightMouseDown(S32 x, S32 y, MASK mask)
 
 	// claim not handled so UI focus stays same
 	
-	pickRightMouseDownCallback();
+	handleRightClickPick();
 	
 	return FALSE;
 }
@@ -136,7 +142,7 @@ BOOL LLToolPie::handleScrollWheel(S32 x, S32 y, S32 clicks)
 }
 
 // True if you selected an object.
-BOOL LLToolPie::pickLeftMouseDownCallback()
+BOOL LLToolPie::handleLeftClickPick()
 {
 	S32 x = mPick.mMousePt.mX;
 	S32 y = mPick.mMousePt.mY;
@@ -319,7 +325,7 @@ BOOL LLToolPie::pickLeftMouseDownCallback()
 	if (!gSavedSettings.getBOOL("LeftClickShowMenu"))
 	{
 		// mouse already released
-		if (!mGrabMouseButtonDown)
+		if (!mMouseButtonDown)
 		{
 			return TRUE;
 		}
@@ -513,7 +519,27 @@ void LLToolPie::selectionPropertiesReceived()
 
 BOOL LLToolPie::handleHover(S32 x, S32 y, MASK mask)
 {
+	if (!mMouseOutsideSlop && mMouseButtonDown)
+	{
+		S32 delta_x = x - mMouseDownX;
+		S32 delta_y = y - mMouseDownY;
+		S32 threshold = gSavedSettings.getS32("DragAndDropDistanceThreshold");
+		if (delta_x * delta_x + delta_y * delta_y > threshold * threshold)
+		{
+			startCameraSteering();
+			mMouseOutsideSlop = TRUE;
+			setMouseCapture(TRUE);
+		}
+	}
+
 	mHoverPick = gViewerWindow->pickImmediate(x, y, FALSE);
+
+	if (mMouseOutsideSlop)
+	{
+		steerCameraWithMouse(x, y);
+		return TRUE;
+	}
+
 	// perform a separate pick that detects transparent objects since they respond to 1-click actions
 	LLPickInfo click_action_pick = gViewerWindow->pickImmediate(x, y, TRUE);
 
@@ -584,37 +610,31 @@ BOOL LLToolPie::handleHover(S32 x, S32 y, MASK mask)
 BOOL LLToolPie::handleMouseUp(S32 x, S32 y, MASK mask)
 {
 	LLViewerObject* obj = mPick.getObject();
+	U8 click_action = final_click_action(obj);
 
-	handleMediaMouseUp();
+	if (hasMouseCapture())
+	{
+		setMouseCapture(FALSE);
+	}
 
-	U8 click_action = final_click_action(obj);
-	if (click_action != CLICK_ACTION_NONE)
+	bool media_handled_click = handleMediaMouseUp() || LLViewerMediaFocus::getInstance()->getFocus();
+	bool mouse_moved = mMouseOutsideSlop;
+	mMouseOutsideSlop = FALSE;
+	mMouseButtonDown = FALSE;
+
+	if (!media_handled_click && click_action == CLICK_ACTION_NONE && !mouse_moved)
 	{
-		switch(click_action)
+		if (gSavedSettings.getBOOL("ClickToWalk")			// click to walk enabled
+			&& !mPick.mPosGlobal.isExactlyZero()			// valid coordinates for pick
+			&& (mPick.mPickType == LLPickInfo::PICK_LAND	// we clicked on land
+				|| mPick.mObjectID.notNull()))				// or on an object
 		{
-			// NOTE: mClickActionBuyEnabled flag enables/disables BUY action but setting cursor to default is okay
-		case CLICK_ACTION_BUY:
-			// NOTE: mClickActionPayEnabled flag enables/disables PAY action but setting cursor to default is okay
-		case CLICK_ACTION_PAY:
-		case CLICK_ACTION_OPEN:
-		case CLICK_ACTION_ZOOM:
-		case CLICK_ACTION_PLAY:
-		case CLICK_ACTION_OPEN_MEDIA:
-			// Because these actions open UI dialogs, we won't change
-			// the cursor again until the next hover and GL pick over
-			// the world.  Keep the cursor an arrow, assuming that 
-			// after the user moves off the UI, they won't be on the
-			// same object anymore.
-			gViewerWindow->setCursor(UI_CURSOR_ARROW);
-			// Make sure the hover-picked object is ignored.
-			//gToolTipView->resetLastHoverObject();
-			break;
-		default:
-			break;
+			handle_go_to();
+			return TRUE;
 		}
 	}
+	gViewerWindow->setCursor(UI_CURSOR_ARROW);
 
-	mGrabMouseButtonDown = FALSE;
 	LLToolMgr::getInstance()->clearTransientTool();
 	gAgentCamera.setLookAt(LOOKAT_TARGET_CONVERSATION, obj); // maybe look at object/person clicked on
 	return LLTool::handleMouseUp(x, y, mask);
@@ -1276,6 +1296,7 @@ void LLToolPie::stopEditing()
 void LLToolPie::onMouseCaptureLost()
 {
 	mMouseOutsideSlop = FALSE;
+	mMouseButtonDown = FALSE;
 	handleMediaMouseUp();
 }
 
@@ -1444,8 +1465,6 @@ bool LLToolPie::handleMediaMouseUp()
 		
 		mMediaMouseCaptureID.setNull();	
 
-		setMouseCapture(FALSE);
-
 		result = true;		
 	}	
 	
@@ -1508,7 +1527,7 @@ static ECursorType cursor_from_parcel_media(U8 click_action)
 
 
 // True if we handled the event.
-BOOL LLToolPie::pickRightMouseDownCallback()
+BOOL LLToolPie::handleRightClickPick()
 {
 	S32 x = mPick.mMousePt.mX;
 	S32 y = mPick.mMousePt.mY;
@@ -1630,10 +1649,136 @@ BOOL LLToolPie::pickRightMouseDownCallback()
 
 void LLToolPie::showVisualContextMenuEffect()
 {
-		// VEFFECT: ShowPie
-		LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_SPHERE, TRUE);
-		effectp->setPositionGlobal(mPick.mPosGlobal);
-		effectp->setColor(LLColor4U(gAgent.getEffectColor()));
-		effectp->setDuration(0.25f);
+	// VEFFECT: ShowPie
+	LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_SPHERE, TRUE);
+	effectp->setPositionGlobal(mPick.mPosGlobal);
+	effectp->setColor(LLColor4U(gAgent.getEffectColor()));
+	effectp->setDuration(0.25f);
+}
+
+
+LLVector3 intersect_ray_with_sphere( const LLVector3& ray_pt, const LLVector3& ray_dir, const LLVector3& sphere_center, F32 sphere_radius)
+{
+	// from http://www.siggraph.org/education/materials/HyperGraph/raytrace/rtinter1.htm
+	LLVector3 sphere_to_ray_start_vec = ray_pt - sphere_center;
+	F32 B = 2.f * ray_dir * sphere_to_ray_start_vec;
+	F32 C = sphere_to_ray_start_vec.lengthSquared() - (sphere_radius * sphere_radius);
+
+	LLVector3 intersection_pt;
+
+	F32 discriminant = B*B - 4.f*C;
+	if (discriminant < 0.f)
+	{
+		// no intersection, compute closest intersection point
+		LLVector3 ray_to_sphere(sphere_to_ray_start_vec * -1.f);
+
+		LLVector3 ray_orthogonal_dir = ray_pt + projected_vec(ray_to_sphere, ray_dir) - sphere_center;
+		ray_orthogonal_dir.normalize();
 
+		intersection_pt = sphere_center + ray_orthogonal_dir * sphere_radius;
+	}
+	else
+	{
+		F32 t0 = (-B - sqrtf(discriminant)) / 2.f;
+		if (t0 > 0.f)
+		{
+			intersection_pt = ray_pt + ray_dir * t0;
+		}
+		else
+		{
+			F32 t1 = (-B + sqrtf(discriminant)) / 2.f;
+			intersection_pt = ray_pt + ray_dir * t1;
+		}
+	}
+
+	return intersection_pt;
+	//LLVector3 ray_pt_to_center = sphere_center - ray_pt;
+	//F32 center_distance = ray_pt_to_center.normVec();
+
+	//F32 dot = ray_dir * ray_pt_to_center;
+
+	//if (dot == 0.f)
+	//{
+	//	return LLVector3::zero;
+	//}
+
+	//// point which ray hits plane centered on sphere origin, facing ray origin
+	//LLVector3 intersection_sphere_plane = ray_pt + (ray_dir * center_distance / dot); 
+	//// vector from sphere origin to the point, normalized to sphere radius
+	//LLVector3 sphere_center_to_intersection = (intersection_sphere_plane - sphere_center) / sphere_radius;
+
+	//F32 dist_squared = sphere_center_to_intersection.magVecSquared();
+	//LLVector3 result;
+
+	//if (dist_squared > 1.f)
+	//{
+	//	result = sphere_center_to_intersection;
+	//	result.normVec();
+	//}
+	//else
+	//{
+	//	result = sphere_center_to_intersection - ray_dir * sqrtf(1.f - dist_squared);
+	//}
+
+	//return sphere_center + (result * sphere_radius);
 }
+
+void LLToolPie::startCameraSteering()
+{
+	mMouseSteerX = mMouseDownX;
+	mMouseSteerY = mMouseDownY;
+}
+
+void LLToolPie::steerCameraWithMouse(S32 x, S32 y)
+{
+	const F32 MIN_ROTATION_RADIUS = 1.f;
+
+	const LLVector3 pick_pos = gAgent.getPosAgentFromGlobal(mDragPick.mPosGlobal);
+	const LLVector3 rotation_center = gAgent.getFrameAgent().getOrigin();
+	const LLVector3 rotation_up_axis(gAgent.getReferenceUpVector());
+
+	LLVector3 pick_offset = pick_pos - rotation_center;
+	F32 up_distance = pick_offset * rotation_up_axis;
+	LLVector3 object_rotation_center = rotation_center + rotation_up_axis * up_distance;
+	F32 pick_distance_from_rotation_center = llclamp(dist_vec(pick_pos, object_rotation_center), MIN_ROTATION_RADIUS, F32_MAX);
+
+	LLVector3 screen_rotation_up_axis = rotation_up_axis - projected_vec(rotation_up_axis, LLViewerCamera::instance().getAtAxis());
+	screen_rotation_up_axis.normalize();
+	LLVector3 screen_rotation_left_axis = screen_rotation_up_axis % LLViewerCamera::instance().getAtAxis();
+
+	LLVector3 mouse_ray = gViewerWindow->mouseDirectionGlobal(x, y);
+	mouse_ray = mouse_ray - projected_vec(mouse_ray, rotation_up_axis);
+	mouse_ray.normalize();
+
+	LLVector3 old_mouse_ray = gViewerWindow->mouseDirectionGlobal(mMouseSteerX, mMouseSteerY);
+	old_mouse_ray = old_mouse_ray - projected_vec(old_mouse_ray, rotation_up_axis);
+	old_mouse_ray.normalize();
+
+	LLVector3 camera_pos = gAgentCamera.getCameraPositionAgent();
+	LLVector3 camera_to_rotation_center = object_rotation_center - camera_pos;
+	LLVector3 adjusted_camera_pos = camera_pos + projected_vec(camera_to_rotation_center, rotation_up_axis);
+	LLVector3 rotation_fwd_axis = LLViewerCamera::instance().getAtAxis() - projected_vec(LLViewerCamera::instance().getAtAxis(), rotation_up_axis);
+	rotation_fwd_axis.normalize();
+	F64 pick_dist = dist_vec(pick_pos, adjusted_camera_pos);
+	LLVector3 mouse_on_sphere = intersect_ray_with_sphere(adjusted_camera_pos + (mouse_ray * pick_dist * 1.1f),
+														-1.f * mouse_ray,
+														object_rotation_center,
+														pick_distance_from_rotation_center);
+	LLVector3 old_mouse_on_sphere = intersect_ray_with_sphere(adjusted_camera_pos + (old_mouse_ray * pick_dist * 1.1f),
+														-1.f * old_mouse_ray,
+														object_rotation_center,
+														pick_distance_from_rotation_center);
+
+
+	LLVector3 rotation_furthest_pt = object_rotation_center + pick_distance_from_rotation_center * rotation_fwd_axis;
+	F32 mouse_lateral_distance = llclamp(((mouse_on_sphere - rotation_furthest_pt) * screen_rotation_left_axis) / pick_distance_from_rotation_center, -1.f, 1.f);
+	F32 old_mouse_lateral_distance = llclamp(((old_mouse_on_sphere - rotation_furthest_pt) * screen_rotation_left_axis) / pick_distance_from_rotation_center, -1.f, 1.f);
+
+	F32 yaw_angle = -1.f * asinf(mouse_lateral_distance);
+	F32 old_yaw_angle = -1.f * asinf(old_mouse_lateral_distance);
+
+	// apply delta
+	gAgent.yaw(yaw_angle - old_yaw_angle);
+	mMouseSteerX = x;
+	mMouseSteerY = y;
+}
\ No newline at end of file
diff --git a/indra/newview/lltoolpie.h b/indra/newview/lltoolpie.h
index 77200a1da4..c46fdd6799 100644
--- a/indra/newview/lltoolpie.h
+++ b/indra/newview/lltoolpie.h
@@ -75,8 +75,8 @@ public:
 	
 private:
 	BOOL outsideSlop		(S32 x, S32 y, S32 start_x, S32 start_y);
-	BOOL pickLeftMouseDownCallback();
-	BOOL pickRightMouseDownCallback();
+	BOOL handleLeftClickPick();
+	BOOL handleRightClickPick();
 	BOOL useClickAction		(MASK mask, LLViewerObject* object,LLViewerObject* parent);
 	
 	void showVisualContextMenuEffect();
@@ -88,12 +88,21 @@ private:
 	BOOL handleTooltipLand(std::string line, std::string tooltip_msg);
 	BOOL handleTooltipObject( LLViewerObject* hover_object, std::string line, std::string tooltip_msg);
 
+	void steerCameraWithMouse(S32 x, S32 y);
+	void startCameraSteering();
+
 private:
-	BOOL				mGrabMouseButtonDown;
+	BOOL				mMouseButtonDown;
 	BOOL				mMouseOutsideSlop;				// for this drag, has mouse moved outside slop region
+	S32					mMouseDownX;
+	S32					mMouseDownY;
+	S32					mMouseSteerX;
+	S32					mMouseSteerY;
+	F32					mLastYaw;
 	LLUUID				mMediaMouseCaptureID;
 	LLPickInfo			mPick;
 	LLPickInfo			mHoverPick;
+	LLPickInfo			mDragPick;
 	LLPointer<LLViewerObject> mClickActionObject;
 	U8					mClickAction;
 	LLSafeHandle<LLObjectSelection> mLeftClickSelection;
-- 
cgit v1.2.3