/indra/newview/llagentcamera.cpp
C++ | 1985 lines | 1411 code | 298 blank | 276 comment | 291 complexity | 2f86ba108ab5e2059d20104bd762e219 MD5 | raw file
Possible License(s): LGPL-2.1
Large files files are truncated, but you can click here to view the full file
- /**
- * @file llagentcamera.cpp
- * @brief LLAgent class implementation
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
- #include "llviewerprecompiledheaders.h"
- #include "llagentcamera.h"
- #include "pipeline.h"
- #include "llagent.h"
- #include "llanimationstates.h"
- #include "llfloatercamera.h"
- #include "llfloaterreg.h"
- #include "llhudmanager.h"
- #include "lljoystickbutton.h"
- #include "llselectmgr.h"
- #include "llsmoothstep.h"
- #include "lltoolmgr.h"
- #include "llviewercamera.h"
- #include "llviewercontrol.h"
- #include "llviewerjoystick.h"
- #include "llviewermenu.h"
- #include "llviewerobjectlist.h"
- #include "llviewerregion.h"
- #include "llviewerwindow.h"
- #include "llvoavatarself.h"
- #include "llwindow.h"
- #include "llworld.h"
- using namespace LLVOAvatarDefines;
- extern LLMenuBarGL* gMenuBarView;
- // Mousewheel camera zoom
- const F32 MIN_ZOOM_FRACTION = 0.25f;
- const F32 INITIAL_ZOOM_FRACTION = 1.f;
- const F32 MAX_ZOOM_FRACTION = 8.f;
- const F32 CAMERA_ZOOM_HALF_LIFE = 0.07f; // seconds
- const F32 FOV_ZOOM_HALF_LIFE = 0.07f; // seconds
- const F32 CAMERA_FOCUS_HALF_LIFE = 0.f;//0.02f;
- const F32 CAMERA_LAG_HALF_LIFE = 0.25f;
- const F32 MIN_CAMERA_LAG = 0.5f;
- const F32 MAX_CAMERA_LAG = 5.f;
- const F32 CAMERA_COLLIDE_EPSILON = 0.1f;
- const F32 MIN_CAMERA_DISTANCE = 0.1f;
- const F32 AVATAR_ZOOM_MIN_X_FACTOR = 0.55f;
- const F32 AVATAR_ZOOM_MIN_Y_FACTOR = 0.7f;
- const F32 AVATAR_ZOOM_MIN_Z_FACTOR = 1.15f;
- const F32 MAX_CAMERA_DISTANCE_FROM_AGENT = 50.f;
- const F32 MAX_CAMERA_SMOOTH_DISTANCE = 50.0f;
- const F32 HEAD_BUFFER_SIZE = 0.3f;
- const F32 CUSTOMIZE_AVATAR_CAMERA_ANIM_SLOP = 0.1f;
- const F32 LAND_MIN_ZOOM = 0.15f;
- const F32 AVATAR_MIN_ZOOM = 0.5f;
- const F32 OBJECT_MIN_ZOOM = 0.02f;
- const F32 APPEARANCE_MIN_ZOOM = 0.39f;
- const F32 APPEARANCE_MAX_ZOOM = 8.f;
- const F32 CUSTOMIZE_AVATAR_CAMERA_DEFAULT_DIST = 3.5f;
- const F32 GROUND_TO_AIR_CAMERA_TRANSITION_TIME = 0.5f;
- const F32 GROUND_TO_AIR_CAMERA_TRANSITION_START_TIME = 0.5f;
- const F32 OBJECT_EXTENTS_PADDING = 0.5f;
- // The agent instance.
- LLAgentCamera gAgentCamera;
- //-----------------------------------------------------------------------------
- // LLAgentCamera()
- //-----------------------------------------------------------------------------
- LLAgentCamera::LLAgentCamera() :
- mInitialized(false),
- mDrawDistance( DEFAULT_FAR_PLANE ),
- mLookAt(NULL),
- mPointAt(NULL),
- mHUDTargetZoom(1.f),
- mHUDCurZoom(1.f),
- mForceMouselook(FALSE),
- mCameraMode( CAMERA_MODE_THIRD_PERSON ),
- mLastCameraMode( CAMERA_MODE_THIRD_PERSON ),
- mCameraPreset(CAMERA_PRESET_REAR_VIEW),
- mCameraAnimating( FALSE ),
- mAnimationCameraStartGlobal(),
- mAnimationFocusStartGlobal(),
- mAnimationTimer(),
- mAnimationDuration(0.33f),
-
- mCameraFOVZoomFactor(0.f),
- mCameraCurrentFOVZoomFactor(0.f),
- mCameraFocusOffset(),
- mCameraFOVDefault(DEFAULT_FIELD_OF_VIEW),
- mCameraCollidePlane(),
- mCurrentCameraDistance(2.f), // meters, set in init()
- mTargetCameraDistance(2.f),
- mCameraZoomFraction(1.f), // deprecated
- mThirdPersonHeadOffset(0.f, 0.f, 1.f),
- mSitCameraEnabled(FALSE),
- mCameraSmoothingLastPositionGlobal(),
- mCameraSmoothingLastPositionAgent(),
- mCameraSmoothingStop(false),
- mCameraUpVector(LLVector3::z_axis), // default is straight up
- mFocusOnAvatar(TRUE),
- mFocusGlobal(),
- mFocusTargetGlobal(),
- mFocusObject(NULL),
- mFocusObjectDist(0.f),
- mFocusObjectOffset(),
- mFocusDotRadius( 0.1f ), // meters
- mTrackFocusObject(TRUE),
- mAtKey(0), // Either 1, 0, or -1... indicates that movement-key is pressed
- mWalkKey(0), // like AtKey, but causes less forward thrust
- mLeftKey(0),
- mUpKey(0),
- mYawKey(0.f),
- mPitchKey(0.f),
- mOrbitLeftKey(0.f),
- mOrbitRightKey(0.f),
- mOrbitUpKey(0.f),
- mOrbitDownKey(0.f),
- mOrbitInKey(0.f),
- mOrbitOutKey(0.f),
- mPanUpKey(0.f),
- mPanDownKey(0.f),
- mPanLeftKey(0.f),
- mPanRightKey(0.f),
- mPanInKey(0.f),
- mPanOutKey(0.f)
- {
- mFollowCam.setMaxCameraDistantFromSubject( MAX_CAMERA_DISTANCE_FROM_AGENT );
- clearGeneralKeys();
- clearOrbitKeys();
- clearPanKeys();
- }
- // Requires gSavedSettings to be initialized.
- //-----------------------------------------------------------------------------
- // init()
- //-----------------------------------------------------------------------------
- void LLAgentCamera::init()
- {
- // *Note: this is where LLViewerCamera::getInstance() used to be constructed.
- mDrawDistance = gSavedSettings.getF32("RenderFarClip");
- LLViewerCamera::getInstance()->setView(DEFAULT_FIELD_OF_VIEW);
- // Leave at 0.1 meters until we have real near clip management
- LLViewerCamera::getInstance()->setNear(0.1f);
- LLViewerCamera::getInstance()->setFar(mDrawDistance); // if you want to change camera settings, do so in camera.h
- LLViewerCamera::getInstance()->setAspect( gViewerWindow->getWorldViewAspectRatio() ); // default, overridden in LLViewerWindow::reshape
- LLViewerCamera::getInstance()->setViewHeightInPixels(768); // default, overridden in LLViewerWindow::reshape
- mCameraFocusOffsetTarget = LLVector4(gSavedSettings.getVector3("CameraOffsetBuild"));
-
- mCameraPreset = (ECameraPreset) gSavedSettings.getU32("CameraPreset");
- mCameraOffsetInitial[CAMERA_PRESET_REAR_VIEW] = gSavedSettings.getControl("CameraOffsetRearView");
- mCameraOffsetInitial[CAMERA_PRESET_FRONT_VIEW] = gSavedSettings.getControl("CameraOffsetFrontView");
- mCameraOffsetInitial[CAMERA_PRESET_GROUP_VIEW] = gSavedSettings.getControl("CameraOffsetGroupView");
- mFocusOffsetInitial[CAMERA_PRESET_REAR_VIEW] = gSavedSettings.getControl("FocusOffsetRearView");
- mFocusOffsetInitial[CAMERA_PRESET_FRONT_VIEW] = gSavedSettings.getControl("FocusOffsetFrontView");
- mFocusOffsetInitial[CAMERA_PRESET_GROUP_VIEW] = gSavedSettings.getControl("FocusOffsetGroupView");
- mCameraCollidePlane.clearVec();
- mCurrentCameraDistance = getCameraOffsetInitial().magVec() * gSavedSettings.getF32("CameraOffsetScale");
- mTargetCameraDistance = mCurrentCameraDistance;
- mCameraZoomFraction = 1.f;
- mTrackFocusObject = gSavedSettings.getBOOL("TrackFocusObject");
- mInitialized = true;
- }
- //-----------------------------------------------------------------------------
- // cleanup()
- //-----------------------------------------------------------------------------
- void LLAgentCamera::cleanup()
- {
- setSitCamera(LLUUID::null);
- if(mLookAt)
- {
- mLookAt->markDead() ;
- mLookAt = NULL;
- }
- if(mPointAt)
- {
- mPointAt->markDead() ;
- mPointAt = NULL;
- }
- setFocusObject(NULL);
- }
- void LLAgentCamera::setAvatarObject(LLVOAvatarSelf* avatar)
- {
- if (!mLookAt)
- {
- mLookAt = (LLHUDEffectLookAt *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_LOOKAT);
- }
- if (!mPointAt)
- {
- mPointAt = (LLHUDEffectPointAt *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINTAT);
- }
-
- if (!mLookAt.isNull())
- {
- mLookAt->setSourceObject(avatar);
- }
- if (!mPointAt.isNull())
- {
- mPointAt->setSourceObject(avatar);
- }
- }
- //-----------------------------------------------------------------------------
- // LLAgent()
- //-----------------------------------------------------------------------------
- LLAgentCamera::~LLAgentCamera()
- {
- cleanup();
- // *Note: this is where LLViewerCamera::getInstance() used to be deleted.
- }
- // Change camera back to third person, stop the autopilot,
- // deselect stuff, etc.
- //-----------------------------------------------------------------------------
- // resetView()
- //-----------------------------------------------------------------------------
- void LLAgentCamera::resetView(BOOL reset_camera, BOOL change_camera)
- {
- if (gAgent.getAutoPilot())
- {
- gAgent.stopAutoPilot(TRUE);
- }
- LLSelectMgr::getInstance()->unhighlightAll();
- // By popular request, keep land selection while walking around. JC
- // LLViewerParcelMgr::getInstance()->deselectLand();
- // force deselect when walking and attachment is selected
- // this is so people don't wig out when their avatar moves without animating
- if (LLSelectMgr::getInstance()->getSelection()->isAttachment())
- {
- LLSelectMgr::getInstance()->deselectAll();
- }
- if (gMenuHolder != NULL)
- {
- // Hide all popup menus
- gMenuHolder->hideMenus();
- }
- if (change_camera && !gSavedSettings.getBOOL("FreezeTime"))
- {
- changeCameraToDefault();
-
- if (LLViewerJoystick::getInstance()->getOverrideCamera())
- {
- handle_toggle_flycam();
- }
- // reset avatar mode from eventual residual motion
- if (LLToolMgr::getInstance()->inBuildMode())
- {
- LLViewerJoystick::getInstance()->moveAvatar(true);
- }
- //Camera Tool is needed for Free Camera Control Mode
- if (!LLFloaterCamera::inFreeCameraMode())
- {
- LLFloaterReg::hideInstance("build");
- // Switch back to basic toolset
- LLToolMgr::getInstance()->setCurrentToolset(gBasicToolset);
- }
-
- gViewerWindow->showCursor();
- }
- if (reset_camera && !gSavedSettings.getBOOL("FreezeTime"))
- {
- if (!gViewerWindow->getLeftMouseDown() && cameraThirdPerson())
- {
- // leaving mouse-steer mode
- LLVector3 agent_at_axis = gAgent.getAtAxis();
- agent_at_axis -= projected_vec(agent_at_axis, gAgent.getReferenceUpVector());
- agent_at_axis.normalize();
- gAgent.resetAxes(lerp(gAgent.getAtAxis(), agent_at_axis, LLCriticalDamp::getInterpolant(0.3f)));
- }
- setFocusOnAvatar(TRUE, ANIMATE);
- mCameraFOVZoomFactor = 0.f;
- }
- mHUDTargetZoom = 1.f;
- }
- // Allow camera to be moved somewhere other than behind avatar.
- //-----------------------------------------------------------------------------
- // unlockView()
- //-----------------------------------------------------------------------------
- void LLAgentCamera::unlockView()
- {
- if (getFocusOnAvatar())
- {
- if (isAgentAvatarValid())
- {
- setFocusGlobal(LLVector3d::zero, gAgentAvatarp->mID);
- }
- setFocusOnAvatar(FALSE, FALSE); // no animation
- }
- }
- //-----------------------------------------------------------------------------
- // slamLookAt()
- //-----------------------------------------------------------------------------
- void LLAgentCamera::slamLookAt(const LLVector3 &look_at)
- {
- LLVector3 look_at_norm = look_at;
- look_at_norm.mV[VZ] = 0.f;
- look_at_norm.normalize();
- gAgent.resetAxes(look_at_norm);
- }
- //-----------------------------------------------------------------------------
- // calcFocusOffset()
- //-----------------------------------------------------------------------------
- LLVector3 LLAgentCamera::calcFocusOffset(LLViewerObject *object, LLVector3 original_focus_point, S32 x, S32 y)
- {
- LLMatrix4 obj_matrix = object->getRenderMatrix();
- LLQuaternion obj_rot = object->getRenderRotation();
- LLVector3 obj_pos = object->getRenderPosition();
- BOOL is_avatar = object->isAvatar();
- // if is avatar - don't do any funk heuristics to position the focal point
- // see DEV-30589
- if (is_avatar)
- {
- return original_focus_point - obj_pos;
- }
-
- 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);
- // 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();
- // 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])
- {
- // then grab it
- longest_object_axis.setVec(obj_matrix.getFwdRow4());
- }
- // is y-axis longest?
- else if (obj_to_cam_ray_proportions.mV[VY] > obj_to_cam_ray_proportions.mV[VZ])
- {
- // then grab it
- longest_object_axis.setVec(obj_matrix.getLeftRow4());
- }
- // otherwise, use z axis
- else
- {
- longest_object_axis.setVec(obj_matrix.getUpRow4());
- }
- // 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;
- 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 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_offset_from_object_center = focus_pt - obj_pos;
- // convert to object-local space
- focus_offset_from_object_center.rotVec(inv_obj_rot);
- // 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++)
- {
- //...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)
- {
- dist_out_of_bounds = llmax(0.f, focus_offset_from_object_center.mV[axis] - (object_extents.mV[axis] * 0.5f));
- }
- else
- {
- dist_out_of_bounds = llmin(0.f, focus_offset_from_object_center.mV[axis] + (object_extents.mV[axis] * 0.5f));
- }
- //...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] = dist_out_of_bounds / camera_to_focus_vec.mV[axis];
- }
- }
- LLVector3 abs_clip_fraction = clip_fraction;
- abs_clip_fraction.abs();
- // 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])
- {
- 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_offset_from_object_center -= clip_fraction.mV[VY] * camera_to_focus_vec;
- }
- else
- {
- focus_offset_from_object_center -= clip_fraction.mV[VZ] * camera_to_focus_vec;
- }
- // convert back to world space
- 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)
- {
- LLVector3 obj_rel = original_focus_point - object->getRenderPosition();
-
- //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_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 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);
- }
-
- focus_offset_from_object_center = obj_rel;
- }
- return focus_offset_from_object_center;
- }
- //-----------------------------------------------------------------------------
- // calcCameraMinDistance()
- //-----------------------------------------------------------------------------
- BOOL LLAgentCamera::calcCameraMinDistance(F32 &obj_min_distance)
- {
- BOOL soft_limit = FALSE; // is the bounding box to be treated literally (volumes) or as an approximation (avatars)
- if (!mFocusObject || mFocusObject->isDead() ||
- mFocusObject->isMesh() ||
- gSavedSettings.getBOOL("DisableCameraConstraints"))
- {
- obj_min_distance = 0.f;
- return TRUE;
- }
- if (mFocusObject->mDrawable.isNull())
- {
- #ifdef LL_RELEASE_FOR_DOWNLOAD
- llwarns << "Focus object with no drawable!" << llendl;
- #else
- mFocusObject->dump();
- llerrs << "Focus object with no drawable!" << llendl;
- #endif
- obj_min_distance = 0.f;
- return TRUE;
- }
-
- LLQuaternion inv_object_rot = ~mFocusObject->getRenderRotation();
- LLVector3 target_offset_origin = mFocusObjectOffset;
- LLVector3 camera_offset_target(getCameraPositionAgent() - gAgent.getPosAgentFromGlobal(mFocusTargetGlobal));
- // convert offsets into object local space
- camera_offset_target.rotVec(inv_object_rot);
- target_offset_origin.rotVec(inv_object_rot);
- // push around object extents based on target offset
- LLVector3 object_extents = mFocusObject->getScale();
- if (mFocusObject->isAvatar())
- {
- // fudge factors that lets you zoom in on avatars a bit more (which don't do FOV zoom)
- object_extents.mV[VX] *= AVATAR_ZOOM_MIN_X_FACTOR;
- object_extents.mV[VY] *= AVATAR_ZOOM_MIN_Y_FACTOR;
- object_extents.mV[VZ] *= AVATAR_ZOOM_MIN_Z_FACTOR;
- soft_limit = TRUE;
- }
- LLVector3 abs_target_offset = target_offset_origin;
- abs_target_offset.abs();
- LLVector3 target_offset_dir = target_offset_origin;
- F32 object_radius = mFocusObject->getVObjRadius();
- BOOL target_outside_object_extents = FALSE;
- for (U32 i = VX; i <= VZ; i++)
- {
- if (abs_target_offset.mV[i] * 2.f > object_extents.mV[i] + OBJECT_EXTENTS_PADDING)
- {
- target_outside_object_extents = TRUE;
- }
- if (camera_offset_target.mV[i] > 0.f)
- {
- object_extents.mV[i] -= target_offset_origin.mV[i] * 2.f;
- }
- else
- {
- object_extents.mV[i] += target_offset_origin.mV[i] * 2.f;
- }
- }
- // don't shrink the object extents so far that the object inverts
- object_extents.clamp(0.001f, F32_MAX);
- // move into first octant
- LLVector3 camera_offset_target_abs_norm = camera_offset_target;
- camera_offset_target_abs_norm.abs();
- // make sure offset is non-zero
- camera_offset_target_abs_norm.clamp(0.001f, F32_MAX);
- camera_offset_target_abs_norm.normalize();
- // find camera position relative to normalized object extents
- LLVector3 camera_offset_target_scaled = camera_offset_target_abs_norm;
- camera_offset_target_scaled.mV[VX] /= object_extents.mV[VX];
- camera_offset_target_scaled.mV[VY] /= object_extents.mV[VY];
- camera_offset_target_scaled.mV[VZ] /= object_extents.mV[VZ];
- if (camera_offset_target_scaled.mV[VX] > camera_offset_target_scaled.mV[VY] &&
- camera_offset_target_scaled.mV[VX] > camera_offset_target_scaled.mV[VZ])
- {
- if (camera_offset_target_abs_norm.mV[VX] < 0.001f)
- {
- obj_min_distance = object_extents.mV[VX] * 0.5f;
- }
- else
- {
- obj_min_distance = object_extents.mV[VX] * 0.5f / camera_offset_target_abs_norm.mV[VX];
- }
- }
- else if (camera_offset_target_scaled.mV[VY] > camera_offset_target_scaled.mV[VZ])
- {
- if (camera_offset_target_abs_norm.mV[VY] < 0.001f)
- {
- obj_min_distance = object_extents.mV[VY] * 0.5f;
- }
- else
- {
- obj_min_distance = object_extents.mV[VY] * 0.5f / camera_offset_target_abs_norm.mV[VY];
- }
- }
- else
- {
- if (camera_offset_target_abs_norm.mV[VZ] < 0.001f)
- {
- obj_min_distance = object_extents.mV[VZ] * 0.5f;
- }
- else
- {
- obj_min_distance = object_extents.mV[VZ] * 0.5f / camera_offset_target_abs_norm.mV[VZ];
- }
- }
- LLVector3 object_split_axis;
- LLVector3 target_offset_scaled = target_offset_origin;
- target_offset_scaled.abs();
- target_offset_scaled.normalize();
- target_offset_scaled.mV[VX] /= object_extents.mV[VX];
- target_offset_scaled.mV[VY] /= object_extents.mV[VY];
- target_offset_scaled.mV[VZ] /= object_extents.mV[VZ];
- if (target_offset_scaled.mV[VX] > target_offset_scaled.mV[VY] &&
- target_offset_scaled.mV[VX] > target_offset_scaled.mV[VZ])
- {
- object_split_axis = LLVector3::x_axis;
- }
- else if (target_offset_scaled.mV[VY] > target_offset_scaled.mV[VZ])
- {
- object_split_axis = LLVector3::y_axis;
- }
- else
- {
- object_split_axis = LLVector3::z_axis;
- }
- LLVector3 camera_offset_object(getCameraPositionAgent() - mFocusObject->getPositionAgent());
- // length projected orthogonal to target offset
- F32 camera_offset_dist = (camera_offset_object - target_offset_dir * (camera_offset_object * target_offset_dir)).magVec();
- // calculate whether the target point would be "visible" if it were outside the bounding box
- // on the opposite of the splitting plane defined by object_split_axis;
- BOOL exterior_target_visible = FALSE;
- if (camera_offset_dist > object_radius)
- {
- // target is visible from camera, so turn off fov zoom
- exterior_target_visible = TRUE;
- }
- F32 camera_offset_clip = camera_offset_object * object_split_axis;
- F32 target_offset_clip = target_offset_dir * object_split_axis;
- // target has moved outside of object extents
- // check to see if camera and target are on same side
- if (target_outside_object_extents)
- {
- if (camera_offset_clip > 0.f && target_offset_clip > 0.f)
- {
- return FALSE;
- }
- else if (camera_offset_clip < 0.f && target_offset_clip < 0.f)
- {
- return FALSE;
- }
- }
- // clamp obj distance to diagonal of 10 by 10 cube
- obj_min_distance = llmin(obj_min_distance, 10.f * F_SQRT3);
- obj_min_distance += LLViewerCamera::getInstance()->getNear() + (soft_limit ? 0.1f : 0.2f);
-
- return TRUE;
- }
- F32 LLAgentCamera::getCameraZoomFraction()
- {
- // 0.f -> camera zoomed all the way out
- // 1.f -> camera zoomed all the way in
- LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection();
- if (selection->getObjectCount() && selection->getSelectType() == SELECT_TYPE_HUD)
- {
- // already [0,1]
- return mHUDTargetZoom;
- }
- else if (mFocusOnAvatar && cameraThirdPerson())
- {
- return clamp_rescale(mCameraZoomFraction, MIN_ZOOM_FRACTION, MAX_ZOOM_FRACTION, 1.f, 0.f);
- }
- else if (cameraCustomizeAvatar())
- {
- F32 distance = (F32)mCameraFocusOffsetTarget.magVec();
- return clamp_rescale(distance, APPEARANCE_MIN_ZOOM, APPEARANCE_MAX_ZOOM, 1.f, 0.f );
- }
- else
- {
- F32 min_zoom;
- const F32 DIST_FUDGE = 16.f; // meters
- F32 max_zoom = llmin(mDrawDistance - DIST_FUDGE,
- LLWorld::getInstance()->getRegionWidthInMeters() - DIST_FUDGE,
- MAX_CAMERA_DISTANCE_FROM_AGENT);
- F32 distance = (F32)mCameraFocusOffsetTarget.magVec();
- if (mFocusObject.notNull())
- {
- if (mFocusObject->isAvatar())
- {
- min_zoom = AVATAR_MIN_ZOOM;
- }
- else
- {
- min_zoom = OBJECT_MIN_ZOOM;
- }
- }
- else
- {
- min_zoom = LAND_MIN_ZOOM;
- }
- return clamp_rescale(distance, min_zoom, max_zoom, 1.f, 0.f);
- }
- }
- void LLAgentCamera::setCameraZoomFraction(F32 fraction)
- {
- // 0.f -> camera zoomed all the way out
- // 1.f -> camera zoomed all the way in
- LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection();
- if (selection->getObjectCount() && selection->getSelectType() == SELECT_TYPE_HUD)
- {
- mHUDTargetZoom = fraction;
- }
- else if (mFocusOnAvatar && cameraThirdPerson())
- {
- mCameraZoomFraction = rescale(fraction, 0.f, 1.f, MAX_ZOOM_FRACTION, MIN_ZOOM_FRACTION);
- }
- else if (cameraCustomizeAvatar())
- {
- LLVector3d camera_offset_dir = mCameraFocusOffsetTarget;
- camera_offset_dir.normalize();
- mCameraFocusOffsetTarget = camera_offset_dir * rescale(fraction, 0.f, 1.f, APPEARANCE_MAX_ZOOM, APPEARANCE_MIN_ZOOM);
- }
- else
- {
- F32 min_zoom = LAND_MIN_ZOOM;
- const F32 DIST_FUDGE = 16.f; // meters
- F32 max_zoom = llmin(mDrawDistance - DIST_FUDGE,
- LLWorld::getInstance()->getRegionWidthInMeters() - DIST_FUDGE,
- MAX_CAMERA_DISTANCE_FROM_AGENT);
- if (mFocusObject.notNull())
- {
- if (mFocusObject.notNull())
- {
- if (mFocusObject->isAvatar())
- {
- min_zoom = AVATAR_MIN_ZOOM;
- }
- else
- {
- min_zoom = OBJECT_MIN_ZOOM;
- }
- }
- }
- LLVector3d camera_offset_dir = mCameraFocusOffsetTarget;
- camera_offset_dir.normalize();
- mCameraFocusOffsetTarget = camera_offset_dir * rescale(fraction, 0.f, 1.f, max_zoom, min_zoom);
- }
- startCameraAnimation();
- }
- //-----------------------------------------------------------------------------
- // cameraOrbitAround()
- //-----------------------------------------------------------------------------
- void LLAgentCamera::cameraOrbitAround(const F32 radians)
- {
- LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection();
- if (selection->getObjectCount() && selection->getSelectType() == SELECT_TYPE_HUD)
- {
- // do nothing for hud selection
- }
- else if (mFocusOnAvatar && (mCameraMode == CAMERA_MODE_THIRD_PERSON || mCameraMode == CAMERA_MODE_FOLLOW))
- {
- gAgent.yaw(radians);
- }
- else
- {
- mCameraFocusOffsetTarget.rotVec(radians, 0.f, 0.f, 1.f);
-
- cameraZoomIn(1.f);
- }
- }
- //-----------------------------------------------------------------------------
- // cameraOrbitOver()
- //-----------------------------------------------------------------------------
- void LLAgentCamera::cameraOrbitOver(const F32 angle)
- {
- LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection();
- if (selection->getObjectCount() && selection->getSelectType() == SELECT_TYPE_HUD)
- {
- // do nothing for hud selection
- }
- else if (mFocusOnAvatar && mCameraMode == CAMERA_MODE_THIRD_PERSON)
- {
- gAgent.pitch(angle);
- }
- else
- {
- LLVector3 camera_offset_unit(mCameraFocusOffsetTarget);
- camera_offset_unit.normalize();
- F32 angle_from_up = acos( camera_offset_unit * gAgent.getReferenceUpVector() );
- LLVector3d left_axis;
- left_axis.setVec(LLViewerCamera::getInstance()->getLeftAxis());
- F32 new_angle = llclamp(angle_from_up - angle, 1.f * DEG_TO_RAD, 179.f * DEG_TO_RAD);
- mCameraFocusOffsetTarget.rotVec(angle_from_up - new_angle, left_axis);
- cameraZoomIn(1.f);
- }
- }
- //-----------------------------------------------------------------------------
- // cameraZoomIn()
- //-----------------------------------------------------------------------------
- void LLAgentCamera::cameraZoomIn(const F32 fraction)
- {
- if (gDisconnected)
- {
- return;
- }
- LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection();
- if (selection->getObjectCount() && selection->getSelectType() == SELECT_TYPE_HUD)
- {
- // just update hud zoom level
- mHUDTargetZoom /= fraction;
- return;
- }
- LLVector3d camera_offset(mCameraFocusOffsetTarget);
- LLVector3d camera_offset_unit(mCameraFocusOffsetTarget);
- F32 min_zoom = LAND_MIN_ZOOM;
- F32 current_distance = (F32)camera_offset_unit.normalize();
- F32 new_distance = current_distance * fraction;
- // Don't move through focus point
- if (mFocusObject)
- {
- LLVector3 camera_offset_dir((F32)camera_offset_unit.mdV[VX], (F32)camera_offset_unit.mdV[VY], (F32)camera_offset_unit.mdV[VZ]);
- if (mFocusObject->isAvatar())
- {
- calcCameraMinDistance(min_zoom);
- }
- else
- {
- min_zoom = OBJECT_MIN_ZOOM;
- }
- }
- new_distance = llmax(new_distance, min_zoom);
- // Don't zoom too far back
- const F32 DIST_FUDGE = 16.f; // meters
- F32 max_distance = llmin(mDrawDistance - DIST_FUDGE,
- LLWorld::getInstance()->getRegionWidthInMeters() - DIST_FUDGE );
- if (new_distance > max_distance)
- {
- new_distance = max_distance;
- /*
- // Unless camera is unlocked
- if (!LLViewerCamera::sDisableCameraConstraints)
- {
- return;
- }
- */
- }
- if(cameraCustomizeAvatar())
- {
- new_distance = llclamp( new_distance, APPEARANCE_MIN_ZOOM, APPEARANCE_MAX_ZOOM );
- }
- mCameraFocusOffsetTarget = new_distance * camera_offset_unit;
- }
- //-----------------------------------------------------------------------------
- // cameraOrbitIn()
- //-----------------------------------------------------------------------------
- void LLAgentCamera::cameraOrbitIn(const F32 meters)
- {
- if (mFocusOnAvatar && mCameraMode == CAMERA_MODE_THIRD_PERSON)
- {
- F32 camera_offset_dist = llmax(0.001f, getCameraOffsetInitial().magVec() * gSavedSettings.getF32("CameraOffsetScale"));
-
- mCameraZoomFraction = (mTargetCameraDistance - meters) / camera_offset_dist;
- if (!gSavedSettings.getBOOL("FreezeTime") && mCameraZoomFraction < MIN_ZOOM_FRACTION && meters > 0.f)
- {
- // No need to animate, camera is already there.
- changeCameraToMouselook(FALSE);
- }
- mCameraZoomFraction = llclamp(mCameraZoomFraction, MIN_ZOOM_FRACTION, MAX_ZOOM_FRACTION);
- }
- else
- {
- LLVector3d camera_offset(mCameraFocusOffsetTarget);
- LLVector3d camera_offset_unit(mCameraFocusOffsetTarget);
- F32 current_distance = (F32)camera_offset_unit.normalize();
- F32 new_distance = current_distance - meters;
- F32 min_zoom = LAND_MIN_ZOOM;
-
- // Don't move through focus point
- if (mFocusObject.notNull())
- {
- if (mFocusObject->isAvatar())
- {
- min_zoom = AVATAR_MIN_ZOOM;
- }
- else
- {
- min_zoom = OBJECT_MIN_ZOOM;
- }
- }
- new_distance = llmax(new_distance, min_zoom);
- // Don't zoom too far back
- const F32 DIST_FUDGE = 16.f; // meters
- F32 max_distance = llmin(mDrawDistance - DIST_FUDGE,
- LLWorld::getInstance()->getRegionWidthInMeters() - DIST_FUDGE );
- if (new_distance > max_distance)
- {
- // Unless camera is unlocked
- if (!gSavedSettings.getBOOL("DisableCameraConstraints"))
- {
- return;
- }
- }
- if( CAMERA_MODE_CUSTOMIZE_AVATAR == getCameraMode() )
- {
- new_distance = llclamp( new_distance, APPEARANCE_MIN_ZOOM, APPEARANCE_MAX_ZOOM );
- }
- // Compute new camera offset
- mCameraFocusOffsetTarget = new_distance * camera_offset_unit;
- cameraZoomIn(1.f);
- }
- }
- //-----------------------------------------------------------------------------
- // cameraPanIn()
- //-----------------------------------------------------------------------------
- void LLAgentCamera::cameraPanIn(F32 meters)
- {
- LLVector3d at_axis;
- at_axis.setVec(LLViewerCamera::getInstance()->getAtAxis());
- mFocusTargetGlobal += meters * at_axis;
- mFocusGlobal = mFocusTargetGlobal;
- // don't enforce zoom constraints as this is the only way for users to get past them easily
- updateFocusOffset();
- // NOTE: panning movements expect the camera to move exactly with the focus target, not animated behind -Nyx
- mCameraSmoothingLastPositionGlobal = calcCameraPositionTargetGlobal();
- }
- //-----------------------------------------------------------------------------
- // cameraPanLeft()
- //-----------------------------------------------------------------------------
- void LLAgentCamera::cameraPanLeft(F32 meters)
- {
- LLVector3d left_axis;
- left_axis.setVec(LLViewerCamera::getInstance()->getLeftAxis());
- mFocusTargetGlobal += meters * left_axis;
- mFocusGlobal = mFocusTargetGlobal;
- // disable smoothing for camera pan, which causes some residents unhappiness
- mCameraSmoothingStop = true;
-
- cameraZoomIn(1.f);
- updateFocusOffset();
- // NOTE: panning movements expect the camera to move exactly with the focus target, not animated behind - Nyx
- mCameraSmoothingLastPositionGlobal = calcCameraPositionTargetGlobal();
- }
- //-----------------------------------------------------------------------------
- // cameraPanUp()
- //-----------------------------------------------------------------------------
- void LLAgentCamera::cameraPanUp(F32 meters)
- {
- LLVector3d up_axis;
- up_axis.setVec(LLViewerCamera::getInstance()->getUpAxis());
- mFocusTargetGlobal += meters * up_axis;
- mFocusGlobal = mFocusTargetGlobal;
- // disable smoothing for camera pan, which causes some residents unhappiness
- mCameraSmoothingStop = true;
- cameraZoomIn(1.f);
- updateFocusOffset();
- // NOTE: panning movements expect the camera to move exactly with the focus target, not animated behind -Nyx
- mCameraSmoothingLastPositionGlobal = calcCameraPositionTargetGlobal();
- }
- //-----------------------------------------------------------------------------
- // updateLookAt()
- //-----------------------------------------------------------------------------
- void LLAgentCamera::updateLookAt(const S32 mouse_x, const S32 mouse_y)
- {
- static LLVector3 last_at_axis;
- if (!isAgentAvatarValid()) return;
- LLQuaternion av_inv_rot = ~gAgentAvatarp->mRoot.getWorldRotation();
- LLVector3 root_at = LLVector3::x_axis * gAgentAvatarp->mRoot.getWorldRotation();
- if ((gViewerWindow->getMouseVelocityStat()->getCurrent() < 0.01f) &&
- (root_at * last_at_axis > 0.95f))
- {
- LLVector3 vel = gAgentAvatarp->getVelocity();
- if (vel.magVecSquared() > 4.f)
- {
- setLookAt(LOOKAT_TARGET_IDLE, gAgentAvatarp, vel * av_inv_rot);
- }
- else
- {
- // *FIX: rotate mframeagent by sit object's rotation?
- LLQuaternion look_rotation = gAgentAvatarp->isSitting() ? gAgentAvatarp->getRenderRotation() : gAgent.getFrameAgent().getQuaternion(); // use camera's current rotation
- LLVector3 look_offset = LLVector3(2.f, 0.f, 0.f) * look_rotation * av_inv_rot;
- setLookAt(LOOKAT_TARGET_IDLE, gAgentAvatarp, look_offset);
- }
- last_at_axis = root_at;
- return;
- }
- last_at_axis = root_at;
-
- if (CAMERA_MODE_CUSTOMIZE_AVATAR == getCameraMode())
- {
- setLookAt(LOOKAT_TARGET_NONE, gAgentAvatarp, LLVector3(-2.f, 0.f, 0.f));
- }
- else
- {
- // Move head based on cursor position
- ELookAtType lookAtType = LOOKAT_TARGET_NONE;
- LLVector3 headLookAxis;
- LLCoordFrame frameCamera = *((LLCoordFrame*)LLViewerCamera::getInstance());
- if (cameraMouselook())
- {
- lookAtType = LOOKAT_TARGET_MOUSELOOK;
- }
- else if (cameraThirdPerson())
- {
- // range from -.5 to .5
- F32 x_from_center =
- ((F32) mouse_x / (F32) gViewerWindow->getWorldViewWidthScaled() ) - 0.5f;
- F32 y_from_center =
- ((F32) mouse_y / (F32) gViewerWindow->getWorldViewHeightScaled() ) - 0.5f;
- frameCamera.yaw( - x_from_center * gSavedSettings.getF32("YawFromMousePosition") * DEG_TO_RAD);
- frameCamera.pitch( - y_from_center * gSavedSettings.getF32("PitchFromMousePosition") * DEG_TO_RAD);
- lookAtType = LOOKAT_TARGET_FREELOOK;
- }
- headLookAxis = frameCamera.getAtAxis();
- // RN: we use world-space offset for mouselook and freelook
- //headLookAxis = headLookAxis * av_inv_rot;
- setLookAt(lookAtType, gAgentAvatarp, headLookAxis);
- }
- }
- //-----------------------------------------------------------------------------
- // updateCamera()
- //-----------------------------------------------------------------------------
- void LLAgentCamera::updateCamera()
- {
- static LLFastTimer::DeclareTimer ftm("Camera");
- LLFastTimer t(ftm);
- // - changed camera_skyward to the new global "mCameraUpVector"
- mCameraUpVector = LLVector3::z_axis;
- //LLVector3 camera_skyward(0.f, 0.f, 1.f);
- U32 camera_mode = mCameraAnimating ? mLastCameraMode : mCameraMode;
- validateFocusObject();
- if (isAgentAvatarValid() &&
- gAgentAvatarp->isSitting() &&
- camera_mode == CAMERA_MODE_MOUSELOOK)
- {
- //changed camera_skyward to the new global "mCameraUpVector"
- mCameraUpVector = mCameraUpVector * gAgentAvatarp->getRenderRotation();
- }
- if (cameraThirdPerson() && mFocusOnAvatar && LLFollowCamMgr::getActiveFollowCamParams())
- {
- changeCameraToFollow();
- }
- //NOTE - this needs to be integrated into a general upVector system here within llAgent.
- if ( camera_mode == CAMERA_MODE_FOLLOW && mFocusOnAvatar )
- {
- mCameraUpVector = mFollowCam.getUpVector();
- }
- if (mSitCameraEnabled)
- {
- if (mSitCameraReferenceObject->isDead())
- {
- setSitCamera(LLUUID::null);
- }
- }
- // Update UI with our camera inputs
- LLFloaterCamera* camera_floater = LLFloaterReg::findTypedInstance<LLFloaterCamera>("camera");
- if (camera_floater)
- {
- camera_floater->mRotate->setToggleState(gAgentCamera.getOrbitRightKey() > 0.f, // left
- gAgentCamera.getOrbitUpKey() > 0.f, // top
- gAgentCamera.getOrbitLeftKey() > 0.f, // right
- gAgentCamera.getOrbitDownKey() > 0.f); // bottom
-
- camera_floater->mTrack->setToggleState(gAgentCamera.getPanLeftKey() > 0.f, // left
- gAgentCamera.getPanUpKey() > 0.f, // top
- gAgentCamera.getPanRightKey() > 0.f, // right
- gAgentCamera.getPanDownKey() > 0.f); // bottom
- }
- // Handle camera movement based on keyboard.
- const F32 ORBIT_OVER_RATE = 90.f * DEG_TO_RAD; // radians per second
- const F32 ORBIT_AROUND_RATE = 90.f * DEG_TO_RAD; // radians per second
- const F32 PAN_RATE = 5.f; // meters per second
- if (gAgentCamera.getOrbitUpKey() || gAgentCamera.getOrbitDownKey())
- {
- F32 input_rate = gAgentCamera.getOrbitUpKey() - gAgentCamera.getOrbitDownKey();
- cameraOrbitOver( input_rate * ORBIT_OVER_RATE / gFPSClamped );
- }
- if (gAgentCamera.getOrbitLeftKey() || gAgentCamera.getOrbitRightKey())
- {
- F32 input_rate = gAgentCamera.getOrbitLeftKey() - gAgentCamera.getOrbitRightKey();
- cameraOrbitAround(input_rate * ORBIT_AROUND_RATE / gFPSClamped);
- }
- if (gAgentCamera.getOrbitInKey() || gAgentCamera.getOrbitOutKey())
- {
- F32 input_rate = gAgentCamera.getOrbitInKey() - gAgentCamera.getOrbitOutKey();
-
- LLVector3d to_focus = gAgent.getPosGlobalFromAgent(LLViewerCamera::getInstance()->getOrigin()) - calcFocusPositionTargetGlobal();
- F32 distance_to_focus = (F32)to_focus.magVec();
- // Move at distance (in meters) meters per second
- cameraOrbitIn( input_rate * distance_to_focus / gFPSClamped );
- }
- if (gAgentCamera.getPanInKey() || gAgentCamera.getPanOutKey())
- {
- F32 input_rate = gAgentCamera.getPanInKey() - gAgentCamera.getPanOutKey();
- cameraPanIn(input_rate * PAN_RATE / gFPSClamped);
- }
- if (gAgentCamera.getPanRightKey() || gAgentCamera.getPanLeftKey())
- {
- F32 input_rate = gAgentCamera.getPanRightKey() - gAgentCamera.getPanLeftKey();
- cameraPanLeft(input_rate * -PAN_RATE / gFPSClamped );
- }
- if (gAgentCamera.getPanUpKey() || gAgentCamera.getPanDownKey())
- {
- F32 input_rate = gAgentCamera.getPanUpKey() - gAgentCamera.getPanDownKey();
- cameraPanUp(input_rate * PAN_RATE / gFPSClamped );
- }
- // Clear camera keyboard keys.
- gAgentCamera.clearOrbitKeys();
- gAgentCamera.clearPanKeys();
- // lerp camera focus offset
- mCameraFocusOffset = lerp(mCameraFocusOffset, mCameraFocusOffsetTarget, LLCriticalDamp::getInterpolant(CAMERA_FOCUS_HALF_LIFE));
- if ( mCameraMode == CAMERA_MODE_FOLLOW )
- {
- if (isAgentAvatarValid())
- {
- //--------------------------------------------------------------------------------
- // this is where the avatar's position and rotation are given to followCam, and
- // where it is updated. All three of its attributes are updated: (1) position,
- // (2) focus, and (3) upvector. They can then be queried elsewhere in llAgent.
- //--------------------------------------------------------------------------------
- // *TODO: use combined rotation of frameagent and sit object
- LLQuaternion avatarRotationForFollowCam = gAgentAvatarp->isSitting() ? gAgentAvatarp->getRenderRotation() : gAgent.getFrameAgent().getQuaternion();
- LLFollowCamParams* current_cam = LLFollowCamMgr::getActiveFollowCamParams();
- if (current_cam)
- {
- mFollowCam.copyParams(*current_cam);
- mFollowCam.setSubjectPositionAndRotation( gAgentAvatarp->getRenderPosition(), avatarRotationForFollowCam );
- mFollowCam.update();
- LLViewerJoystick::getInstance()->setCameraNeedsUpdate(true);
- }
- else
- {
- changeCameraToThirdPerson(TRUE);
- }
- }
- }
- BOOL hit_limit;
- LLVector3d camera_pos_global;
- LLVector3d camera_target_global = calcCameraPositionTargetGlobal(&hit_limit);
- mCameraVirtualPositionAgent = gAgent.getPosAgentFromGlobal(camera_target_global);
- LLVector3d focus_target_global = calcFocusPositionTargetGlobal();
- // perform field of view correction
- mCameraFOVZoomFactor = calcCameraFOVZoomFactor();
- camera_target_global = focus_target_global + (camera_target_global - focus_target_global) * (1.f + mCameraFOVZoomFactor);
- gAgent.setShowAvatar(TRUE); // can see avatar by default
- // Adjust position for animation
- if (mCameraAnimating)
- {
- F32 time = mAnimationTimer.getElapsedTimeF32();
- // yet another instance of critically damped motion, hooray!
- // F32 fraction_of_animation = 1.f - pow(2.f, -time / CAMERA_ZOOM_HALF_LIFE);
- // linear interpolation
- F32 fraction_of_animation = time / mAnimationDuration;
- BOOL isfirstPerson = mCameraMode == CAMERA_MODE_MOUSELOOK;
- BOOL wasfirstPerson = mLastCameraMode == CAMERA_MODE_MOUSELOOK;
- F32 fraction_animation_to_skip;
- if (mAnimationCameraStartGlobal == camera_target_global)
- {
- fraction_animation_to_skip = 0.f;
- }
- else
- {
- LLVector3d cam_delta = mAnimationCameraStartGlobal - camera_target_global;
- fraction_animation_to_skip = HEAD_BUFFER_SIZE / (F32)cam_delta.magVec();
- }
- F32 animation_start_fraction = (wasfirstPerson) ? fraction_animation_to_skip : 0.f;
- F32 animation_finish_fraction = (isfirstPerson) ? (1.f - fraction_animation_to_skip) : 1.f;
-
- if (fraction_of_animation < animation_finish_fraction)
- {
- if (fraction_of_animation < animation_start_fraction || fraction_of_animation > animation_finish_fraction )
- {
- gAgent.setShowAvatar(FALSE);
- }
- // ...adjust position for animation
- F32 smooth_fraction_of_animation = llsmoothstep(0.0f, 1.0f, fraction_of_animation);
- camera_pos_global = lerp(mAnimationCameraStartGlobal, camera_target_global, smooth_fraction_of_animation);
- mFocusGlobal = lerp(mAnimationFocusStartGlobal, focus_target_global, smooth_fraction_of_animation);
- }
- else
- {
- // ...animation complete
- mCameraAnimating = FALSE;
- camera_pos_global = camera_target_global;
- mFocusGlobal = focus_target_global;
- gAgent.endAnimationUpdateUI();
- gAgent.setShowAvatar(TRUE);
- }
- if (isAgentAvatarValid() && (mCameraMode != CAMERA_MODE_MOUSELOOK))
- {
- gAgentAvatarp->updateAttachmentVisibility(mCameraMode);
- }
- }
- else
- {
- camera_pos_global = camera_target_global;
- mFocusGlobal = focus_target_global;
- gAgent.setShowAvatar(TRUE);
- }
- // smoothing
- if (TRUE)
- {
- LLVector3d agent_pos = gAgent.getPositionGlobal();
- LLVector3d camera_pos_agent = camera_pos_global - agent_pos;
- // Sitting on what you're manipulating can cause camera jitter with smoothing.
- // This turns off smoothing while editing. -MG
- bool in_build_mode = LLToolMgr::getInstance()->inBuildMode();
- mCameraSmoothingStop = mCameraSmoothingStop || in_build_mode;
-
- if (cameraThirdPerson() && !mCameraSmoothingStop)
- {
- const F32 SMOOTHING_HALF_LIFE = 0.02f;
-
- F32 smoothing = LLCriticalDamp::getInterpolant(gSavedSettings.getF32("CameraPositionSmoothing") * SMOOTHING_HALF_LIFE, FALSE);
-
- if (!mFocusObject) // we differentiate on avatar mode
- {
- // for avatar-relative focus, we smooth in avatar space -
- // the avatar moves too jerkily w/r/t global space to smooth there.
- LLVector3d delta = camera_pos_agent - mCameraSmoothingLastPositionAgent;
- if (delta.magVec() < MAX_CAMERA_SMOOTH_DISTANCE) // only smooth over short distances please
- {
- camera_pos_agent = lerp(mCameraSmoothingLastPositionAgent, camera_pos_agent, smoothing);
- camera_pos_global = camera_pos_agent + agent_pos;
- }
- }
- else
- {
- LLVector3d delta = camera_pos_global - mCameraSmoothingLastPositionGlobal;
- if (delta.magVec() < MAX_CAMERA_SMOOTH_DISTANCE) // only smooth over short distances please
- {
- camera_pos_global = lerp(mCameraSmoothingLastPositionGlobal, camera_pos_global, smoothing);
- }
- }
- }
-
- mCameraSmoothingLastPositionGlobal = camera_pos_global;
- mCameraSmoothingLastPositionAgent = camera_pos_agent;
- mCameraSmoothingStop = false;
- }
-
- mCameraCurrentFOVZoomFactor = lerp(mCameraCurrentFOVZoomFactor, mCameraFOVZoomFactor, LLCriticalDamp::getInterpolant(FOV_ZOOM_HALF_LIFE));
- // llinfos << "Current FOV Zoom: " << mCameraCurrentFOVZoomFactor << " Target FOV Zoom: " << mCameraFOVZoomFactor << " Object penetration: " << mFocusObjectDist << llendl;
- LLVector3 focus_agent = gAgent.getPosAgentFromGlobal(mFocusGlobal);
-
- mCameraPositionAgent = gAgent.getPosAgentFromGlobal(camera_pos_global);
- // Move the camera
- LLViewerCamera::getInstance()->updateCameraLocation(mCameraPositionAgent, mCameraUpVector, focus_agent);
- //LLViewerCamera::getInstance()->updateCameraLocation(mCameraPositionAgent, camera_skyward, focus_agent);
-
- // Change FOV
- LLViewerCamera::getInstance()->setView(LLViewerCamera::getInstance()->getDefaultFOV() / (1.f + mCameraCurrentFOVZoomFactor));
- // follow camera when in customize mode
- if (cameraCustomizeAvatar())
- {
- setLookAt(LOOKAT_TARGET_FOCUS, NULL, mCameraPositionAgent);
- }
- // update the travel distance stat
- // this isn't directly related to the camera
- // but this seemed like the best place to do this
- LLVector3d global_pos = gAgent.getPositionGlobal();
- if (!gAgent.getLastPositionGlobal().isExactlyZero())
- {
- LLVector3d delta = global_pos - gAgent.getLastPositionGlobal();
- gAgent.setDistanceTraveled(gAgent.getDistanceTraveled() + delta.magVec());
- }
- gAgent.setLastPositionGlobal(global_pos);
-
- if (LLVOAvatar::sVisibleInFirstPerson && isAgentAvatarValid() && !gAgentAvatarp->isSitting() && cameraMouselook())
- {
- LLVector3 head_pos = gAgentAvatarp->mHeadp->getWorldPosition() +
- LLVector3(0.08f, 0.f, 0.05f) * gAgentAvatarp->mHeadp->getWorldRotation() +
- LLVector3(0.1f, 0.f, 0.f) * gAgentAvatarp->mPelvisp->getWorldRotation();
- LLVector3 diff = mCameraPositionAgent - head_pos;
- diff = diff * ~gAgentAvatarp->mRoot.getWorldRotation();
- LLJoint* torso_joint = gAgentAvatarp->mTorsop;
- LLJoint* chest_joint = gAgentAvatarp->mChestp;
- LLVector3 torso_scale = torso_joint->getScale();
- LLVector3 chest_scale = chest_joint->getScale();
- // shorten avatar skeleton to avoid foot interpenetration
- if (!gAgentAvatarp->mInAir)
- {
- LLVector3 chest_offset = LLVector3(0.f, 0.f, chest_joint->getPosition().mV[VZ]) * torso_joint->getWorldRotation();
- F32 z_compensate = llclamp(-diff.mV[VZ], -0.2f, 1.f);
- F32 scale_factor = llclamp(1.f - ((z_compensate * 0.5f) / chest_offset.mV[VZ]), 0.5f, 1.2f);
- torso_joint->setScale(LLVector3(1.f, 1.f, scale_factor));
- LLJoint* neck_joint = gAgentAvatarp->mNeckp;
- LLVector3 neck_offset = LLVector3(0.f, 0.f, neck_joint->getPosition().mV[VZ]) * chest_joint->getWorldRotation();
- scale_factor = llclamp(1.f - ((z_compensate * 0.5f) / neck_offset.mV[VZ]), 0.5f, 1.2f);
- chest_joint->setScale(LLVector3(1.f, 1.f, scale_factor));
- diff.mV[VZ] = 0.f;
- }
- gAgentAvatarp->mPelvisp->setPosition(gAgentAvatarp->mPelvisp->getPosition() + diff);
- gAgentAvatarp->mRoot.updateWorldMatrixChildren();
- for (LLVOAvatar::attachment_map_t::iterator iter = gAgentAvatarp->mAttachmentPoints.begin();
- iter != gAgentAvatarp->mAttachmentPoints.end(); )
- {
- LLVOAvatar::attachment_map_t::iterator curiter = iter++;
- LLViewerJointAttachment* attachment = curiter->second;
- for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
- attachment_iter != attachment->mAttachedObjects.end();
- ++attachment_iter)
- {
- LLViewerObject *attached_object = (*attachment_iter);
- if (attached_object && !attached_object->isDead() && attached_object->mDrawable.notNull())
- {
- // clear any existing "early" movements of attachment
- attached_object->mDrawable->clearState(LLDrawable::EARLY_MOVE);
- gPipeline.updateMoveNormalAsync(attached_object->mDrawable);
- attached_object->updateText();
- }
- }
- }
- torso_joint->setScale(torso_scale);
- chest_joint->setScale(chest_scale);
- }
- }
- void LLAgentCamera::updateLastCamera()
- {
- mLastCameraMode = mCameraMode;
- }
- void LLAgentCamera::updateFocusOffset()
- {
- validateFocusObject();
- if (mFocusObject.notNull())
- {
- LLVector3d obj_pos = gAgent.getPosGlobalFromAgent(mFocusObject->getRenderPosition());
- mFocusObjectOffset.setVec(mFocusTargetGlobal - obj_pos);
- }
- }
- void LLAgentCamera::validateFocusObject()
- {
- if (mFocusObject.notNull() &&
- mFocusObject->isDead())
- {
- mFocusObjectOffset.clearVec();
- clearFocusObject();
- mCamer…
Large files files are truncated, but you can click here to view the full file