summaryrefslogtreecommitdiff
path: root/indra/newview/llagent.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/llagent.cpp')
-rw-r--r--indra/newview/llagent.cpp171
1 files changed, 85 insertions, 86 deletions
diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp
index 9785940ff6..98526c8a57 100644
--- a/indra/newview/llagent.cpp
+++ b/indra/newview/llagent.cpp
@@ -1315,167 +1315,166 @@ LLQuaternion LLAgent::getQuat() const
//-----------------------------------------------------------------------------
// calcFocusOffset()
//-----------------------------------------------------------------------------
-LLVector3 LLAgent::calcFocusOffset(LLViewerObject *object, LLVector3 pos_agent, S32 x, S32 y)
+LLVector3 LLAgent::calcFocusOffset(LLViewerObject *object, LLVector3 original_focus_point, S32 x, S32 y)
{
// calculate offset based on view direction
BOOL is_avatar = object->isAvatar();
- LLMatrix4 obj_matrix = is_avatar ? ((LLVOAvatar*)object)->mPelvisp->getWorldMatrix() : object->getRenderMatrix();
- LLQuaternion obj_rot = is_avatar ? ((LLVOAvatar*)object)->mPelvisp->getWorldRotation() : object->getRenderRotation();
- LLVector3 obj_pos = is_avatar ? ((LLVOAvatar*)object)->mPelvisp->getWorldPosition() : object->getRenderPosition();
- LLQuaternion inv_obj_rot = ~obj_rot;
-
- LLVector3 obj_dir_abs = obj_pos - LLViewerCamera::getInstance()->getOrigin();
- obj_dir_abs.rotVec(inv_obj_rot);
- obj_dir_abs.normalize();
- obj_dir_abs.abs();
-
+ // since the animation system allows the avatars facing and position to deviate from its nominal LLViewerObject/LLDrawable transform
+ // calculate the focus-specific orientation for avatars based off the pelvis joint
+ // NOTE: pelvis no longer good candidate, removed. DEV-30589
+ LLMatrix4 obj_matrix = object->getRenderMatrix();
+ LLQuaternion obj_rot = object->getRenderRotation();
+ LLVector3 obj_pos = object->getRenderPosition();
+ LLQuaternion inv_obj_rot = ~obj_rot; // get inverse of rotation
LLVector3 object_extents = object->getScale();
// make sure they object extents are non-zero
object_extents.clamp(0.001f, F32_MAX);
- LLVector3 object_half_extents = object_extents * 0.5f;
- obj_dir_abs.mV[VX] = obj_dir_abs.mV[VX] / object_extents.mV[VX];
- obj_dir_abs.mV[VY] = obj_dir_abs.mV[VY] / object_extents.mV[VY];
- obj_dir_abs.mV[VZ] = obj_dir_abs.mV[VZ] / object_extents.mV[VZ];
+ // obj_to_cam_ray is unit vector pointing from object center to camera, in the coordinate frame of the object
+ LLVector3 obj_to_cam_ray = obj_pos - LLViewerCamera::getInstance()->getOrigin();
+ obj_to_cam_ray.rotVec(inv_obj_rot);
+ obj_to_cam_ray.normalize();
- LLVector3 normal;
- if (obj_dir_abs.mV[VX] > obj_dir_abs.mV[VY] && obj_dir_abs.mV[VX] > obj_dir_abs.mV[VZ])
+ // obj_to_cam_ray_proportions are the (positive) ratios of
+ // the obj_to_cam_ray x,y,z components with the x,y,z object dimensions.
+ LLVector3 obj_to_cam_ray_proportions;
+ obj_to_cam_ray_proportions.mV[VX] = llabs(obj_to_cam_ray.mV[VX] / object_extents.mV[VX]);
+ obj_to_cam_ray_proportions.mV[VY] = llabs(obj_to_cam_ray.mV[VY] / object_extents.mV[VY]);
+ obj_to_cam_ray_proportions.mV[VZ] = llabs(obj_to_cam_ray.mV[VZ] / object_extents.mV[VZ]);
+
+ // find the largest ratio stored in obj_to_cam_ray_proportions
+ // this corresponds to the object's local axial plane (XY, YZ, XZ) that is *most* facing the camera
+ LLVector3 longest_object_axis;
+ // is x-axis longest?
+ if (obj_to_cam_ray_proportions.mV[VX] > obj_to_cam_ray_proportions.mV[VY]
+ && obj_to_cam_ray_proportions.mV[VX] > obj_to_cam_ray_proportions.mV[VZ])
{
- normal.setVec(obj_matrix.getFwdRow4());
+ // then grab it
+ longest_object_axis.setVec(obj_matrix.getFwdRow4());
}
- else if (obj_dir_abs.mV[VY] > obj_dir_abs.mV[VZ])
+ // is y-axis longest?
+ else if (obj_to_cam_ray_proportions.mV[VY] > obj_to_cam_ray_proportions.mV[VZ])
{
- normal.setVec(obj_matrix.getLeftRow4());
+ // then grab it
+ longest_object_axis.setVec(obj_matrix.getLeftRow4());
}
+ // otherwise, use z axis
else
{
- normal.setVec(obj_matrix.getUpRow4());
+ longest_object_axis.setVec(obj_matrix.getUpRow4());
}
- normal.normalize();
+
+ // Use this axis as the normal to project mouse click on to plane with that normal, at the object center.
+ // This generates a point behind the mouse cursor that is approximately in the middle of the object in
+ // terms of depth.
+ // We do this to allow the camera rotation tool to "tumble" the object by rotating the camera.
+ // If the focus point were the object surface under the mouse, camera rotation would introduce an undesirable
+ // eccentricity to the object orientation
+ LLVector3 focus_plane_normal(longest_object_axis);
+ focus_plane_normal.normalize();
LLVector3d focus_pt_global;
- // RN: should we check return value for valid pick?
- gViewerWindow->mousePointOnPlaneGlobal(focus_pt_global, x, y, gAgent.getPosGlobalFromAgent(obj_pos), normal);
+ gViewerWindow->mousePointOnPlaneGlobal(focus_pt_global, x, y, gAgent.getPosGlobalFromAgent(obj_pos), focus_plane_normal);
LLVector3 focus_pt = gAgent.getPosAgentFromGlobal(focus_pt_global);
- // find vector from camera to focus point in object coordinates
- LLVector3 camera_focus_vec = focus_pt - LLViewerCamera::getInstance()->getOrigin();
- // convert to object-local space
- camera_focus_vec.rotVec(inv_obj_rot);
+
+ // find vector from camera to focus point in object space
+ LLVector3 camera_to_focus_vec = focus_pt - LLViewerCamera::getInstance()->getOrigin();
+ camera_to_focus_vec.rotVec(inv_obj_rot);
// find vector from object origin to focus point in object coordinates
- LLVector3 focus_delta = focus_pt - obj_pos;
+ LLVector3 focus_offset_from_object_center = focus_pt - obj_pos;
// convert to object-local space
- focus_delta.rotVec(inv_obj_rot);
+ focus_offset_from_object_center.rotVec(inv_obj_rot);
- // calculate clip percentage needed to get focus offset back in bounds along the camera_focus axis
+ // We need to project the focus point back into the bounding box of the focused object.
+ // Do this by calculating the XYZ scale factors needed to get focus offset back in bounds along the camera_focus axis
LLVector3 clip_fraction;
+ // for each axis...
for (U32 axis = VX; axis <= VZ; axis++)
{
- F32 clip_amt;
- if (focus_delta.mV[axis] > 0.f)
+ //...calculate distance that focus offset sits outside of bounding box along that axis...
+ //NOTE: dist_out_of_bounds keeps the sign of focus_offset_from_object_center
+ F32 dist_out_of_bounds;
+ if (focus_offset_from_object_center.mV[axis] > 0.f)
{
- clip_amt = llmax(0.f, focus_delta.mV[axis] - object_half_extents.mV[axis]);
+ dist_out_of_bounds = llmax(0.f, focus_offset_from_object_center.mV[axis] - (object_extents.mV[axis] * 0.5f));
}
else
{
- clip_amt = llmin(0.f, focus_delta.mV[axis] + object_half_extents.mV[axis]);
+ dist_out_of_bounds = llmin(0.f, focus_offset_from_object_center.mV[axis] + (object_extents.mV[axis] * 0.5f));
}
- // don't divide by very small nunber
- if (llabs(camera_focus_vec.mV[axis]) < 0.0001f)
+ //...then calculate the scale factor needed to push camera_to_focus_vec back in bounds along current axis
+ if (llabs(camera_to_focus_vec.mV[axis]) < 0.0001f)
{
+ // don't divide by very small number
clip_fraction.mV[axis] = 0.f;
}
else
{
- clip_fraction.mV[axis] = clip_amt / camera_focus_vec.mV[axis];
+ clip_fraction.mV[axis] = dist_out_of_bounds / camera_to_focus_vec.mV[axis];
}
}
LLVector3 abs_clip_fraction = clip_fraction;
abs_clip_fraction.abs();
- // find greatest shrinkage factor and
+ // find axis of focus offset that is *most* outside the bounding box and use that to
// rescale focus offset to inside object extents
- if (abs_clip_fraction.mV[VX] > abs_clip_fraction.mV[VY] &&
- abs_clip_fraction.mV[VX] > abs_clip_fraction.mV[VZ])
+ if (abs_clip_fraction.mV[VX] > abs_clip_fraction.mV[VY]
+ && abs_clip_fraction.mV[VX] > abs_clip_fraction.mV[VZ])
{
- focus_delta -= clip_fraction.mV[VX] * camera_focus_vec;
+ focus_offset_from_object_center -= clip_fraction.mV[VX] * camera_to_focus_vec;
}
else if (abs_clip_fraction.mV[VY] > abs_clip_fraction.mV[VZ])
{
- focus_delta -= clip_fraction.mV[VY] * camera_focus_vec;
+ focus_offset_from_object_center -= clip_fraction.mV[VY] * camera_to_focus_vec;
}
else
{
- focus_delta -= clip_fraction.mV[VZ] * camera_focus_vec;
+ focus_offset_from_object_center -= clip_fraction.mV[VZ] * camera_to_focus_vec;
}
// convert back to world space
- focus_delta.rotVec(obj_rot);
+ focus_offset_from_object_center.rotVec(obj_rot);
+ // now, based on distance of camera from object relative to object size
+ // push the focus point towards the near surface of the object when (relatively) close to the objcet
+ // or keep the focus point in the object middle when (relatively) far
+ // NOTE: leave focus point in middle of avatars, since the behavior you want when alt-zooming on avatars
+ // is almost always "tumble about middle" and not "spin around surface point"
if (!is_avatar)
{
- //unproject relative clicked coordinate from window coordinate using GL
- /*GLint viewport[4];
- GLdouble modelview[16];
- GLdouble projection[16];
- GLfloat winX, winY, winZ;
- GLdouble posX, posY, posZ;
-
- // convert our matrices to something that has a multiply that works
- glh::matrix4f newModel((F32*)LLViewerCamera::getInstance()->getModelview().mMatrix);
- glh::matrix4f tmpObjMat((F32*)obj_matrix.mMatrix);
- newModel *= tmpObjMat;
-
- for(U32 i = 0; i < 16; ++i)
- {
- modelview[i] = newModel.m[i];
- projection[i] = LLViewerCamera::getInstance()->getProjection().mMatrix[i/4][i%4];
- }
- glGetIntegerv( GL_VIEWPORT, viewport );
-
- winX = ((F32)x) * gViewerWindow->getDisplayScale().mV[VX];
- winY = ((F32)y) * gViewerWindow->getDisplayScale().mV[VY];
- glReadPixels( llfloor(winX), llfloor(winY), 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &winZ );
-
- gluUnProject( winX, winY, winZ, modelview, projection, viewport, &posX, &posY, &posZ);*/
-
- LLVector3 obj_rel = pos_agent - object->getRenderPosition();
+ LLVector3 obj_rel = original_focus_point - object->getRenderPosition();
- LLVector3 obj_center = LLVector3(0, 0, 0) * object->getRenderMatrix();
-
//now that we have the object relative position, we should bias toward the center of the object
//based on the distance of the camera to the focus point vs. the distance of the camera to the focus
F32 relDist = llabs(obj_rel * LLViewerCamera::getInstance()->getAtAxis());
- F32 viewDist = dist_vec(obj_center + obj_rel, LLViewerCamera::getInstance()->getOrigin());
+ F32 viewDist = dist_vec(obj_pos + obj_rel, LLViewerCamera::getInstance()->getOrigin());
LLBBox obj_bbox = object->getBoundingBoxAgent();
F32 bias = 0.f;
+ // virtual_camera_pos is the camera position we are simulating by backing the camera off
+ // and adjusting the FOV
LLVector3 virtual_camera_pos = gAgent.getPosAgentFromGlobal(mFocusTargetGlobal + (getCameraPositionGlobal() - mFocusTargetGlobal) / (1.f + mCameraFOVZoomFactor));
- if(obj_bbox.containsPointAgent(virtual_camera_pos))
- {
- // if the camera is inside the object (large, hollow objects, for example)
- // force focus point all the way to destination depth, away from object center
- bias = 1.f;
- }
- else
+ // if the camera is inside the object (large, hollow objects, for example)
+ // leave focus point all the way to destination depth, away from object center
+ if(!obj_bbox.containsPointAgent(virtual_camera_pos))
{
// perform magic number biasing of focus point towards surface vs. planar center
bias = clamp_rescale(relDist/viewDist, 0.1f, 0.7f, 0.0f, 1.0f);
+ obj_rel = lerp(focus_offset_from_object_center, obj_rel, bias);
}
-
- obj_rel = lerp(focus_delta, obj_rel, bias);
-
- return LLVector3(obj_rel);
+
+ focus_offset_from_object_center = obj_rel;
}
- return LLVector3(focus_delta.mV[VX], focus_delta.mV[VY], focus_delta.mV[VZ]);
+ return focus_offset_from_object_center;
}
//-----------------------------------------------------------------------------