diff --git a/AscentChangelog.txt b/AscentChangelog.txt
index d815846e3..d7c9aff00 100644
--- a/AscentChangelog.txt
+++ b/AscentChangelog.txt
@@ -78,5 +78,4 @@ Build Window:
* Copy/Paste Primitive Parameters buttons
Known issues:
-Online/Total counts in the friends list sometimes go haywire. Not often or by a large margin, but it happens.
-Skin menu doesn't work - On hold until we actually have some skins to show - Ascent will have its own "branded" skin at some point.
\ No newline at end of file
+Online/Total counts in the friends list sometimes go haywire. Not often or by a large margin, but it happens.
\ No newline at end of file
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index f464a5ea0..3ed19931a 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -64,6 +64,7 @@ include_directories(
)
set(viewer_SOURCE_FILES
+ ascentuploadbrowser.cpp
dhparam.cpp
dsaparam.cpp
emerald.cpp
@@ -512,7 +513,7 @@ endif (LINUX)
set(viewer_HEADER_FILES
CMakeLists.txt
ViewerInstall.cmake
-
+ ascentuploadbrowser.h
emerald.h
emeraldboobutils.h
dofloaterhex.h
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 291e08e46..3369bca1b 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -101,7 +101,6 @@
Value
1
-
BroadcastViewerEffects
+ AscentDisableLogoutScreens
+
+ AscentDisableTeleportScreens
+
+ EmeraldUseProperArc
+
+ EmeraldBoobMass
+
+ EmeraldBoobHardness
+
+ EmeraldBreastPhysicsToggle
+
+ EmeraldBreastSportsBra
+
+ EmeraldBoobVelMax
+
+ EmeraldBoobFriction
+
+ EmeraldBoobVelMin
+
+ EmeraldBoobXYInfluence
+
+
+
- EmeraldBoobMass
-
- EmeraldBoobHardness
-
- EmeraldBreastPhysicsToggle
-
- EmeraldBreastSportsBra
-
- EmeraldBoobVelMax
-
- EmeraldBoobFriction
-
- EmeraldBoobVelMin
-
- EmeraldBoobXYInfluence
-
AscentCmdLine
- AscentCmdLineMapToKeepPos
+ AscentMapToKeepPos
- FloaterDickDongsRect
+ FloaterUploadRect
FloaterHexRect
diff --git a/indra/newview/ascentprefssys.cpp b/indra/newview/ascentprefssys.cpp
index 13563d2a5..024a19d0f 100644
--- a/indra/newview/ascentprefssys.cpp
+++ b/indra/newview/ascentprefssys.cpp
@@ -36,11 +36,13 @@
#include "ascentprefssys.h"
#include "llcolorswatch.h"
#include "llvoavatar.h"
+#include "llhudeffectlookat.h"
#include "llagent.h"
#include "llstartup.h"
#include "llviewercontrol.h"
#include "lluictrlfactory.h"
#include "llcombobox.h"
+#include "llradiogroup.h"
#include "llwind.h"
#include "llviewernetwork.h"
#include "pipeline.h"
@@ -86,6 +88,7 @@ private:
BOOL mBroadcastViewerEffects;
BOOL mDisablePointAtAndBeam;
BOOL mPrivateLookAt;
+ BOOL mShowLookAt;
BOOL mRevokePermsOnStandUp;
};
@@ -121,6 +124,10 @@ void LLPrefsAscentSysImpl::onCommitCheckBox(LLUICtrl* ctrl, void* user_data)
self->childDisable("speed_rez_seconds");
}
}
+ else if (ctrl->getControlName() == "ShowLookAt")
+ {
+ LLHUDEffectLookAt::sDebugLookAt = self->childGetValue("show_look_at_check").asBoolean();
+ }
}
void LLPrefsAscentSysImpl::refreshValues()
@@ -155,6 +162,7 @@ void LLPrefsAscentSysImpl::refreshValues()
mBroadcastViewerEffects = gSavedSettings.getBOOL("BroadcastViewerEffects");
mDisablePointAtAndBeam = gSavedSettings.getBOOL("DisablePointAtAndBeam");
mPrivateLookAt = gSavedSettings.getBOOL("PrivateLookAt");
+ mShowLookAt = LLHUDEffectLookAt::sDebugLookAt;
mRevokePermsOnStandUp = gSavedSettings.getBOOL("RevokePermsOnStandUp");
}
@@ -174,33 +182,9 @@ void LLPrefsAscentSysImpl::refresh()
childSetValue("seconds_in_chat_and_ims_check", mSecondsInChatAndIMs);
childSetValue("allow_mu_pose_check", mEnableMUPose);
childSetValue("close_ooc_check", mEnableOOCAutoClose);
- //Show Links
- //Time Format
- //Date Format
- childSetValue("seconds_in_chat_and_ims_check", mEnableOOCAutoClose);
- //Save Performance --------------------------------------------------------------------
- childSetValue("fetch_inventory_on_login_check", mFetchInventoryOnLogin);
- childSetValue("enable_wind", mEnableLLWind);
- childSetValue("enable_clouds", mEnableClouds);
- childSetValue("speed_rez_check", mSpeedRez);
- if (mSpeedRez)
- {
- childEnable("speed_rez_interval");
- childEnable("speed_rez_seconds");
- }
- else
- {
- childDisable("speed_rez_interval");
- childDisable("speed_rez_seconds");
- }
- //Command Line ------------------------------------------------------------------------
-
- //Privacy -----------------------------------------------------------------------------
- childSetValue("broadcast_viewer_effects", mBroadcastViewerEffects);
- childSetValue("disable_point_at_and_beams_check", mDisablePointAtAndBeam);
- childSetValue("private_look_at_check", mPrivateLookAt);
- childSetValue("revoke_perms_on_stand_up_check", mRevokePermsOnStandUp);
-
+ LLRadioGroup* radioLinkOptions = getChild("objects_link");
+ radioLinkOptions->selectNthItem(mLinksForChattingObjects);
+ //childSetValue("objects_link", mLinksForChattingObjects);
std::string format = gSavedSettings.getString("ShortTimeFormat");
if (format.find("%p") == -1)
{
@@ -238,6 +222,31 @@ void LLPrefsAscentSysImpl::refresh()
{
combo->setCurrentByIndex(mDateFormat);
}
+
+ childSetValue("seconds_in_chat_and_ims_check", mEnableOOCAutoClose);
+ //Save Performance --------------------------------------------------------------------
+ childSetValue("fetch_inventory_on_login_check", mFetchInventoryOnLogin);
+ childSetValue("enable_wind", mEnableLLWind);
+ childSetValue("enable_clouds", mEnableClouds);
+ childSetValue("speed_rez_check", mSpeedRez);
+ if (mSpeedRez)
+ {
+ childEnable("speed_rez_interval");
+ childEnable("speed_rez_seconds");
+ }
+ else
+ {
+ childDisable("speed_rez_interval");
+ childDisable("speed_rez_seconds");
+ }
+ //Command Line ------------------------------------------------------------------------
+
+ //Privacy -----------------------------------------------------------------------------
+ childSetValue("broadcast_viewer_effects", mBroadcastViewerEffects);
+ childSetValue("disable_point_at_and_beams_check", mDisablePointAtAndBeam);
+ childSetValue("private_look_at_check", mPrivateLookAt);
+ childSetValue("show_look_at_check", mShowLookAt);
+ childSetValue("revoke_perms_on_stand_up_check", mRevokePermsOnStandUp);
}
void LLPrefsAscentSysImpl::cancel()
@@ -304,7 +313,7 @@ void LLPrefsAscentSysImpl::apply()
gSavedSettings.setBOOL("AscentHideTypingNotification", childGetValue("hide_typing_check"));
gSavedSettings.setBOOL("AscentAllowMUpose", childGetValue("allow_mu_pose_check"));
gSavedSettings.setBOOL("AscentAutoCloseOOC", childGetValue("close_ooc_check"));
- gSavedSettings.setU32("LinksForChattingObjects", childGetValue("objects_link").asInteger());
+ //gSavedSettings.setU32("LinksForChattingObjects", childGetValue("objects_link"). );
LLComboBox* combo = getChild("time_format_combobox");
if (combo) {
@@ -379,15 +388,16 @@ void LLPrefsAscentSysImpl::apply()
gSavedSettings.setString("AscentCmdTeleportToCam", childGetValue("AscentCmdTeleportToCam"));
gSavedSettings.setString("AscentCmdLineKeyToName", childGetValue("AscentCmdLineKeyToName"));
gSavedSettings.setString("AscentCmdLineOfferTp", childGetValue("AscentCmdLineOfferTp"));
- gSavedSettings.setString("AscentCmdLineMapTo", childGetValue("AscentCmdLineMapTo"));
- gSavedSettings.setBOOL("AscentCmdLineMapToKeepPos", childGetValue("AscentCmdLineMapToKeepPos"));
- gSavedSettings.setString("AscentCmdLineTP2", childGetValue("AscentCmdLineTP2"));
+ gSavedSettings.setString("AscentCmdLineMapTo", childGetValue("AscentCmdLineMapTo"));
+ gSavedSettings.setBOOL("AscentMapToKeepPos", childGetValue("AscentMapToKeepPos"));
+ gSavedSettings.setString("AscentCmdLineTP2", childGetValue("AscentCmdLineTP2"));
//Privacy --------------------------------------------------------------------------------
gSavedSettings.setBOOL("BroadcastViewerEffects", childGetValue("broadcast_viewer_effects"));
gSavedSettings.setBOOL("DisablePointAtAndBeam", childGetValue("disable_point_at_and_beams_check"));
gSavedSettings.setBOOL("PrivateLookAt", childGetValue("private_look_at_check"));
+ LLHUDEffectLookAt::sDebugLookAt = childGetValue("show_look_at_check");
gSavedSettings.setBOOL("RevokePermsOnStandUp", childGetValue("revoke_perms_on_stand_up_check"));
refreshValues();
diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp
index 6bb93479f..7eee584f5 100644
--- a/indra/newview/llagent.cpp
+++ b/indra/newview/llagent.cpp
@@ -1,8170 +1,8170 @@
-/**
- * @file llagent.cpp
- * @brief LLAgent class implementation
- *
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2009, Linden Research, Inc.
- *
- * Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
- *
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
- *
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
- *
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
- * $/LicenseInfo$
- */
-
-#include "llviewerprecompiledheaders.h"
-
-#include "stdtypes.h"
-#include "stdenums.h"
-
-#include "llagent.h"
-
-#include "llcamera.h"
-#include "llcoordframe.h"
-#include "indra_constants.h"
-#include "llmath.h"
-#include "llcriticaldamp.h"
-#include "llfocusmgr.h"
-#include "llglheaders.h"
-#include "llparcel.h"
-#include "llpermissions.h"
-#include "llregionhandle.h"
-#include "m3math.h"
-#include "m4math.h"
-#include "message.h"
-#include "llquaternion.h"
-#include "v3math.h"
-#include "v4math.h"
-#include "llsmoothstep.h"
-#include "llsdutil.h"
-//#include "vmath.h"
-
-#include "imageids.h"
-#include "llbox.h"
-#include "llbutton.h"
-#include "llcallingcard.h"
-#include "llchatbar.h"
-#include "llconsole.h"
-#include "lldrawable.h"
-#include "llface.h"
-#include "llfirstuse.h"
-#include "llfloater.h"
-#include "llfloateractivespeakers.h"
-#include "llfloateravatarinfo.h"
-#include "llfloaterbuildoptions.h"
-#include "llfloatercamera.h"
-#include "llfloaterchat.h"
-#include "llfloatercustomize.h"
-#include "llfloaterdirectory.h"
-#include "llfloatergroupinfo.h"
-#include "llfloatergroups.h"
-#include "llfloaterland.h"
-#include "llfloatermap.h"
-#include "llfloatermute.h"
-#include "llfloatersnapshot.h"
-#include "llfloatertools.h"
-#include "llfloaterworldmap.h"
-#include "llgroupmgr.h"
-#include "llhomelocationresponder.h"
-#include "llhudeffectlookat.h"
-#include "llhudmanager.h"
-#include "llinventorymodel.h"
-#include "llinventoryview.h"
-#include "lljoystickbutton.h"
-#include "llmenugl.h"
-#include "llmorphview.h"
-#include "llmoveview.h"
-#include "llnotify.h"
-#include "llquantize.h"
-#include "llsdutil.h"
-#include "llselectmgr.h"
-#include "llsky.h"
-#include "llrendersphere.h"
-#include "llstatusbar.h"
-#include "llstartup.h"
-#include "llimview.h"
-#include "lltexturestats.h"
-#include "lltool.h"
-#include "lltoolcomp.h"
-#include "lltoolfocus.h"
-#include "lltoolgrab.h"
-#include "lltoolmgr.h"
-#include "lltoolpie.h"
-#include "lltoolview.h"
-#include "llui.h" // for make_ui_sound
-#include "llurldispatcher.h"
-#include "llviewercamera.h"
-#include "llviewerinventory.h"
-#include "llviewermediafocus.h"
-#include "llviewermenu.h"
-#include "llviewernetwork.h"
-#include "llviewerobjectlist.h"
-#include "llviewerparcelmgr.h"
-#include "llviewerparceloverlay.h"
-#include "llviewerregion.h"
-#include "llviewerstats.h"
-#include "llviewerwindow.h"
-#include "llviewerdisplay.h"
-#include "llvoavatar.h"
-#include "llvoground.h"
-#include "llvosky.h"
-#include "llwearable.h"
-#include "llwearablelist.h"
-#include "llworld.h"
-#include "llworldmap.h"
-#include "pipeline.h"
-#include "roles_constants.h"
-#include "llviewercontrol.h"
-#include "llappviewer.h"
-#include "llviewerjoystick.h"
-#include "llfollowcam.h"
-//
-#include "llao.h"
-#include "llworldmapmessage.h"
-//
-using namespace LLVOAvatarDefines;
-
-extern LLMenuBarGL* gMenuBarView;
-
-//drone wandering constants
-const F32 MAX_WANDER_TIME = 20.f; // seconds
-const F32 MAX_HEADING_HALF_ERROR = 0.2f; // radians
-const F32 WANDER_MAX_SLEW_RATE = 2.f * DEG_TO_RAD; // radians / frame
-const F32 WANDER_TARGET_MIN_DISTANCE = 10.f; // meters
-
-// Autopilot constants
-const F32 AUTOPILOT_HEADING_HALF_ERROR = 10.f * DEG_TO_RAD; // radians
-const F32 AUTOPILOT_MAX_SLEW_RATE = 1.f * DEG_TO_RAD; // radians / frame
-const F32 AUTOPILOT_STOP_DISTANCE = 2.f; // meters
-const F32 AUTOPILOT_HEIGHT_ADJUST_DISTANCE = 8.f; // meters
-const F32 AUTOPILOT_MIN_TARGET_HEIGHT_OFF_GROUND = 1.f; // meters
-const F32 AUTOPILOT_MAX_TIME_NO_PROGRESS = 1.5f; // seconds
-
-// face editing constants
-const LLVector3d FACE_EDIT_CAMERA_OFFSET(0.4f, -0.05f, 0.07f);
-const LLVector3d FACE_EDIT_TARGET_OFFSET(0.f, 0.f, 0.05f);
-
-// 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 METERS_PER_WHEEL_CLICK = 1.f;
-
-const F32 MAX_TIME_DELTA = 1.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.0f;
-const F32 MIN_CAMERA_DISTANCE = 0.0f;
-const F32 AVATAR_ZOOM_MIN_X_FACTOR = 0.0f;
-const F32 AVATAR_ZOOM_MIN_Y_FACTOR = 0.0f;
-const F32 AVATAR_ZOOM_MIN_Z_FACTOR = 0.0f;
-
-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.2f;
-
-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;
-
-// fidget constants
-const F32 MIN_FIDGET_TIME = 8.f; // seconds
-const F32 MAX_FIDGET_TIME = 20.f; // seconds
-
-const S32 MAX_NUM_CHAT_POSITIONS = 10;
-const F32 GROUND_TO_AIR_CAMERA_TRANSITION_TIME = 0.5f;
-const F32 GROUND_TO_AIR_CAMERA_TRANSITION_START_TIME = 0.5f;
-
-const F32 MAX_VELOCITY_AUTO_LAND_SQUARED = 4.f * 4.f;
-
-const F32 MAX_FOCUS_OFFSET = 20.f;
-
-const F32 OBJECT_EXTENTS_PADDING = 0.5f;
-
-const F32 MIN_RADIUS_ALPHA_SIZZLE = 0.5f;
-
-const F64 CHAT_AGE_FAST_RATE = 3.0;
-
-// The agent instance.
-LLAgent gAgent;
-//
-LLUUID gReSitTargetID;
-LLVector3 gReSitOffset;
-//
-//
-// Statics
-//
-
-//
-// For MapBlockReply funk 'cause I dunno what I'm doing
-BOOL LLAgent::lure_show = FALSE;
-std::string LLAgent::lure_name;
-LLVector3d LLAgent::lure_posglobal;
-U16 LLAgent::lure_global_x;
-U16 LLAgent::lure_global_y;
-int LLAgent::lure_x;
-int LLAgent::lure_y;
-int LLAgent::lure_z;
-std::string LLAgent::lure_maturity;
-
-//
-
-BOOL LLAgent::exlPhantom = 0;
-LLVector3 LLAgent::exlStartMeasurePoint = LLVector3::zero;
-LLVector3 LLAgent::exlEndMeasurePoint = LLVector3::zero;
-
-const F32 LLAgent::TYPING_TIMEOUT_SECS = 5.f;
-
-std::map LLAgent::sTeleportErrorMessages;
-std::map LLAgent::sTeleportProgressMessages;
-
-class LLAgentFriendObserver : public LLFriendObserver
-{
-public:
- LLAgentFriendObserver() {}
- virtual ~LLAgentFriendObserver() {}
- virtual void changed(U32 mask);
-};
-
-void LLAgentFriendObserver::changed(U32 mask)
-{
- // if there's a change we're interested in.
- if((mask & (LLFriendObserver::POWERS)) != 0)
- {
- gAgent.friendsChanged();
- }
-}
-
-// ************************************************************
-// Enabled this definition to compile a 'hacked' viewer that
-// locally believes the end user has godlike powers.
-// #define HACKED_GODLIKE_VIEWER
-// For a toggled version, see viewer.h for the
-// TOGGLE_HACKED_GODLIKE_VIEWER define, instead.
-// ************************************************************
-
-// Constructors and Destructors
-
-// JC - Please try to make this order match the order in the header
-// file. Otherwise it's hard to find variables that aren't initialized.
-//-----------------------------------------------------------------------------
-// LLAgent()
-//-----------------------------------------------------------------------------
-LLAgent::LLAgent() :
- mDrawDistance( DEFAULT_FAR_PLANE ),
-
- mGroupPowers(0),
- mHideGroupTitle(FALSE),
- mGroupID(),
-
- mMapOriginX(0.F),
- mMapOriginY(0.F),
- mMapWidth(0),
- mMapHeight(0),
-
- mLookAt(NULL),
- mPointAt(NULL),
-
- mHUDTargetZoom(1.f),
- mHUDCurZoom(1.f),
- mInitialized(FALSE),
- mNumPendingQueries(0),
- mActiveCacheQueries(NULL),
- mForceMouselook(FALSE),
-
- mDoubleTapRunTimer(),
- mDoubleTapRunMode(DOUBLETAP_NONE),
-
- mbAlwaysRun(false),
- mbRunning(false),
-
- mAgentAccess(gSavedSettings),
- mTeleportState( TELEPORT_NONE ),
- mRegionp(NULL),
-
- mAgentOriginGlobal(),
- mPositionGlobal(),
-
- mDistanceTraveled(0.F),
- mLastPositionGlobal(LLVector3d::zero),
-
- mAvatarObject(NULL),
-
- mRenderState(0),
- mTypingTimer(),
-
- mCameraMode( CAMERA_MODE_THIRD_PERSON ),
- mLastCameraMode( CAMERA_MODE_THIRD_PERSON ),
- mViewsPushed(FALSE),
-
- mCustomAnim(FALSE),
- mShowAvatar(TRUE),
- mCameraAnimating( FALSE ),
- mAnimationCameraStartGlobal(),
- mAnimationFocusStartGlobal(),
- mAnimationTimer(),
- mAnimationDuration(0.33f),
-
- mCameraFOVZoomFactor(0.f),
- mCameraCurrentFOVZoomFactor(0.f),
- mCameraFocusOffset(),
- mCameraFOVDefault(DEFAULT_FIELD_OF_VIEW),
-
- mCameraOffsetDefault(),
- 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),
- mUIOffset(0.f),
-
- mFrameAgent(),
-
- mIsBusy(FALSE),
-
- 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),
-
- 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),
-
- mControlFlags(0x00000000),
- mbFlagsDirty(FALSE),
- mbFlagsNeedReset(FALSE),
-
- mbJump(FALSE),
-
- mAutoPilot(FALSE),
- mAutoPilotFlyOnStop(FALSE),
- mAutoPilotTargetGlobal(),
- mAutoPilotStopDistance(1.f),
- mAutoPilotUseRotation(FALSE),
- mAutoPilotTargetFacing(LLVector3::zero),
- mAutoPilotTargetDist(0.f),
- mAutoPilotNoProgressFrameCount(0),
- mAutoPilotRotationThreshold(0.f),
- mAutoPilotFinishedCallback(NULL),
- mAutoPilotCallbackData(NULL),
-
- mCapabilities(),
-
- mEffectColor(0.f, 1.f, 1.f, 1.f),
-
- mHaveHomePosition(FALSE),
- mHomeRegionHandle( 0 ),
- mNearChatRadius(CHAT_NORMAL_RADIUS / 2.f),
-
- mNextFidgetTime(0.f),
- mCurrentFidget(0),
- mFirstLogin(FALSE),
- mGenderChosen(FALSE),
-
- mAgentWearablesUpdateSerialNum(0),
- mWearablesLoaded(FALSE),
- mTextureCacheQueryID(0),
- mAppearanceSerialNum(0),
- mbTeleportKeepsLookAt(false)
-{
- U32 i;
- for (i = 0; i < TOTAL_CONTROLS; i++)
- {
- mControlsTakenCount[i] = 0;
- mControlsTakenPassedOnCount[i] = 0;
- }
-
- mActiveCacheQueries = new S32[BAKED_NUM_INDICES];
- for (i = 0; i < (U32)BAKED_NUM_INDICES; i++)
- {
- mActiveCacheQueries[i] = 0;
- }
-
- mFollowCam.setMaxCameraDistantFromSubject( MAX_CAMERA_DISTANCE_FROM_AGENT );
-}
-
-// Requires gSavedSettings to be initialized.
-//-----------------------------------------------------------------------------
-// init()
-//-----------------------------------------------------------------------------
-void LLAgent::init()
-{
- mDrawDistance = gSavedSettings.getF32("RenderFarClip");
-
- // *Note: this is where LLViewerCamera::getInstance() used to be constructed.
-
- 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->getDisplayAspectRatio() ); // default, overridden in LLViewerWindow::reshape
- LLViewerCamera::getInstance()->setViewHeightInPixels(768); // default, overridden in LLViewerWindow::reshape
-
- setFlying( gSavedSettings.getBOOL("FlyingAtExit") );
-
- mCameraFocusOffsetTarget = LLVector4(gSavedSettings.getVector3("CameraOffsetBuild"));
- mCameraOffsetDefault = gSavedSettings.getVector3("CameraOffsetDefault");
- mCameraCollidePlane.clearVec();
- mCurrentCameraDistance = mCameraOffsetDefault.magVec() * gSavedSettings.getF32("CameraOffsetScale");
- mTargetCameraDistance = mCurrentCameraDistance;
- mCameraZoomFraction = 1.f;
- mTrackFocusObject = gSavedSettings.getBOOL("TrackFocusObject");
-
-// LLDebugVarMessageBox::show("Camera Lag", &CAMERA_FOCUS_HALF_LIFE, 0.5f, 0.01f);
-
- if (!gSavedSettings.getBOOL("AscentStoreSettingsPerAccount"))
- {
- llinfos << "Using client effect color." << llendl;
- mEffectColor = gSavedSettings.getColor4("EffectColor");
- }
- else
- {
- llinfos << "Using account effect color." << llendl;
- mEffectColor = gSavedPerAccountSettings.getColor4("EffectColor");
- }
-
- mInitialized = TRUE;
-}
-
-//-----------------------------------------------------------------------------
-// cleanup()
-//-----------------------------------------------------------------------------
-void LLAgent::cleanup()
-{
- setSitCamera(LLUUID::null);
- mAvatarObject = NULL;
- if(mLookAt)
- {
- mLookAt->markDead() ;
- mLookAt = NULL;
- }
- if(mPointAt)
- {
- mPointAt->markDead() ;
- mPointAt = NULL;
- }
- mRegionp = NULL;
- setFocusObject(NULL);
-}
-
-//-----------------------------------------------------------------------------
-// LLAgent()
-//-----------------------------------------------------------------------------
-LLAgent::~LLAgent()
-{
- cleanup();
-
- delete [] mActiveCacheQueries;
- mActiveCacheQueries = NULL;
-
- // *Note: this is where LLViewerCamera::getInstance() used to be deleted.
-}
-
-// Change camera back to third person, stop the autopilot,
-// deselect stuff, etc.
-//-----------------------------------------------------------------------------
-// resetView()
-//-----------------------------------------------------------------------------
-void LLAgent::resetView(BOOL reset_camera, BOOL change_camera)
-{
- if (mAutoPilot)
- {
- stopAutoPilot(TRUE);
- }
-
- if (!gNoRender)
- {
- 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();
- }
-
- // 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);
- }
-
- gFloaterTools->close();
-
- gViewerWindow->showCursor();
-
- // Switch back to basic toolset
- LLToolMgr::getInstance()->setCurrentToolset(gBasicToolset);
- }
-
-
- if (reset_camera && !gSavedSettings.getBOOL("FreezeTime"))
- {
- if (!gViewerWindow->getLeftMouseDown() && cameraThirdPerson())
- {
- // leaving mouse-steer mode
- LLVector3 agent_at_axis = getAtAxis();
- agent_at_axis -= projected_vec(agent_at_axis, getReferenceUpVector());
- agent_at_axis.normalize();
- gAgent.resetAxes(lerp(getAtAxis(), agent_at_axis, LLCriticalDamp::getInterpolant(0.3f)));
- }
-
- setFocusOnAvatar(TRUE, ANIMATE);
- }
-
- mHUDTargetZoom = 1.f;
-}
-
-// Handle any actions that need to be performed when the main app gains focus
-// (such as through alt-tab).
-//-----------------------------------------------------------------------------
-// onAppFocusGained()
-//-----------------------------------------------------------------------------
-void LLAgent::onAppFocusGained()
-{
- if (CAMERA_MODE_MOUSELOOK == mCameraMode)
- {
- changeCameraToDefault();
- LLToolMgr::getInstance()->clearSavedTool();
- }
-}
-
-
-void LLAgent::ageChat()
-{
- if (mAvatarObject.notNull())
- {
- // get amount of time since I last chatted
- F64 elapsed_time = (F64)mAvatarObject->mChatTimer.getElapsedTimeF32();
- // add in frame time * 3 (so it ages 4x)
- mAvatarObject->mChatTimer.setAge(elapsed_time + (F64)gFrameDTClamped * (CHAT_AGE_FAST_RATE - 1.0));
- }
-}
-
-// Allow camera to be moved somewhere other than behind avatar.
-//-----------------------------------------------------------------------------
-// unlockView()
-//-----------------------------------------------------------------------------
-void LLAgent::unlockView()
-{
- if (getFocusOnAvatar())
- {
- if (mAvatarObject.notNull())
- {
- setFocusGlobal( LLVector3d::zero, mAvatarObject->mID );
- }
- setFocusOnAvatar(FALSE, FALSE); // no animation
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// moveAt()
-//-----------------------------------------------------------------------------
-void LLAgent::moveAt(S32 direction, bool reset)
-{
- // age chat timer so it fades more quickly when you are intentionally moving
- ageChat();
-
- setKey(direction, mAtKey);
-
- if (direction > 0)
- {
- setControlFlags(AGENT_CONTROL_AT_POS | AGENT_CONTROL_FAST_AT);
- }
- else if (direction < 0)
- {
- setControlFlags(AGENT_CONTROL_AT_NEG | AGENT_CONTROL_FAST_AT);
- }
-
- if (reset)
- {
- resetView();
- }
-}
-
-//-----------------------------------------------------------------------------
-// moveAtNudge()
-//-----------------------------------------------------------------------------
-void LLAgent::moveAtNudge(S32 direction)
-{
- // age chat timer so it fades more quickly when you are intentionally moving
- ageChat();
-
- setKey(direction, mWalkKey);
-
- if (direction > 0)
- {
- setControlFlags(AGENT_CONTROL_NUDGE_AT_POS);
- }
- else if (direction < 0)
- {
- setControlFlags(AGENT_CONTROL_NUDGE_AT_NEG);
- }
-
- resetView();
-}
-
-//-----------------------------------------------------------------------------
-// moveLeft()
-//-----------------------------------------------------------------------------
-void LLAgent::moveLeft(S32 direction)
-{
- // age chat timer so it fades more quickly when you are intentionally moving
- ageChat();
-
- setKey(direction, mLeftKey);
-
- if (direction > 0)
- {
- setControlFlags(AGENT_CONTROL_LEFT_POS | AGENT_CONTROL_FAST_LEFT);
- }
- else if (direction < 0)
- {
- setControlFlags(AGENT_CONTROL_LEFT_NEG | AGENT_CONTROL_FAST_LEFT);
- }
-
- resetView();
-}
-
-//-----------------------------------------------------------------------------
-// moveLeftNudge()
-//-----------------------------------------------------------------------------
-void LLAgent::moveLeftNudge(S32 direction)
-{
- // age chat timer so it fades more quickly when you are intentionally moving
- ageChat();
-
- setKey(direction, mLeftKey);
-
- if (direction > 0)
- {
- setControlFlags(AGENT_CONTROL_NUDGE_LEFT_POS);
- }
- else if (direction < 0)
- {
- setControlFlags(AGENT_CONTROL_NUDGE_LEFT_NEG);
- }
-
- resetView();
-}
-
-//-----------------------------------------------------------------------------
-// moveUp()
-//-----------------------------------------------------------------------------
-void LLAgent::moveUp(S32 direction)
-{
- // age chat timer so it fades more quickly when you are intentionally moving
- ageChat();
-
- setKey(direction, mUpKey);
-
- if (direction > 0)
- {
- setControlFlags(AGENT_CONTROL_UP_POS | AGENT_CONTROL_FAST_UP);
- }
- else if (direction < 0)
- {
- setControlFlags(AGENT_CONTROL_UP_NEG | AGENT_CONTROL_FAST_UP);
- }
-
- resetView();
-}
-
-//-----------------------------------------------------------------------------
-// moveYaw()
-//-----------------------------------------------------------------------------
-void LLAgent::moveYaw(F32 mag, bool reset_view)
-{
- mYawKey = mag;
-
- if (mag > 0)
- {
- setControlFlags(AGENT_CONTROL_YAW_POS);
- }
- else if (mag < 0)
- {
- setControlFlags(AGENT_CONTROL_YAW_NEG);
- }
-
- if (reset_view)
- {
- resetView();
- }
-}
-
-//-----------------------------------------------------------------------------
-// movePitch()
-//-----------------------------------------------------------------------------
-void LLAgent::movePitch(S32 direction)
-{
- setKey(direction, mPitchKey);
-
- if (direction > 0)
- {
- setControlFlags(AGENT_CONTROL_PITCH_POS );
- }
- else if (direction < 0)
- {
- setControlFlags(AGENT_CONTROL_PITCH_NEG);
- }
-}
-
-
-// Does this parcel allow you to fly?
-BOOL LLAgent::canFly()
-{
- if (isGodlike()) return TRUE;
-
- //
- if(gSavedSettings.getBOOL("AlwaysAllowFly")) return TRUE;
- //
-
- LLViewerRegion* regionp = getRegion();
- if (regionp && regionp->getBlockFly()) return FALSE;
-
- LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
- if (!parcel) return FALSE;
-
- // Allow owners to fly on their own land.
- if (LLViewerParcelMgr::isParcelOwnedByAgent(parcel, GP_LAND_ALLOW_FLY))
- {
- return TRUE;
- }
-
- return parcel->getAllowFly();
-}
-
-// Better Set Phantom options ~Charbl
-void LLAgent::setPhantom(BOOL phantom)
-{
- exlPhantom = phantom;
-}
-
-BOOL LLAgent::getPhantom()
-{
- return exlPhantom;
-}
-//
-
-//-----------------------------------------------------------------------------
-// setFlying()
-//-----------------------------------------------------------------------------
-void LLAgent::setFlying(BOOL fly)
-{
- if (mAvatarObject.notNull())
- {
- if(mAvatarObject->mSignaledAnimations.find(ANIM_AGENT_STANDUP) != mAvatarObject->mSignaledAnimations.end())
- {
- return;
- }
-
- // don't allow taking off while sitting
- if (fly && mAvatarObject->mIsSitting)
- {
- return;
- }
- }
-
- if (fly)
- {
- BOOL was_flying = getFlying();
- if (!canFly() && !was_flying)
- {
- // parcel doesn't let you start fly
- // gods can always fly
- // and it's OK if you're already flying
- make_ui_sound("UISndBadKeystroke");
- return;
- }
- if( !was_flying )
- {
- LLViewerStats::getInstance()->incStat(LLViewerStats::ST_FLY_COUNT);
- }
- setControlFlags(AGENT_CONTROL_FLY);
- gSavedSettings.setBOOL("FlyBtnState", TRUE);
- }
- else
- {
- clearControlFlags(AGENT_CONTROL_FLY);
- gSavedSettings.setBOOL("FlyBtnState", FALSE);
- }
- mbFlagsDirty = TRUE;
-}
-
-
-// UI based mechanism of setting fly state
-//-----------------------------------------------------------------------------
-// toggleFlying()
-//-----------------------------------------------------------------------------
-void LLAgent::toggleFlying()
-{
- BOOL fly = !(mControlFlags & AGENT_CONTROL_FLY);
-
- setFlying( fly );
- resetView();
-}
-
-void LLAgent::togglePhantom()
-{
- BOOL phan = !(exlPhantom);
-
- setPhantom( phan );
-}
-
-
-//-----------------------------------------------------------------------------
-// setRegion()
-//-----------------------------------------------------------------------------
-void LLAgent::setRegion(LLViewerRegion *regionp)
-{
- llassert(regionp);
- if (mRegionp != regionp)
- {
- // std::string host_name;
- // host_name = regionp->getHost().getHostName();
-
- std::string ip = regionp->getHost().getString();
- llinfos << "Moving agent into region: " << regionp->getName()
- << " located at " << ip << llendl;
- if (mRegionp)
- {
- // We've changed regions, we're now going to change our agent coordinate frame.
- mAgentOriginGlobal = regionp->getOriginGlobal();
- LLVector3d agent_offset_global = mRegionp->getOriginGlobal();
-
- LLVector3 delta;
- delta.setVec(regionp->getOriginGlobal() - mRegionp->getOriginGlobal());
-
- setPositionAgent(getPositionAgent() - delta);
-
- LLVector3 camera_position_agent = LLViewerCamera::getInstance()->getOrigin();
- LLViewerCamera::getInstance()->setOrigin(camera_position_agent - delta);
-
- // Update all of the regions.
- LLWorld::getInstance()->updateAgentOffset(agent_offset_global);
-
- // Hack to keep sky in the agent's region, otherwise it may get deleted - DJS 08/02/02
- // *TODO: possibly refactor into gSky->setAgentRegion(regionp)? -Brad
- if (gSky.mVOSkyp)
- {
- gSky.mVOSkyp->setRegion(regionp);
- }
- if (gSky.mVOGroundp)
- {
- gSky.mVOGroundp->setRegion(regionp);
- }
-
- }
- else
- {
- // First time initialization.
- // We've changed regions, we're now going to change our agent coordinate frame.
- mAgentOriginGlobal = regionp->getOriginGlobal();
-
- LLVector3 delta;
- delta.setVec(regionp->getOriginGlobal());
-
- setPositionAgent(getPositionAgent() - delta);
- LLVector3 camera_position_agent = LLViewerCamera::getInstance()->getOrigin();
- LLViewerCamera::getInstance()->setOrigin(camera_position_agent - delta);
-
- // Update all of the regions.
- LLWorld::getInstance()->updateAgentOffset(mAgentOriginGlobal);
- }
- }
- mRegionp = regionp;
-
- // Must shift hole-covering water object locations because local
- // coordinate frame changed.
- LLWorld::getInstance()->updateWaterObjects();
-
- // keep a list of regions we've been too
- // this is just an interesting stat, logged at the dataserver
- // we could trake this at the dataserver side, but that's harder
- U64 handle = regionp->getHandle();
- mRegionsVisited.insert(handle);
-
- LLSelectMgr::getInstance()->updateSelectionCenter();
-}
-
-
-//-----------------------------------------------------------------------------
-// getRegion()
-//-----------------------------------------------------------------------------
-LLViewerRegion *LLAgent::getRegion() const
-{
- return mRegionp;
-}
-
-
-const LLHost& LLAgent::getRegionHost() const
-{
- if (mRegionp)
- {
- return mRegionp->getHost();
- }
- else
- {
- return LLHost::invalid;
- }
-}
-
-//-----------------------------------------------------------------------------
-// getSLURL()
-// returns empty() if getRegion() == NULL
-//-----------------------------------------------------------------------------
-std::string LLAgent::getSLURL() const
-{
- std::string slurl;
- LLViewerRegion *regionp = getRegion();
- if (regionp)
- {
- LLVector3d agentPos = getPositionGlobal();
- S32 x = llround( (F32)fmod( agentPos.mdV[VX], (F64)REGION_WIDTH_METERS ) );
- S32 y = llround( (F32)fmod( agentPos.mdV[VY], (F64)REGION_WIDTH_METERS ) );
- S32 z = llround( (F32)agentPos.mdV[VZ] );
- slurl = LLURLDispatcher::buildSLURL(regionp->getName(), x, y, z);
- }
- return slurl;
-}
-
-//-----------------------------------------------------------------------------
-// inPrelude()
-//-----------------------------------------------------------------------------
-BOOL LLAgent::inPrelude()
-{
- return mRegionp && mRegionp->isPrelude();
-}
-
-
-//-----------------------------------------------------------------------------
-// canManageEstate()
-//-----------------------------------------------------------------------------
-
-BOOL LLAgent::canManageEstate() const
-{
- return mRegionp && mRegionp->canManageEstate();
-}
-
-//-----------------------------------------------------------------------------
-// sendMessage()
-//-----------------------------------------------------------------------------
-void LLAgent::sendMessage()
-{
- if (gDisconnected)
- {
- llwarns << "Trying to send message when disconnected!" << llendl;
- return;
- }
- if (!mRegionp)
- {
- llerrs << "No region for agent yet!" << llendl;
- }
- gMessageSystem->sendMessage(mRegionp->getHost());
-}
-
-
-//-----------------------------------------------------------------------------
-// sendReliableMessage()
-//-----------------------------------------------------------------------------
-void LLAgent::sendReliableMessage()
-{
- if (gDisconnected)
- {
- lldebugs << "Trying to send message when disconnected!" << llendl;
- return;
- }
- if (!mRegionp)
- {
- lldebugs << "LLAgent::sendReliableMessage No region for agent yet, not sending message!" << llendl;
- return;
- }
- gMessageSystem->sendReliable(mRegionp->getHost());
-}
-
-//-----------------------------------------------------------------------------
-// getVelocity()
-//-----------------------------------------------------------------------------
-LLVector3 LLAgent::getVelocity() const
-{
- if (mAvatarObject.notNull())
- {
- return mAvatarObject->getVelocity();
- }
- else
- {
- return LLVector3::zero;
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// setPositionAgent()
-//-----------------------------------------------------------------------------
-void LLAgent::setPositionAgent(const LLVector3 &pos_agent)
-{
- if (!pos_agent.isFinite())
- {
- llerrs << "setPositionAgent is not a number" << llendl;
- }
-
- if (mAvatarObject.notNull() && mAvatarObject->getParent())
- {
- LLVector3 pos_agent_sitting;
- LLVector3d pos_agent_d;
- LLViewerObject *parent = (LLViewerObject*)mAvatarObject->getParent();
-
- pos_agent_sitting = mAvatarObject->getPosition() * parent->getRotation() + parent->getPositionAgent();
- pos_agent_d.setVec(pos_agent_sitting);
-
- mFrameAgent.setOrigin(pos_agent_sitting);
- mPositionGlobal = pos_agent_d + mAgentOriginGlobal;
- }
- else
- {
- mFrameAgent.setOrigin(pos_agent);
-
- LLVector3d pos_agent_d;
- pos_agent_d.setVec(pos_agent);
- mPositionGlobal = pos_agent_d + mAgentOriginGlobal;
- }
-}
-
-//-----------------------------------------------------------------------------
-// slamLookAt()
-//-----------------------------------------------------------------------------
-void LLAgent::slamLookAt(const LLVector3 &look_at)
-{
- LLVector3 look_at_norm = look_at;
- look_at_norm.mV[VZ] = 0.f;
- look_at_norm.normalize();
- resetAxes(look_at_norm);
-}
-
-//-----------------------------------------------------------------------------
-// getPositionGlobal()
-//-----------------------------------------------------------------------------
-const LLVector3d &LLAgent::getPositionGlobal() const
-{
- if (mAvatarObject.notNull() && !mAvatarObject->mDrawable.isNull())
- {
- mPositionGlobal = getPosGlobalFromAgent(mAvatarObject->getRenderPosition());
- }
- else
- {
- mPositionGlobal = getPosGlobalFromAgent(mFrameAgent.getOrigin());
- }
-
- return mPositionGlobal;
-}
-
-//-----------------------------------------------------------------------------
-// getPositionAgent()
-//-----------------------------------------------------------------------------
-const LLVector3 &LLAgent::getPositionAgent()
-{
- if(mAvatarObject.notNull() && !mAvatarObject->mDrawable.isNull())
- {
- mFrameAgent.setOrigin(mAvatarObject->getRenderPosition());
- }
-
- return mFrameAgent.getOrigin();
-}
-
-//-----------------------------------------------------------------------------
-// getRegionsVisited()
-//-----------------------------------------------------------------------------
-S32 LLAgent::getRegionsVisited() const
-{
- return mRegionsVisited.size();
-}
-
-//-----------------------------------------------------------------------------
-// getDistanceTraveled()
-//-----------------------------------------------------------------------------
-F64 LLAgent::getDistanceTraveled() const
-{
- return mDistanceTraveled;
-}
-
-
-//-----------------------------------------------------------------------------
-// getPosAgentFromGlobal()
-//-----------------------------------------------------------------------------
-LLVector3 LLAgent::getPosAgentFromGlobal(const LLVector3d &pos_global) const
-{
- LLVector3 pos_agent;
- pos_agent.setVec(pos_global - mAgentOriginGlobal);
- return pos_agent;
-}
-
-
-//-----------------------------------------------------------------------------
-// getPosGlobalFromAgent()
-//-----------------------------------------------------------------------------
-LLVector3d LLAgent::getPosGlobalFromAgent(const LLVector3 &pos_agent) const
-{
- LLVector3d pos_agent_d;
- pos_agent_d.setVec(pos_agent);
- return pos_agent_d + mAgentOriginGlobal;
-}
-
-
-//-----------------------------------------------------------------------------
-// resetAxes()
-//-----------------------------------------------------------------------------
-void LLAgent::resetAxes()
-{
- mFrameAgent.resetAxes();
-}
-
-
-// Copied from LLCamera::setOriginAndLookAt
-// Look_at must be unit vector
-//-----------------------------------------------------------------------------
-// resetAxes()
-//-----------------------------------------------------------------------------
-void LLAgent::resetAxes(const LLVector3 &look_at)
-{
- LLVector3 skyward = getReferenceUpVector();
-
- // if look_at has zero length, fail
- // if look_at and skyward are parallel, fail
- //
- // Test both of these conditions with a cross product.
- LLVector3 cross(look_at % skyward);
- if (cross.isNull())
- {
- llinfos << "LLAgent::resetAxes cross-product is zero" << llendl;
- return;
- }
-
- // Make sure look_at and skyward are not parallel
- // and neither are zero length
- LLVector3 left(skyward % look_at);
- LLVector3 up(look_at % left);
-
- mFrameAgent.setAxes(look_at, left, up);
-}
-
-
-//-----------------------------------------------------------------------------
-// rotate()
-//-----------------------------------------------------------------------------
-void LLAgent::rotate(F32 angle, const LLVector3 &axis)
-{
- mFrameAgent.rotate(angle, axis);
-}
-
-
-//-----------------------------------------------------------------------------
-// rotate()
-//-----------------------------------------------------------------------------
-void LLAgent::rotate(F32 angle, F32 x, F32 y, F32 z)
-{
- mFrameAgent.rotate(angle, x, y, z);
-}
-
-
-//-----------------------------------------------------------------------------
-// rotate()
-//-----------------------------------------------------------------------------
-void LLAgent::rotate(const LLMatrix3 &matrix)
-{
- mFrameAgent.rotate(matrix);
-}
-
-
-//-----------------------------------------------------------------------------
-// rotate()
-//-----------------------------------------------------------------------------
-void LLAgent::rotate(const LLQuaternion &quaternion)
-{
- mFrameAgent.rotate(quaternion);
-}
-
-
-//-----------------------------------------------------------------------------
-// getReferenceUpVector()
-//-----------------------------------------------------------------------------
-LLVector3 LLAgent::getReferenceUpVector()
-{
- // this vector is in the coordinate frame of the avatar's parent object, or the world if none
- LLVector3 up_vector = LLVector3::z_axis;
- if (mAvatarObject.notNull() &&
- mAvatarObject->getParent() &&
- mAvatarObject->mDrawable.notNull())
- {
- U32 camera_mode = mCameraAnimating ? mLastCameraMode : mCameraMode;
- // and in third person...
- if (camera_mode == CAMERA_MODE_THIRD_PERSON)
- {
- // make the up vector point to the absolute +z axis
- up_vector = up_vector * ~((LLViewerObject*)mAvatarObject->getParent())->getRenderRotation();
- }
- else if (camera_mode == CAMERA_MODE_MOUSELOOK)
- {
- // make the up vector point to the avatar's +z axis
- up_vector = up_vector * mAvatarObject->mDrawable->getRotation();
- }
- }
-
- return up_vector;
-}
-
-
-// Radians, positive is forward into ground
-//-----------------------------------------------------------------------------
-// pitch()
-//-----------------------------------------------------------------------------
-void LLAgent::pitch(F32 angle)
-{
- // don't let user pitch if pointed almost all the way down or up
- mFrameAgent.pitch(clampPitchToLimits(angle));
-}
-
-
-// Radians, positive is forward into ground
-//-----------------------------------------------------------------------------
-// clampPitchToLimits()
-//-----------------------------------------------------------------------------
-F32 LLAgent::clampPitchToLimits(F32 angle)
-{
- // A dot B = mag(A) * mag(B) * cos(angle between A and B)
- // so... cos(angle between A and B) = A dot B / mag(A) / mag(B)
- // = A dot B for unit vectors
-
- LLVector3 skyward = getReferenceUpVector();
-
- F32 look_down_limit;
- F32 look_up_limit = 10.f * DEG_TO_RAD;
-
- F32 angle_from_skyward = acos( mFrameAgent.getAtAxis() * skyward );
-
- if (mAvatarObject.notNull() && mAvatarObject->mIsSitting)
- {
- look_down_limit = 130.f * DEG_TO_RAD;
- }
- else
- {
- look_down_limit = 170.f * DEG_TO_RAD;
- }
-
- // clamp pitch to limits
- if ((angle >= 0.f) && (angle_from_skyward + angle > look_down_limit))
- {
- angle = look_down_limit - angle_from_skyward;
- }
- else if ((angle < 0.f) && (angle_from_skyward + angle < look_up_limit))
- {
- angle = look_up_limit - angle_from_skyward;
- }
-
- return angle;
-}
-
-
-//-----------------------------------------------------------------------------
-// roll()
-//-----------------------------------------------------------------------------
-void LLAgent::roll(F32 angle)
-{
- mFrameAgent.roll(angle);
-}
-
-
-//-----------------------------------------------------------------------------
-// yaw()
-//-----------------------------------------------------------------------------
-void LLAgent::yaw(F32 angle)
-{
- if (!rotateGrabbed())
- {
- mFrameAgent.rotate(angle, getReferenceUpVector());
- }
-}
-
-
-// Returns a quat that represents the rotation of the agent in the absolute frame
-//-----------------------------------------------------------------------------
-// getQuat()
-//-----------------------------------------------------------------------------
-LLQuaternion LLAgent::getQuat() const
-{
- return mFrameAgent.getQuaternion();
-}
-
-
-//-----------------------------------------------------------------------------
-// calcFocusOffset()
-//-----------------------------------------------------------------------------
-LLVector3 LLAgent::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 LLAgent::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())
- {
- 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() - 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 LLAgent::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 LLAgent::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 LLAgent::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))
- {
- mFrameAgent.rotate(radians, getReferenceUpVector());
- }
- else
- {
- mCameraFocusOffsetTarget.rotVec(radians, 0.f, 0.f, 1.f);
-
- cameraZoomIn(1.f);
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// cameraOrbitOver()
-//-----------------------------------------------------------------------------
-void LLAgent::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)
- {
- pitch(angle);
- }
- else
- {
- LLVector3 camera_offset_unit(mCameraFocusOffsetTarget);
- camera_offset_unit.normalize();
-
- F32 angle_from_up = acos( camera_offset_unit * 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 LLAgent::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)
- {
- // screw cam constraints
- //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 LLAgent::cameraOrbitIn(const F32 meters)
-{
- if (mFocusOnAvatar && mCameraMode == CAMERA_MODE_THIRD_PERSON)
- {
- F32 camera_offset_dist = llmax(0.001f, mCameraOffsetDefault.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 LLAgent::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 LLAgent::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 LLAgent::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();
-}
-
-//-----------------------------------------------------------------------------
-// setKey()
-//-----------------------------------------------------------------------------
-void LLAgent::setKey(const S32 direction, S32 &key)
-{
- if (direction > 0)
- {
- key = 1;
- }
- else if (direction < 0)
- {
- key = -1;
- }
- else
- {
- key = 0;
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// getControlFlags()
-//-----------------------------------------------------------------------------
-U32 LLAgent::getControlFlags()
-{
-/*
- // HACK -- avoids maintenance of control flags when camera mode is turned on or off,
- // only worries about it when the flags are measured
- if (mCameraMode == CAMERA_MODE_MOUSELOOK)
- {
- if ( !(mControlFlags & AGENT_CONTROL_MOUSELOOK) )
- {
- mControlFlags |= AGENT_CONTROL_MOUSELOOK;
- }
- }
-*/
- return mControlFlags;
-}
-
-//-----------------------------------------------------------------------------
-// setControlFlags()
-//-----------------------------------------------------------------------------
-void LLAgent::setControlFlags(U32 mask)
-{
- mControlFlags |= mask;
- mbFlagsDirty = TRUE;
-}
-
-
-//-----------------------------------------------------------------------------
-// clearControlFlags()
-//-----------------------------------------------------------------------------
-void LLAgent::clearControlFlags(U32 mask)
-{
- U32 old_flags = mControlFlags;
- mControlFlags &= ~mask;
- if (old_flags != mControlFlags)
- {
- mbFlagsDirty = TRUE;
- }
-}
-
-//-----------------------------------------------------------------------------
-// controlFlagsDirty()
-//-----------------------------------------------------------------------------
-BOOL LLAgent::controlFlagsDirty() const
-{
- return mbFlagsDirty;
-}
-
-//-----------------------------------------------------------------------------
-// enableControlFlagReset()
-//-----------------------------------------------------------------------------
-void LLAgent::enableControlFlagReset()
-{
- mbFlagsNeedReset = TRUE;
-}
-
-//-----------------------------------------------------------------------------
-// resetControlFlags()
-//-----------------------------------------------------------------------------
-void LLAgent::resetControlFlags()
-{
- if (mbFlagsNeedReset)
- {
- mbFlagsNeedReset = FALSE;
- mbFlagsDirty = FALSE;
- // reset all of the ephemeral flags
- // some flags are managed elsewhere
- mControlFlags &= AGENT_CONTROL_AWAY | AGENT_CONTROL_FLY | AGENT_CONTROL_MOUSELOOK;
- }
-}
-
-//-----------------------------------------------------------------------------
-// setAFK()
-//-----------------------------------------------------------------------------
-void LLAgent::setAFK()
-{
- // Drones can't go AFK
- if (gNoRender)
- {
- return;
- }
-
- if (!gAgent.getRegion())
- {
- // Don't set AFK if we're not talking to a region yet.
- return;
- }
-
- if (!(mControlFlags & AGENT_CONTROL_AWAY))
- {
- sendAnimationRequest(ANIM_AGENT_AWAY, ANIM_REQUEST_START);
- setControlFlags(AGENT_CONTROL_AWAY | AGENT_CONTROL_STOP);
- gAwayTimer.start();
- if (gAFKMenu)
- {
- //*TODO:Translate
- gAFKMenu->setLabel(std::string("Set Not Away"));
- }
- }
-}
-
-//-----------------------------------------------------------------------------
-// clearAFK()
-//-----------------------------------------------------------------------------
-void LLAgent::clearAFK()
-{
- gAwayTriggerTimer.reset();
- if (!gSavedSettings.controlExists("FakeAway")) gSavedSettings.declareBOOL("FakeAway", FALSE, "", NO_PERSIST);
- if (gSavedSettings.getBOOL("FakeAway") == TRUE) return;
-
- // Gods can sometimes get into away state (via gestures)
- // without setting the appropriate control flag. JC
- LLVOAvatar* av = mAvatarObject;
- if (mControlFlags & AGENT_CONTROL_AWAY
- || (av
- && (av->mSignaledAnimations.find(ANIM_AGENT_AWAY) != av->mSignaledAnimations.end())))
- {
- sendAnimationRequest(ANIM_AGENT_AWAY, ANIM_REQUEST_STOP);
- clearControlFlags(AGENT_CONTROL_AWAY);
- if (gAFKMenu)
- {
- //*TODO:Translate
- gAFKMenu->setLabel(std::string("Set Away"));
- }
- }
-}
-
-//-----------------------------------------------------------------------------
-// getAFK()
-//-----------------------------------------------------------------------------
-BOOL LLAgent::getAFK() const
-{
- return (mControlFlags & AGENT_CONTROL_AWAY) != 0;
-}
-
-//-----------------------------------------------------------------------------
-// setBusy()
-//-----------------------------------------------------------------------------
-void LLAgent::setBusy()
-{
- sendAnimationRequest(ANIM_AGENT_BUSY, ANIM_REQUEST_START);
- mIsBusy = TRUE;
- if (gBusyMenu)
- {
- //*TODO:Translate
- gBusyMenu->setLabel(std::string("Set Not Busy"));
- }
- LLFloaterMute::getInstance()->updateButtons();
-}
-
-//-----------------------------------------------------------------------------
-// clearBusy()
-//-----------------------------------------------------------------------------
-void LLAgent::clearBusy()
-{
- mIsBusy = FALSE;
- sendAnimationRequest(ANIM_AGENT_BUSY, ANIM_REQUEST_STOP);
- if (gBusyMenu)
- {
- //*TODO:Translate
- gBusyMenu->setLabel(std::string("Set Busy"));
- }
- LLFloaterMute::getInstance()->updateButtons();
-}
-
-//-----------------------------------------------------------------------------
-// getBusy()
-//-----------------------------------------------------------------------------
-BOOL LLAgent::getBusy() const
-{
- return mIsBusy;
-}
-
-
-//-----------------------------------------------------------------------------
-// startAutoPilotGlobal()
-//-----------------------------------------------------------------------------
-void LLAgent::startAutoPilotGlobal(const LLVector3d &target_global, const std::string& behavior_name, const LLQuaternion *target_rotation, void (*finish_callback)(BOOL, void *), void *callback_data, F32 stop_distance, F32 rot_threshold)
-{
- if (!gAgent.getAvatarObject())
- {
- return;
- }
-
- mAutoPilotFinishedCallback = finish_callback;
- mAutoPilotCallbackData = callback_data;
- mAutoPilotRotationThreshold = rot_threshold;
- mAutoPilotBehaviorName = behavior_name;
-
- LLVector3d delta_pos( target_global );
- delta_pos -= getPositionGlobal();
- F64 distance = delta_pos.magVec();
- LLVector3d trace_target = target_global;
-
- trace_target.mdV[VZ] -= 10.f;
-
- LLVector3d intersection;
- LLVector3 normal;
- LLViewerObject *hit_obj;
- F32 heightDelta = LLWorld::getInstance()->resolveStepHeightGlobal(NULL, target_global, trace_target, intersection, normal, &hit_obj);
-
- if (stop_distance > 0.f)
- {
- mAutoPilotStopDistance = stop_distance;
- }
- else
- {
- // Guess at a reasonable stop distance.
- mAutoPilotStopDistance = fsqrtf( distance );
- if (mAutoPilotStopDistance < 0.5f)
- {
- mAutoPilotStopDistance = 0.5f;
- }
- }
-
- mAutoPilotFlyOnStop = getFlying();
-
- if (distance > 30.0)
- {
- setFlying(TRUE);
- }
-
- if ( distance > 1.f && heightDelta > (sqrtf(mAutoPilotStopDistance) + 1.f))
- {
- setFlying(TRUE);
- mAutoPilotFlyOnStop = TRUE;
- }
-
- mAutoPilot = TRUE;
- mAutoPilotTargetGlobal = target_global;
-
- // trace ray down to find height of destination from ground
- LLVector3d traceEndPt = target_global;
- traceEndPt.mdV[VZ] -= 20.f;
-
- LLVector3d targetOnGround;
- LLVector3 groundNorm;
- LLViewerObject *obj;
-
- LLWorld::getInstance()->resolveStepHeightGlobal(NULL, target_global, traceEndPt, targetOnGround, groundNorm, &obj);
- F64 target_height = llmax((F64)gAgent.getAvatarObject()->getPelvisToFoot(), target_global.mdV[VZ] - targetOnGround.mdV[VZ]);
-
- // clamp z value of target to minimum height above ground
- mAutoPilotTargetGlobal.mdV[VZ] = targetOnGround.mdV[VZ] + target_height;
- mAutoPilotTargetDist = (F32)dist_vec(gAgent.getPositionGlobal(), mAutoPilotTargetGlobal);
- if (target_rotation)
- {
- mAutoPilotUseRotation = TRUE;
- mAutoPilotTargetFacing = LLVector3::x_axis * *target_rotation;
- mAutoPilotTargetFacing.mV[VZ] = 0.f;
- mAutoPilotTargetFacing.normalize();
- }
- else
- {
- mAutoPilotUseRotation = FALSE;
- }
-
- mAutoPilotNoProgressFrameCount = 0;
-}
-
-
-//-----------------------------------------------------------------------------
-// startFollowPilot()
-//-----------------------------------------------------------------------------
-void LLAgent::startFollowPilot(const LLUUID &leader_id)
-{
- if (!mAutoPilot) return;
-
- mLeaderID = leader_id;
- if ( mLeaderID.isNull() ) return;
-
- LLViewerObject* object = gObjectList.findObject(mLeaderID);
- if (!object)
- {
- mLeaderID = LLUUID::null;
- return;
- }
-
- startAutoPilotGlobal(object->getPositionGlobal());
-}
-
-
-//-----------------------------------------------------------------------------
-// stopAutoPilot()
-//-----------------------------------------------------------------------------
-void LLAgent::stopAutoPilot(BOOL user_cancel)
-{
- if (mAutoPilot)
- {
- mAutoPilot = FALSE;
- if (mAutoPilotUseRotation && !user_cancel)
- {
- resetAxes(mAutoPilotTargetFacing);
- }
- //NB: auto pilot can terminate for a reason other than reaching the destination
- if (mAutoPilotFinishedCallback)
- {
- mAutoPilotFinishedCallback(!user_cancel && dist_vec(gAgent.getPositionGlobal(), mAutoPilotTargetGlobal) < mAutoPilotStopDistance, mAutoPilotCallbackData);
- }
- mLeaderID = LLUUID::null;
-
- // If the user cancelled, don't change the fly state
- if (!user_cancel)
- {
- setFlying(mAutoPilotFlyOnStop);
- }
- setControlFlags(AGENT_CONTROL_STOP);
-
- if (user_cancel && !mAutoPilotBehaviorName.empty())
- {
- if (mAutoPilotBehaviorName == "Sit")
- LLNotifications::instance().add("CancelledSit");
- else if (mAutoPilotBehaviorName == "Attach")
- LLNotifications::instance().add("CancelledAttach");
- else
- LLNotifications::instance().add("Cancelled");
- }
- }
-}
-
-
-// Returns necessary agent pitch and yaw changes, radians.
-//-----------------------------------------------------------------------------
-// autoPilot()
-//-----------------------------------------------------------------------------
-void LLAgent::autoPilot(F32 *delta_yaw)
-{
- if (mAutoPilot)
- {
- if (!mLeaderID.isNull())
- {
- LLViewerObject* object = gObjectList.findObject(mLeaderID);
- if (!object)
- {
- stopAutoPilot();
- return;
- }
- mAutoPilotTargetGlobal = object->getPositionGlobal();
- }
-
- if (mAvatarObject.isNull())
- {
- return;
- }
-
- if (mAvatarObject->mInAir)
- {
- setFlying(TRUE);
- }
-
- LLVector3 at;
- at.setVec(mFrameAgent.getAtAxis());
- LLVector3 target_agent = getPosAgentFromGlobal(mAutoPilotTargetGlobal);
- LLVector3 direction = target_agent - getPositionAgent();
-
- F32 target_dist = direction.magVec();
-
- if (target_dist >= mAutoPilotTargetDist)
- {
- mAutoPilotNoProgressFrameCount++;
- if (mAutoPilotNoProgressFrameCount > AUTOPILOT_MAX_TIME_NO_PROGRESS * gFPSClamped)
- {
- stopAutoPilot();
- return;
- }
- }
-
- mAutoPilotTargetDist = target_dist;
-
- // Make this a two-dimensional solution
- at.mV[VZ] = 0.f;
- direction.mV[VZ] = 0.f;
-
- at.normalize();
- F32 xy_distance = direction.normalize();
-
- F32 yaw = 0.f;
- if (mAutoPilotTargetDist > mAutoPilotStopDistance)
- {
- yaw = angle_between(mFrameAgent.getAtAxis(), direction);
- }
- else if (mAutoPilotUseRotation)
- {
- // we're close now just aim at target facing
- yaw = angle_between(at, mAutoPilotTargetFacing);
- direction = mAutoPilotTargetFacing;
- }
-
- yaw = 4.f * yaw / gFPSClamped;
-
- // figure out which direction to turn
- LLVector3 scratch(at % direction);
-
- if (scratch.mV[VZ] > 0.f)
- {
- setControlFlags(AGENT_CONTROL_YAW_POS);
- }
- else
- {
- yaw = -yaw;
- setControlFlags(AGENT_CONTROL_YAW_NEG);
- }
-
- *delta_yaw = yaw;
-
- // Compute when to start slowing down and when to stop
- F32 stop_distance = mAutoPilotStopDistance;
- F32 slow_distance;
- if (getFlying())
- {
- slow_distance = llmax(6.f, mAutoPilotStopDistance + 5.f);
- stop_distance = llmax(2.f, mAutoPilotStopDistance);
- }
- else
- {
- slow_distance = llmax(3.f, mAutoPilotStopDistance + 2.f);
- }
-
- // If we're flying, handle autopilot points above or below you.
- if (getFlying() && xy_distance < AUTOPILOT_HEIGHT_ADJUST_DISTANCE)
- {
- if (mAvatarObject.notNull())
- {
- F64 current_height = mAvatarObject->getPositionGlobal().mdV[VZ];
- F32 delta_z = (F32)(mAutoPilotTargetGlobal.mdV[VZ] - current_height);
- F32 slope = delta_z / xy_distance;
- if (slope > 0.45f && delta_z > 6.f)
- {
- setControlFlags(AGENT_CONTROL_FAST_UP | AGENT_CONTROL_UP_POS);
- }
- else if (slope > 0.002f && delta_z > 0.5f)
- {
- setControlFlags(AGENT_CONTROL_UP_POS);
- }
- else if (slope < -0.45f && delta_z < -6.f && current_height > AUTOPILOT_MIN_TARGET_HEIGHT_OFF_GROUND)
- {
- setControlFlags(AGENT_CONTROL_FAST_UP | AGENT_CONTROL_UP_NEG);
- }
- else if (slope < -0.002f && delta_z < -0.5f && current_height > AUTOPILOT_MIN_TARGET_HEIGHT_OFF_GROUND)
- {
- setControlFlags(AGENT_CONTROL_UP_NEG);
- }
- }
- }
-
- // calculate delta rotation to target heading
- F32 delta_target_heading = angle_between(mFrameAgent.getAtAxis(), mAutoPilotTargetFacing);
-
- if (xy_distance > slow_distance && yaw < (F_PI / 10.f))
- {
- // walking/flying fast
- setControlFlags(AGENT_CONTROL_FAST_AT | AGENT_CONTROL_AT_POS);
- }
- else if (mAutoPilotTargetDist > mAutoPilotStopDistance)
- {
- // walking/flying slow
- if (at * direction > 0.9f)
- {
- setControlFlags(AGENT_CONTROL_AT_POS);
- }
- else if (at * direction < -0.9f)
- {
- setControlFlags(AGENT_CONTROL_AT_NEG);
- }
- }
-
- // check to see if we need to keep rotating to target orientation
- if (mAutoPilotTargetDist < mAutoPilotStopDistance)
- {
- setControlFlags(AGENT_CONTROL_STOP);
- if(!mAutoPilotUseRotation || (delta_target_heading < mAutoPilotRotationThreshold))
- {
- stopAutoPilot();
- }
- }
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// propagate()
-//-----------------------------------------------------------------------------
-void LLAgent::propagate(const F32 dt)
-{
- // Update UI based on agent motion
- LLFloaterMove *floater_move = LLFloaterMove::getInstance();
- if (floater_move)
- {
- floater_move->mForwardButton ->setToggleState( mAtKey > 0 || mWalkKey > 0 );
- floater_move->mBackwardButton ->setToggleState( mAtKey < 0 || mWalkKey < 0 );
- floater_move->mSlideLeftButton ->setToggleState( mLeftKey > 0 );
- floater_move->mSlideRightButton->setToggleState( mLeftKey < 0 );
- floater_move->mTurnLeftButton ->setToggleState( mYawKey > 0.f );
- floater_move->mTurnRightButton ->setToggleState( mYawKey < 0.f );
- floater_move->mMoveUpButton ->setToggleState( mUpKey > 0 );
- floater_move->mMoveDownButton ->setToggleState( mUpKey < 0 );
- }
-
- // handle rotation based on keyboard levels
- const F32 YAW_RATE = 90.f * DEG_TO_RAD; // radians per second
- yaw( YAW_RATE * mYawKey * dt );
-
- const F32 PITCH_RATE = 90.f * DEG_TO_RAD; // radians per second
- pitch(PITCH_RATE * (F32) mPitchKey * dt);
-
- // handle auto-land behavior
- if (mAvatarObject.notNull())
- {
- BOOL in_air = mAvatarObject->mInAir;
- LLVector3 land_vel = getVelocity();
- land_vel.mV[VZ] = 0.f;
-
- if (!in_air
- && mUpKey < 0
- && land_vel.magVecSquared() < MAX_VELOCITY_AUTO_LAND_SQUARED
- && gSavedSettings.getBOOL("AutomaticFly"))
- {
- // land automatically
- setFlying(FALSE);
- }
- }
-
- // clear keys
- mAtKey = 0;
- mWalkKey = 0;
- mLeftKey = 0;
- mUpKey = 0;
- mYawKey = 0.f;
- mPitchKey = 0;
-}
-
-//-----------------------------------------------------------------------------
-// updateAgentPosition()
-//-----------------------------------------------------------------------------
-void LLAgent::updateAgentPosition(const F32 dt, const F32 yaw_radians, const S32 mouse_x, const S32 mouse_y)
-{
- propagate(dt);
-
- // static S32 cameraUpdateCount = 0;
-
- rotate(yaw_radians, 0, 0, 1);
-
- //
- // Check for water and land collision, set underwater flag
- //
-
- updateLookAt(mouse_x, mouse_y);
-}
-
-//-----------------------------------------------------------------------------
-// updateLookAt()
-//-----------------------------------------------------------------------------
-void LLAgent::updateLookAt(const S32 mouse_x, const S32 mouse_y)
-{
- static LLVector3 last_at_axis;
-
-
- if (mAvatarObject.isNull())
- {
- return;
- }
-
- LLQuaternion av_inv_rot = ~mAvatarObject->mRoot.getWorldRotation();
- LLVector3 root_at = LLVector3::x_axis * mAvatarObject->mRoot.getWorldRotation();
-
- if ((gViewerWindow->getMouseVelocityStat()->getCurrent() < 0.01f) &&
- (root_at * last_at_axis > 0.95f ))
- {
- LLVector3 vel = mAvatarObject->getVelocity();
- if (vel.magVecSquared() > 4.f)
- {
- setLookAt(LOOKAT_TARGET_IDLE, mAvatarObject, vel * av_inv_rot);
- }
- else
- {
- // *FIX: rotate mframeagent by sit object's rotation?
- LLQuaternion look_rotation = mAvatarObject->mIsSitting ? mAvatarObject->getRenderRotation() : mFrameAgent.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, mAvatarObject, look_offset);
- }
- last_at_axis = root_at;
- return;
- }
-
- last_at_axis = root_at;
-
- if (CAMERA_MODE_CUSTOMIZE_AVATAR == getCameraMode())
- {
- setLookAt(LOOKAT_TARGET_NONE, mAvatarObject, 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->getWindowWidth() ) - 0.5f;
- F32 y_from_center =
- ((F32) mouse_y / (F32) gViewerWindow->getWindowHeight() ) - 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, mAvatarObject, headLookAxis);
- }
-}
-
-// friends and operators
-
-std::ostream& operator<<(std::ostream &s, const LLAgent &agent)
-{
- // This is unfinished, but might never be used.
- // We'll just leave it for now; we can always delete it.
- s << " { "
- << " Frame = " << agent.mFrameAgent << "\n"
- << " }";
- return s;
-}
-
-
-// ------------------- Beginning of legacy LLCamera hack ----------------------
-// This section is included for legacy LLCamera support until
-// it is no longer needed. Some legacy code must exist in
-// non-legacy functions, and is labeled with "// legacy" comments.
-
-//-----------------------------------------------------------------------------
-// setAvatarObject()
-//-----------------------------------------------------------------------------
-void LLAgent::setAvatarObject(LLVOAvatar *avatar)
-{
- mAvatarObject = avatar;
-
- if (!avatar)
- {
- llinfos << "Setting LLAgent::mAvatarObject to NULL" << llendl;
- return;
- }
-
- 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);
- }
-
- sendAgentWearablesRequest();
-}
-
-// TRUE if your own avatar needs to be rendered. Usually only
-// in third person and build.
-//-----------------------------------------------------------------------------
-// needsRenderAvatar()
-//-----------------------------------------------------------------------------
-BOOL LLAgent::needsRenderAvatar()
-{
- if (cameraMouselook() && !LLVOAvatar::sVisibleInFirstPerson)
- {
- return FALSE;
- }
-
- return mShowAvatar && mGenderChosen;
-}
-
-// TRUE if we need to render your own avatar's head.
-BOOL LLAgent::needsRenderHead()
-{
- return (LLVOAvatar::sVisibleInFirstPerson && LLPipeline::sReflectionRender) || (mShowAvatar && !cameraMouselook());
-}
-
-//-----------------------------------------------------------------------------
-// startTyping()
-//-----------------------------------------------------------------------------
-void LLAgent::startTyping()
-{
- if (gSavedSettings.getBOOL("FakeAway"))
- return;
- mTypingTimer.reset();
-
- if (getRenderState() & AGENT_STATE_TYPING)
- {
- // already typing, don't trigger a different animation
- return;
- }
- setRenderState(AGENT_STATE_TYPING);
-
- if (mChatTimer.getElapsedTimeF32() < 2.f)
- {
- LLViewerObject* chatter = gObjectList.findObject(mLastChatterID);
- if (chatter && chatter->isAvatar())
- {
- gAgent.setLookAt(LOOKAT_TARGET_RESPOND, chatter, LLVector3::zero);
- }
- }
-
- if (gSavedSettings.getBOOL("PlayTypingAnim"))
- {
- sendAnimationRequest(ANIM_AGENT_TYPE, ANIM_REQUEST_START);
- }
- gChatBar->sendChatFromViewer("", CHAT_TYPE_START, FALSE);
-}
-
-//-----------------------------------------------------------------------------
-// stopTyping()
-//-----------------------------------------------------------------------------
-void LLAgent::stopTyping()
-{
- if (mRenderState & AGENT_STATE_TYPING)
- {
- clearRenderState(AGENT_STATE_TYPING);
- sendAnimationRequest(ANIM_AGENT_TYPE, ANIM_REQUEST_STOP);
- gChatBar->sendChatFromViewer("", CHAT_TYPE_STOP, FALSE);
- }
-}
-
-//-----------------------------------------------------------------------------
-// setRenderState()
-//-----------------------------------------------------------------------------
-void LLAgent::setRenderState(U8 newstate)
-{
- mRenderState |= newstate;
-}
-
-//-----------------------------------------------------------------------------
-// clearRenderState()
-//-----------------------------------------------------------------------------
-void LLAgent::clearRenderState(U8 clearstate)
-{
- mRenderState &= ~clearstate;
-}
-
-
-//-----------------------------------------------------------------------------
-// getRenderState()
-//-----------------------------------------------------------------------------
-U8 LLAgent::getRenderState()
-{
- if (gNoRender || gKeyboard == NULL)
- {
- return 0;
- }
-
- // *FIX: don't do stuff in a getter! This is infinite loop city!
- if ((mTypingTimer.getElapsedTimeF32() > TYPING_TIMEOUT_SECS)
- && (mRenderState & AGENT_STATE_TYPING))
- {
- stopTyping();
- }
-
- if ((!LLSelectMgr::getInstance()->getSelection()->isEmpty() && LLSelectMgr::getInstance()->shouldShowSelection())
- || LLToolMgr::getInstance()->getCurrentTool()->isEditing() )
- {
- setRenderState(AGENT_STATE_EDITING);
- }
- else
- {
- clearRenderState(AGENT_STATE_EDITING);
- }
-
- return mRenderState;
-}
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-
-static const LLFloaterView::skip_list_t& get_skip_list()
-{
- static LLFloaterView::skip_list_t skip_list;
- skip_list.insert(LLFloaterMap::getInstance());
- return skip_list;
-}
-
-//-----------------------------------------------------------------------------
-// endAnimationUpdateUI()
-//-----------------------------------------------------------------------------
-void LLAgent::endAnimationUpdateUI()
-{
- if (mCameraMode == mLastCameraMode)
- {
- // We're already done endAnimationUpdateUI for this transition.
- return;
- }
-
- // clean up UI from mode we're leaving
- if ( mLastCameraMode == CAMERA_MODE_MOUSELOOK )
- {
- // show mouse cursor
- gViewerWindow->showCursor();
- // show menus
- gMenuBarView->setVisible(TRUE);
- gStatusBar->setVisibleForMouselook(true);
-
- LLToolMgr::getInstance()->setCurrentToolset(gBasicToolset);
-
- // Only pop if we have pushed...
- if (TRUE == mViewsPushed)
- {
- mViewsPushed = FALSE;
- gFloaterView->popVisibleAll(get_skip_list());
- }
-
- gAgent.setLookAt(LOOKAT_TARGET_CLEAR);
- if( gMorphView )
- {
- gMorphView->setVisible( FALSE );
- }
-
- // Disable mouselook-specific animations
- if (mAvatarObject.notNull())
- {
- if( mAvatarObject->isAnyAnimationSignaled(AGENT_GUN_AIM_ANIMS, NUM_AGENT_GUN_AIM_ANIMS) )
- {
- if (mAvatarObject->mSignaledAnimations.find(ANIM_AGENT_AIM_RIFLE_R) != mAvatarObject->mSignaledAnimations.end())
- {
- sendAnimationRequest(ANIM_AGENT_AIM_RIFLE_R, ANIM_REQUEST_STOP);
- sendAnimationRequest(ANIM_AGENT_HOLD_RIFLE_R, ANIM_REQUEST_START);
- }
- if (mAvatarObject->mSignaledAnimations.find(ANIM_AGENT_AIM_HANDGUN_R) != mAvatarObject->mSignaledAnimations.end())
- {
- sendAnimationRequest(ANIM_AGENT_AIM_HANDGUN_R, ANIM_REQUEST_STOP);
- sendAnimationRequest(ANIM_AGENT_HOLD_HANDGUN_R, ANIM_REQUEST_START);
- }
- if (mAvatarObject->mSignaledAnimations.find(ANIM_AGENT_AIM_BAZOOKA_R) != mAvatarObject->mSignaledAnimations.end())
- {
- sendAnimationRequest(ANIM_AGENT_AIM_BAZOOKA_R, ANIM_REQUEST_STOP);
- sendAnimationRequest(ANIM_AGENT_HOLD_BAZOOKA_R, ANIM_REQUEST_START);
- }
- if (mAvatarObject->mSignaledAnimations.find(ANIM_AGENT_AIM_BOW_L) != mAvatarObject->mSignaledAnimations.end())
- {
- sendAnimationRequest(ANIM_AGENT_AIM_BOW_L, ANIM_REQUEST_STOP);
- sendAnimationRequest(ANIM_AGENT_HOLD_BOW_L, ANIM_REQUEST_START);
- }
- }
- }
- }
- else
- if( mLastCameraMode == CAMERA_MODE_CUSTOMIZE_AVATAR )
- {
- // make sure we ask to save changes
-
- LLToolMgr::getInstance()->setCurrentToolset(gBasicToolset);
-
- // HACK: If we're quitting, and we were in customize avatar, don't
- // let the mini-map go visible again. JC
- if (!LLAppViewer::instance()->quitRequested())
- {
- LLFloaterMap::getInstance()->popVisible();
- }
-
- if( gMorphView )
- {
- gMorphView->setVisible( FALSE );
- }
-
- if (mAvatarObject.notNull())
- {
- if(mCustomAnim)
- {
- sendAnimationRequest(ANIM_AGENT_CUSTOMIZE, ANIM_REQUEST_STOP);
- sendAnimationRequest(ANIM_AGENT_CUSTOMIZE_DONE, ANIM_REQUEST_START);
-
- mCustomAnim = FALSE ;
- }
-
- }
- setLookAt(LOOKAT_TARGET_CLEAR);
- }
-
- //---------------------------------------------------------------------
- // Set up UI for mode we're entering
- //---------------------------------------------------------------------
- if (mCameraMode == CAMERA_MODE_MOUSELOOK)
- {
- // hide menus
- gMenuBarView->setVisible(FALSE);
- gStatusBar->setVisibleForMouselook(false);
-
- // clear out camera lag effect
- mCameraLag.clearVec();
-
- // JC - Added for always chat in third person option
- gFocusMgr.setKeyboardFocus(NULL);
-
- LLToolMgr::getInstance()->setCurrentToolset(gMouselookToolset);
-
- mViewsPushed = TRUE;
-
- gFloaterView->pushVisibleAll(FALSE, get_skip_list());
-
- if( gMorphView )
- {
- gMorphView->setVisible(FALSE);
- }
-
- gConsole->setVisible( TRUE );
-
- if (mAvatarObject.notNull())
- {
- // Trigger mouselook-specific animations
- if( mAvatarObject->isAnyAnimationSignaled(AGENT_GUN_HOLD_ANIMS, NUM_AGENT_GUN_HOLD_ANIMS) )
- {
- if (mAvatarObject->mSignaledAnimations.find(ANIM_AGENT_HOLD_RIFLE_R) != mAvatarObject->mSignaledAnimations.end())
- {
- sendAnimationRequest(ANIM_AGENT_HOLD_RIFLE_R, ANIM_REQUEST_STOP);
- sendAnimationRequest(ANIM_AGENT_AIM_RIFLE_R, ANIM_REQUEST_START);
- }
- if (mAvatarObject->mSignaledAnimations.find(ANIM_AGENT_HOLD_HANDGUN_R) != mAvatarObject->mSignaledAnimations.end())
- {
- sendAnimationRequest(ANIM_AGENT_HOLD_HANDGUN_R, ANIM_REQUEST_STOP);
- sendAnimationRequest(ANIM_AGENT_AIM_HANDGUN_R, ANIM_REQUEST_START);
- }
- if (mAvatarObject->mSignaledAnimations.find(ANIM_AGENT_HOLD_BAZOOKA_R) != mAvatarObject->mSignaledAnimations.end())
- {
- sendAnimationRequest(ANIM_AGENT_HOLD_BAZOOKA_R, ANIM_REQUEST_STOP);
- sendAnimationRequest(ANIM_AGENT_AIM_BAZOOKA_R, ANIM_REQUEST_START);
- }
- if (mAvatarObject->mSignaledAnimations.find(ANIM_AGENT_HOLD_BOW_L) != mAvatarObject->mSignaledAnimations.end())
- {
- sendAnimationRequest(ANIM_AGENT_HOLD_BOW_L, ANIM_REQUEST_STOP);
- sendAnimationRequest(ANIM_AGENT_AIM_BOW_L, ANIM_REQUEST_START);
- }
- }
- if (mAvatarObject->getParent())
- {
- LLVector3 at_axis = LLViewerCamera::getInstance()->getAtAxis();
- LLViewerObject* root_object = (LLViewerObject*)mAvatarObject->getRoot();
- if (root_object->flagCameraDecoupled())
- {
- resetAxes(at_axis);
- }
- else
- {
- resetAxes(at_axis * ~((LLViewerObject*)mAvatarObject->getParent())->getRenderRotation());
- }
- }
- }
-
- }
- else if (mCameraMode == CAMERA_MODE_CUSTOMIZE_AVATAR)
- {
- LLToolMgr::getInstance()->setCurrentToolset(gFaceEditToolset);
-
- LLFloaterMap::getInstance()->pushVisible(FALSE);
- /*
- LLView *view;
- for (view = gFloaterView->getFirstChild(); view; view = gFloaterView->getNextChild())
- {
- view->pushVisible(FALSE);
- }
- */
-
- if( gMorphView )
- {
- gMorphView->setVisible( TRUE );
- }
-
- // freeze avatar
- if (mAvatarObject.notNull())
- {
- //
- //mPauseRequest = mAvatarObject->requestPause();
- //
- }
- }
-
- if (getAvatarObject())
- {
- getAvatarObject()->updateAttachmentVisibility(mCameraMode);
- }
-
- gFloaterTools->dirty();
-
- // Don't let this be called more than once if the camera
- // mode hasn't changed. --JC
- mLastCameraMode = mCameraMode;
-
-}
-
-
-//-----------------------------------------------------------------------------
-// updateCamera()
-//-----------------------------------------------------------------------------
-void LLAgent::updateCamera()
-{
- //Ventrella - changed camera_skyward to the new global "mCameraUpVector"
- mCameraUpVector = LLVector3::z_axis;
- //LLVector3 camera_skyward(0.f, 0.f, 1.f);
- //end Ventrella
-
- U32 camera_mode = mCameraAnimating ? mLastCameraMode : mCameraMode;
-
- validateFocusObject();
-
- if (mAvatarObject.notNull() &&
- mAvatarObject->mIsSitting &&
- camera_mode == CAMERA_MODE_MOUSELOOK)
- {
- //Ventrella
- //changed camera_skyward to the new global "mCameraUpVector"
- mCameraUpVector = mCameraUpVector * mAvatarObject->getRenderRotation();
- //end Ventrella
- }
-
- if (cameraThirdPerson() && mFocusOnAvatar && LLFollowCamMgr::getActiveFollowCamParams())
- {
- changeCameraToFollow();
- }
-
- //Ventrella
- //NOTE - this needs to be integrated into a general upVector system here within llAgent.
- if ( camera_mode == CAMERA_MODE_FOLLOW && mFocusOnAvatar )
- {
- mCameraUpVector = mFollowCam.getUpVector();
- }
- //end Ventrella
-
- if (mSitCameraEnabled)
- {
- if (mSitCameraReferenceObject->isDead())
- {
- setSitCamera(LLUUID::null);
- }
- }
-
- // Update UI with our camera inputs
- LLFloaterCamera::getInstance()->mRotate->setToggleState(
- mOrbitRightKey > 0.f, // left
- mOrbitUpKey > 0.f, // top
- mOrbitLeftKey > 0.f, // right
- mOrbitDownKey > 0.f); // bottom
-
- LLFloaterCamera::getInstance()->mZoom->setToggleState(
- mOrbitInKey > 0.f, // top
- mOrbitOutKey > 0.f); // bottom
-
- LLFloaterCamera::getInstance()->mTrack->setToggleState(
- mPanLeftKey > 0.f, // left
- mPanUpKey > 0.f, // top
- mPanRightKey > 0.f, // right
- mPanDownKey > 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( mOrbitUpKey || mOrbitDownKey )
- {
- F32 input_rate = mOrbitUpKey - mOrbitDownKey;
- cameraOrbitOver( input_rate * ORBIT_OVER_RATE / gFPSClamped );
- }
-
- if( mOrbitLeftKey || mOrbitRightKey)
- {
- F32 input_rate = mOrbitLeftKey - mOrbitRightKey;
- cameraOrbitAround( input_rate * ORBIT_AROUND_RATE / gFPSClamped );
- }
-
- if( mOrbitInKey || mOrbitOutKey )
- {
- F32 input_rate = mOrbitInKey - mOrbitOutKey;
-
- 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( mPanInKey || mPanOutKey )
- {
- F32 input_rate = mPanInKey - mPanOutKey;
- cameraPanIn( input_rate * PAN_RATE / gFPSClamped );
- }
-
- if( mPanRightKey || mPanLeftKey )
- {
- F32 input_rate = mPanRightKey - mPanLeftKey;
- cameraPanLeft( input_rate * -PAN_RATE / gFPSClamped );
- }
-
- if( mPanUpKey || mPanDownKey )
- {
- F32 input_rate = mPanUpKey - mPanDownKey;
- cameraPanUp( input_rate * PAN_RATE / gFPSClamped );
- }
-
- // Clear camera keyboard keys.
- mOrbitLeftKey = 0.f;
- mOrbitRightKey = 0.f;
- mOrbitUpKey = 0.f;
- mOrbitDownKey = 0.f;
- mOrbitInKey = 0.f;
- mOrbitOutKey = 0.f;
-
- mPanRightKey = 0.f;
- mPanLeftKey = 0.f;
- mPanUpKey = 0.f;
- mPanDownKey = 0.f;
- mPanInKey = 0.f;
- mPanOutKey = 0.f;
-
- // lerp camera focus offset
- mCameraFocusOffset = lerp(mCameraFocusOffset, mCameraFocusOffsetTarget, LLCriticalDamp::getInterpolant(CAMERA_FOCUS_HALF_LIFE));
-
- //Ventrella
- if ( mCameraMode == CAMERA_MODE_FOLLOW )
- {
- if ( mAvatarObject.notNull() )
- {
- //--------------------------------------------------------------------------------
- // 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 = mAvatarObject->mIsSitting ? mAvatarObject->getRenderRotation() : mFrameAgent.getQuaternion();
-
- LLFollowCamParams* current_cam = LLFollowCamMgr::getActiveFollowCamParams();
- if (current_cam)
- {
- mFollowCam.copyParams(*current_cam);
- mFollowCam.setSubjectPositionAndRotation( mAvatarObject->getRenderPosition(), avatarRotationForFollowCam );
- mFollowCam.update();
- }
- else
- {
- changeCameraToThirdPerson(TRUE);
- }
- }
- }
- // end Ventrella
-
- BOOL hit_limit;
- LLVector3d camera_pos_global;
- LLVector3d camera_target_global = calcCameraPositionTargetGlobal(&hit_limit);
- mCameraVirtualPositionAgent = 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);
-
- mShowAvatar = 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 )
- {
- mShowAvatar = 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;
-
- endAnimationUpdateUI();
- mShowAvatar = TRUE;
- }
-
- if (getAvatarObject() && mCameraMode != CAMERA_MODE_MOUSELOOK)
- {
- getAvatarObject()->updateAttachmentVisibility(mCameraMode);
- }
- }
- else
- {
- camera_pos_global = camera_target_global;
- mFocusGlobal = focus_target_global;
- mShowAvatar = TRUE;
- }
-
- // smoothing
- if (TRUE)
- {
- LLVector3d agent_pos = 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
- mCameraSmoothingStop |= (BOOL)LLToolMgr::getInstance()->inBuildMode();
-
- 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;
-
- F32 ui_offset = 0.f;
- if( CAMERA_MODE_CUSTOMIZE_AVATAR == mCameraMode )
- {
- ui_offset = calcCustomizeAvatarUIOffset( camera_pos_global );
- }
-
-
- LLVector3 focus_agent = getPosAgentFromGlobal(mFocusGlobal);
-
- mCameraPositionAgent = getPosAgentFromGlobal(camera_pos_global);
-
- // Move the camera
-
- //Ventrella
- LLViewerCamera::getInstance()->updateCameraLocation(mCameraPositionAgent, mCameraUpVector, focus_agent);
- //LLViewerCamera::getInstance()->updateCameraLocation(mCameraPositionAgent, camera_skyward, focus_agent);
- //end Ventrella
-
- //RN: translate UI offset after camera is oriented properly
- LLViewerCamera::getInstance()->translate(LLViewerCamera::getInstance()->getLeftAxis() * ui_offset);
-
- // 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 = getPositionGlobal();
- if (! mLastPositionGlobal.isExactlyZero())
- {
- LLVector3d delta = global_pos - mLastPositionGlobal;
- mDistanceTraveled += delta.magVec();
- }
- mLastPositionGlobal = global_pos;
-
- if (LLVOAvatar::sVisibleInFirstPerson && mAvatarObject.notNull() && !mAvatarObject->mIsSitting && cameraMouselook())
- {
- LLVector3 head_pos = mAvatarObject->mHeadp->getWorldPosition() +
- LLVector3(0.08f, 0.f, 0.05f) * mAvatarObject->mHeadp->getWorldRotation() +
- LLVector3(0.1f, 0.f, 0.f) * mAvatarObject->mPelvisp->getWorldRotation();
- LLVector3 diff = mCameraPositionAgent - head_pos;
- diff = diff * ~mAvatarObject->mRoot.getWorldRotation();
-
- LLJoint* torso_joint = mAvatarObject->mTorsop;
- LLJoint* chest_joint = mAvatarObject->mChestp;
- LLVector3 torso_scale = torso_joint->getScale();
- LLVector3 chest_scale = chest_joint->getScale();
-
- // shorten avatar skeleton to avoid foot interpenetration
- if (!mAvatarObject->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 = mAvatarObject->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;
- }
-
- mAvatarObject->mPelvisp->setPosition(mAvatarObject->mPelvisp->getPosition() + diff);
-
- mAvatarObject->mRoot.updateWorldMatrixChildren();
-
- for (LLVOAvatar::attachment_map_t::iterator iter = mAvatarObject->mAttachmentPoints.begin();
- iter != mAvatarObject->mAttachmentPoints.end(); )
- {
- LLVOAvatar::attachment_map_t::iterator curiter = iter++;
- LLViewerJointAttachment* attachment = curiter->second;
- LLViewerObject *attached_object = attachment->getObject();
- 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 LLAgent::updateFocusOffset()
-{
- validateFocusObject();
- if (mFocusObject.notNull())
- {
- LLVector3d obj_pos = getPosGlobalFromAgent(mFocusObject->getRenderPosition());
- mFocusObjectOffset.setVec(mFocusTargetGlobal - obj_pos);
- }
-}
-
-void LLAgent::validateFocusObject()
-{
- if (mFocusObject.notNull() &&
- (mFocusObject->isDead()))
- {
- mFocusObjectOffset.clearVec();
- clearFocusObject();
- mCameraFOVZoomFactor = 0.f;
- }
-}
-
-//-----------------------------------------------------------------------------
-// calcCustomizeAvatarUIOffset()
-//-----------------------------------------------------------------------------
-F32 LLAgent::calcCustomizeAvatarUIOffset( const LLVector3d& camera_pos_global )
-{
- F32 ui_offset = 0.f;
-
- if( gFloaterCustomize )
- {
- const LLRect& rect = gFloaterCustomize->getRect();
-
- // Move the camera so that the avatar isn't covered up by this floater.
- F32 fraction_of_fov = 0.5f - (0.5f * (1.f - llmin(1.f, ((F32)rect.getWidth() / (F32)gViewerWindow->getWindowWidth()))));
- F32 apparent_angle = fraction_of_fov * LLViewerCamera::getInstance()->getView() * LLViewerCamera::getInstance()->getAspect(); // radians
- F32 offset = tan(apparent_angle);
-
- if( rect.mLeft < (gViewerWindow->getWindowWidth() - rect.mRight) )
- {
- // Move the avatar to the right (camera to the left)
- ui_offset = offset;
- }
- else
- {
- // Move the avatar to the left (camera to the right)
- ui_offset = -offset;
- }
- }
- F32 range = (F32)dist_vec(camera_pos_global, gAgent.getFocusGlobal());
- mUIOffset = lerp(mUIOffset, ui_offset, LLCriticalDamp::getInterpolant(0.05f));
- return mUIOffset * range;
-}
-
-//-----------------------------------------------------------------------------
-// calcFocusPositionTargetGlobal()
-//-----------------------------------------------------------------------------
-LLVector3d LLAgent::calcFocusPositionTargetGlobal()
-{
- if (mFocusObject.notNull() && mFocusObject->isDead())
- {
- clearFocusObject();
- }
-
- // Ventrella
- if ( mCameraMode == CAMERA_MODE_FOLLOW && mFocusOnAvatar )
- {
- mFocusTargetGlobal = gAgent.getPosGlobalFromAgent(mFollowCam.getSimulatedFocus());
- return mFocusTargetGlobal;
- }// End Ventrella
- else if (mCameraMode == CAMERA_MODE_MOUSELOOK)
- {
- LLVector3d at_axis(1.0, 0.0, 0.0);
- LLQuaternion agent_rot = mFrameAgent.getQuaternion();
- if (mAvatarObject.notNull() && mAvatarObject->getParent())
- {
- LLViewerObject* root_object = (LLViewerObject*)mAvatarObject->getRoot();
- if (!root_object->flagCameraDecoupled())
- {
- agent_rot *= ((LLViewerObject*)(mAvatarObject->getParent()))->getRenderRotation();
- }
- }
- at_axis = at_axis * agent_rot;
- mFocusTargetGlobal = calcCameraPositionTargetGlobal() + at_axis;
- return mFocusTargetGlobal;
- }
- else if (mCameraMode == CAMERA_MODE_CUSTOMIZE_AVATAR)
- {
- return mFocusTargetGlobal;
- }
- else if (!mFocusOnAvatar)
- {
- if (mFocusObject.notNull() && !mFocusObject->isDead() && mFocusObject->mDrawable.notNull())
- {
- LLDrawable* drawablep = mFocusObject->mDrawable;
-
- if (mTrackFocusObject &&
- drawablep &&
- drawablep->isActive())
- {
- if (!mFocusObject->isAvatar())
- {
- if (mFocusObject->isSelected())
- {
- gPipeline.updateMoveNormalAsync(drawablep);
- }
- else
- {
- if (drawablep->isState(LLDrawable::MOVE_UNDAMPED))
- {
- gPipeline.updateMoveNormalAsync(drawablep);
- }
- else
- {
- gPipeline.updateMoveDampedAsync(drawablep);
- }
- }
- }
- }
- // if not tracking object, update offset based on new object position
- else
- {
- updateFocusOffset();
- }
- LLVector3 focus_agent = mFocusObject->getRenderPosition() + mFocusObjectOffset;
- mFocusTargetGlobal.setVec(getPosGlobalFromAgent(focus_agent));
- }
- return mFocusTargetGlobal;
- }
- else if (mSitCameraEnabled && mAvatarObject.notNull() && mAvatarObject->mIsSitting && mSitCameraReferenceObject.notNull())
- {
- // sit camera
- LLVector3 object_pos = mSitCameraReferenceObject->getRenderPosition();
- LLQuaternion object_rot = mSitCameraReferenceObject->getRenderRotation();
-
- LLVector3 target_pos = object_pos + (mSitCameraFocus * object_rot);
- return getPosGlobalFromAgent(target_pos);
- }
- else
- {
- return getPositionGlobal() + calcThirdPersonFocusOffset();
- }
-}
-
-LLVector3d LLAgent::calcThirdPersonFocusOffset()
-{
- // ...offset from avatar
- LLVector3d focus_offset;
- focus_offset.setVec(gSavedSettings.getVector3("FocusOffsetDefault"));
-
- LLQuaternion agent_rot = mFrameAgent.getQuaternion();
- if (!mAvatarObject.isNull() && mAvatarObject->getParent())
- {
- agent_rot *= ((LLViewerObject*)(mAvatarObject->getParent()))->getRenderRotation();
- }
-
- focus_offset = focus_offset * agent_rot;
- return focus_offset;
-}
-
-void LLAgent::setupSitCamera()
-{
- // agent frame entering this function is in world coordinates
- if (mAvatarObject.notNull() && mAvatarObject->getParent())
- {
- LLQuaternion parent_rot = ((LLViewerObject*)mAvatarObject->getParent())->getRenderRotation();
- // slam agent coordinate frame to proper parent local version
- LLVector3 at_axis = mFrameAgent.getAtAxis();
- at_axis.mV[VZ] = 0.f;
- at_axis.normalize();
- resetAxes(at_axis * ~parent_rot);
- }
-}
-
-//-----------------------------------------------------------------------------
-// getCameraPositionAgent()
-//-----------------------------------------------------------------------------
-const LLVector3 &LLAgent::getCameraPositionAgent() const
-{
- return LLViewerCamera::getInstance()->getOrigin();
-}
-
-//-----------------------------------------------------------------------------
-// getCameraPositionGlobal()
-//-----------------------------------------------------------------------------
-LLVector3d LLAgent::getCameraPositionGlobal() const
-{
- return getPosGlobalFromAgent(LLViewerCamera::getInstance()->getOrigin());
-}
-
-//-----------------------------------------------------------------------------
-// calcCameraFOVZoomFactor()
-//-----------------------------------------------------------------------------
-F32 LLAgent::calcCameraFOVZoomFactor()
-{
- LLVector3 camera_offset_dir;
- camera_offset_dir.setVec(mCameraFocusOffset);
-
- if (mCameraMode == CAMERA_MODE_MOUSELOOK)
- {
- return 0.f;
- }
- else if (mFocusObject.notNull() && !mFocusObject->isAvatar())
- {
- // don't FOV zoom on mostly transparent objects
- LLVector3 focus_offset = mFocusObjectOffset;
- F32 obj_min_dist = 0.f;
- calcCameraMinDistance(obj_min_dist);
- F32 current_distance = llmax(0.001f, camera_offset_dir.magVec());
-
- mFocusObjectDist = obj_min_dist - current_distance;
-
- F32 new_fov_zoom = llclamp(mFocusObjectDist / current_distance, 0.f, 1000.f);
- return new_fov_zoom;
- }
- else // focusing on land or avatar
- {
- // keep old field of view until user changes focus explicitly
- return mCameraFOVZoomFactor;
- //return 0.f;
- }
-}
-
-//-----------------------------------------------------------------------------
-// calcCameraPositionTargetGlobal()
-//-----------------------------------------------------------------------------
-LLVector3d LLAgent::calcCameraPositionTargetGlobal(BOOL *hit_limit)
-{
- // Compute base camera position and look-at points.
- F32 camera_land_height;
- LLVector3d frame_center_global = mAvatarObject.isNull() ? getPositionGlobal()
- : getPosGlobalFromAgent(mAvatarObject->mRoot.getWorldPosition());
-
- LLVector3 upAxis = getUpAxis();
- BOOL isConstrained = FALSE;
- LLVector3d head_offset;
- head_offset.setVec(mThirdPersonHeadOffset);
-
- LLVector3d camera_position_global;
-
- // Ventrella
- if ( mCameraMode == CAMERA_MODE_FOLLOW && mFocusOnAvatar )
- {
- camera_position_global = gAgent.getPosGlobalFromAgent(mFollowCam.getSimulatedPosition());
- }// End Ventrella
- else if (mCameraMode == CAMERA_MODE_MOUSELOOK)
- {
- if (mAvatarObject.isNull() || mAvatarObject->mDrawable.isNull())
- {
- llwarns << "Null avatar drawable!" << llendl;
- return LLVector3d::zero;
- }
- head_offset.clearVec();
- if (mAvatarObject->mIsSitting && mAvatarObject->getParent())
- {
- mAvatarObject->updateHeadOffset();
- head_offset.mdV[VX] = mAvatarObject->mHeadOffset.mV[VX];
- head_offset.mdV[VY] = mAvatarObject->mHeadOffset.mV[VY];
- head_offset.mdV[VZ] = mAvatarObject->mHeadOffset.mV[VZ] + 0.1f;
- const LLMatrix4& mat = ((LLViewerObject*) mAvatarObject->getParent())->getRenderMatrix();
- camera_position_global = getPosGlobalFromAgent
- ((mAvatarObject->getPosition()+
- LLVector3(head_offset)*mAvatarObject->getRotation()) * mat);
- }
- else
- {
- head_offset.mdV[VZ] = mAvatarObject->mHeadOffset.mV[VZ];
- if (mAvatarObject->mIsSitting)
- {
- head_offset.mdV[VZ] += 0.1;
- }
- camera_position_global = getPosGlobalFromAgent(mAvatarObject->getRenderPosition());//frame_center_global;
- head_offset = head_offset * mAvatarObject->getRenderRotation();
- camera_position_global = camera_position_global + head_offset;
- }
- }
- else if (mCameraMode == CAMERA_MODE_THIRD_PERSON && mFocusOnAvatar)
- {
- LLVector3 local_camera_offset;
- F32 camera_distance = 0.f;
-
- if (mSitCameraEnabled
- && mAvatarObject.notNull()
- && mAvatarObject->mIsSitting
- && mSitCameraReferenceObject.notNull())
- {
- // sit camera
- LLVector3 object_pos = mSitCameraReferenceObject->getRenderPosition();
- LLQuaternion object_rot = mSitCameraReferenceObject->getRenderRotation();
-
- LLVector3 target_pos = object_pos + (mSitCameraPos * object_rot);
-
- camera_position_global = getPosGlobalFromAgent(target_pos);
- }
- else
- {
- local_camera_offset = mCameraZoomFraction * mCameraOffsetDefault * gSavedSettings.getF32("CameraOffsetScale");
-
- // are we sitting down?
- if (mAvatarObject.notNull() && mAvatarObject->getParent())
- {
- LLQuaternion parent_rot = ((LLViewerObject*)mAvatarObject->getParent())->getRenderRotation();
- // slam agent coordinate frame to proper parent local version
- LLVector3 at_axis = mFrameAgent.getAtAxis() * parent_rot;
- at_axis.mV[VZ] = 0.f;
- at_axis.normalize();
- resetAxes(at_axis * ~parent_rot);
-
- local_camera_offset = local_camera_offset * mFrameAgent.getQuaternion() * parent_rot;
- }
- else
- {
- local_camera_offset = mFrameAgent.rotateToAbsolute( local_camera_offset );
- }
-
- if (!mCameraCollidePlane.isExactlyZero() && (mAvatarObject.isNull() || !mAvatarObject->mIsSitting))
- {
- LLVector3 plane_normal;
- plane_normal.setVec(mCameraCollidePlane.mV);
-
- F32 offset_dot_norm = local_camera_offset * plane_normal;
- if (llabs(offset_dot_norm) < 0.001f)
- {
- offset_dot_norm = 0.001f;
- }
-
- camera_distance = local_camera_offset.normalize();
-
- F32 pos_dot_norm = getPosAgentFromGlobal(frame_center_global + head_offset) * plane_normal;
-
- // if agent is outside the colliding half-plane
- if (pos_dot_norm > mCameraCollidePlane.mV[VW])
- {
- // check to see if camera is on the opposite side (inside) the half-plane
- if (offset_dot_norm + pos_dot_norm < mCameraCollidePlane.mV[VW])
- {
- // diminish offset by factor to push it back outside the half-plane
- camera_distance *= (pos_dot_norm - mCameraCollidePlane.mV[VW] - CAMERA_COLLIDE_EPSILON) / -offset_dot_norm;
- }
- }
- else
- {
- if (offset_dot_norm + pos_dot_norm > mCameraCollidePlane.mV[VW])
- {
- camera_distance *= (mCameraCollidePlane.mV[VW] - pos_dot_norm - CAMERA_COLLIDE_EPSILON) / offset_dot_norm;
- }
- }
- }
- else
- {
- camera_distance = local_camera_offset.normalize();
- }
-
- mTargetCameraDistance = llmax(camera_distance, MIN_CAMERA_DISTANCE);
-
- if (mTargetCameraDistance != mCurrentCameraDistance)
- {
- F32 camera_lerp_amt = LLCriticalDamp::getInterpolant(CAMERA_ZOOM_HALF_LIFE);
-
- mCurrentCameraDistance = lerp(mCurrentCameraDistance, mTargetCameraDistance, camera_lerp_amt);
- }
-
- // Make the camera distance current
- local_camera_offset *= mCurrentCameraDistance;
-
- // set the global camera position
- LLVector3d camera_offset;
-
- LLVector3 av_pos = mAvatarObject.isNull() ? LLVector3::zero : mAvatarObject->getRenderPosition();
- camera_offset.setVec( local_camera_offset );
- camera_position_global = frame_center_global + head_offset + camera_offset;
-
- if (mAvatarObject.notNull())
- {
- LLVector3d camera_lag_d;
- F32 lag_interp = LLCriticalDamp::getInterpolant(CAMERA_LAG_HALF_LIFE);
- LLVector3 target_lag;
- LLVector3 vel = getVelocity();
-
- // lag by appropriate amount for flying
- F32 time_in_air = mAvatarObject->mTimeInAir.getElapsedTimeF32();
- if(!mCameraAnimating && mAvatarObject->mInAir && time_in_air > GROUND_TO_AIR_CAMERA_TRANSITION_START_TIME)
- {
- LLVector3 frame_at_axis = mFrameAgent.getAtAxis();
- frame_at_axis -= projected_vec(frame_at_axis, getReferenceUpVector());
- frame_at_axis.normalize();
-
- //transition smoothly in air mode, to avoid camera pop
- F32 u = (time_in_air - GROUND_TO_AIR_CAMERA_TRANSITION_START_TIME) / GROUND_TO_AIR_CAMERA_TRANSITION_TIME;
- u = llclamp(u, 0.f, 1.f);
-
- lag_interp *= u;
-
- if (gViewerWindow->getLeftMouseDown() && gViewerWindow->getLastPick().mObjectID == mAvatarObject->getID())
- {
- // disable camera lag when using mouse-directed steering
- target_lag.clearVec();
- }
- else
- {
- target_lag = vel * gSavedSettings.getF32("DynamicCameraStrength") / 30.f;
- }
-
- mCameraLag = lerp(mCameraLag, target_lag, lag_interp);
-
- F32 lag_dist = mCameraLag.magVec();
- if (lag_dist > MAX_CAMERA_LAG)
- {
- mCameraLag = mCameraLag * MAX_CAMERA_LAG / lag_dist;
- }
-
- // clamp camera lag so that avatar is always in front
- F32 dot = (mCameraLag - (frame_at_axis * (MIN_CAMERA_LAG * u))) * frame_at_axis;
- if (dot < -(MIN_CAMERA_LAG * u))
- {
- mCameraLag -= (dot + (MIN_CAMERA_LAG * u)) * frame_at_axis;
- }
- }
- else
- {
- mCameraLag = lerp(mCameraLag, LLVector3::zero, LLCriticalDamp::getInterpolant(0.15f));
- }
-
- camera_lag_d.setVec(mCameraLag);
- camera_position_global = camera_position_global - camera_lag_d;
- }
- }
- }
- else
- {
- LLVector3d focusPosGlobal = calcFocusPositionTargetGlobal();
- // camera gets pushed out later wrt mCameraFOVZoomFactor...this is "raw" value
- camera_position_global = focusPosGlobal + mCameraFocusOffset;
- }
-
- if (!gSavedSettings.getBOOL("DisableCameraConstraints") && !gAgent.isGodlike())
- {
- LLViewerRegion* regionp = LLWorld::getInstance()->getRegionFromPosGlobal(
- camera_position_global);
- bool constrain = true;
- if(regionp && regionp->canManageEstate())
- {
- constrain = false;
- }
- if(constrain)
- {
- F32 max_dist = ( CAMERA_MODE_CUSTOMIZE_AVATAR == mCameraMode ) ?
- APPEARANCE_MAX_ZOOM : mDrawDistance;
-
- LLVector3d camera_offset = camera_position_global
- - gAgent.getPositionGlobal();
- F32 camera_distance = (F32)camera_offset.magVec();
-
- if(camera_distance > max_dist)
- {
- camera_position_global = gAgent.getPositionGlobal() +
- (max_dist / camera_distance) * camera_offset;
- isConstrained = TRUE;
- }
- }
-
-// JC - Could constrain camera based on parcel stuff here.
-// LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromPosGlobal(camera_position_global);
-//
-// if (regionp && !regionp->mParcelOverlay->isBuildCameraAllowed(regionp->getPosRegionFromGlobal(camera_position_global)))
-// {
-// camera_position_global = last_position_global;
-//
-// isConstrained = TRUE;
-// }
- }
-
- // Don't let camera go underground
- F32 camera_min_off_ground = getCameraMinOffGround();
-
- camera_land_height = LLWorld::getInstance()->resolveLandHeightGlobal(camera_position_global);
-
- if (camera_position_global.mdV[VZ] < camera_land_height + camera_min_off_ground)
- {
- camera_position_global.mdV[VZ] = camera_land_height + camera_min_off_ground;
- isConstrained = TRUE;
- }
-
-
- if (hit_limit)
- {
- *hit_limit = isConstrained;
- }
-
- return camera_position_global;
-}
-
-
-//-----------------------------------------------------------------------------
-// handleScrollWheel()
-//-----------------------------------------------------------------------------
-void LLAgent::handleScrollWheel(S32 clicks)
-{
- if ( mCameraMode == CAMERA_MODE_FOLLOW && gAgent.getFocusOnAvatar())
- {
- if ( ! mFollowCam.getPositionLocked() ) // not if the followCam position is locked in place
- {
- mFollowCam.zoom( clicks );
- if ( mFollowCam.isZoomedToMinimumDistance() )
- {
- changeCameraToMouselook(FALSE);
- }
- }
- }
- else
- {
- LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection();
- const F32 ROOT_ROOT_TWO = sqrt(F_SQRT2);
-
- // Block if camera is animating
- if (mCameraAnimating)
- {
- return;
- }
-
- if (selection->getObjectCount() && selection->getSelectType() == SELECT_TYPE_HUD)
- {
- F32 zoom_factor = (F32)pow(0.8, -clicks);
- cameraZoomIn(zoom_factor);
- }
- else if (mFocusOnAvatar && mCameraMode == CAMERA_MODE_THIRD_PERSON)
- {
- F32 current_zoom_fraction = mTargetCameraDistance / (mCameraOffsetDefault.magVec() * gSavedSettings.getF32("CameraOffsetScale"));
- current_zoom_fraction *= 1.f - pow(ROOT_ROOT_TWO, clicks);
-
- cameraOrbitIn(current_zoom_fraction * mCameraOffsetDefault.magVec() * gSavedSettings.getF32("CameraOffsetScale"));
- }
- else
- {
- F32 current_zoom_fraction = (F32)mCameraFocusOffsetTarget.magVec();
- cameraOrbitIn(current_zoom_fraction * (1.f - pow(ROOT_ROOT_TWO, clicks)));
- }
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// getCameraMinOffGround()
-//-----------------------------------------------------------------------------
-F32 LLAgent::getCameraMinOffGround()
-{
- if (mCameraMode == CAMERA_MODE_MOUSELOOK)
- {
- return 0.f;
- }
- else
- {
- if (gSavedSettings.getBOOL("DisableCameraConstraints"))
- {
- return -1000.f;
- }
- else
- {
- return 0.5f;
- }
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// resetCamera()
-//-----------------------------------------------------------------------------
-void LLAgent::resetCamera()
-{
- // Remove any pitch from the avatar
- LLVector3 at = mFrameAgent.getAtAxis();
- at.mV[VZ] = 0.f;
- at.normalize();
- gAgent.resetAxes(at);
- // have to explicitly clear field of view zoom now
- mCameraFOVZoomFactor = 0.f;
-
- updateCamera();
-}
-
-//-----------------------------------------------------------------------------
-// changeCameraToMouselook()
-//-----------------------------------------------------------------------------
-void LLAgent::changeCameraToMouselook(BOOL animate)
-{
- if (LLViewerJoystick::getInstance()->getOverrideCamera())
- {
- return;
- }
-
- // visibility changes at end of animation
- gViewerWindow->getWindow()->resetBusyCount();
-
- // Menus should not remain open on switching to mouselook...
- LLMenuGL::sMenuContainer->hideMenus();
-
- // unpause avatar animation
- mPauseRequest = NULL;
-
- LLToolMgr::getInstance()->setCurrentToolset(gMouselookToolset);
-
- gSavedSettings.setBOOL("FirstPersonBtnState", FALSE);
- gSavedSettings.setBOOL("MouselookBtnState", TRUE);
- gSavedSettings.setBOOL("ThirdPersonBtnState", FALSE);
- gSavedSettings.setBOOL("BuildBtnState", FALSE);
-
- if (mAvatarObject.notNull())
- {
- mAvatarObject->stopMotion( ANIM_AGENT_BODY_NOISE );
- mAvatarObject->stopMotion( ANIM_AGENT_BREATHE_ROT );
- }
-
- //gViewerWindow->stopGrab();
- LLSelectMgr::getInstance()->deselectAll();
- gViewerWindow->hideCursor();
- gViewerWindow->moveCursorToCenter();
-
- if( mCameraMode != CAMERA_MODE_MOUSELOOK )
- {
- gFocusMgr.setKeyboardFocus( NULL );
-
- mLastCameraMode = mCameraMode;
- mCameraMode = CAMERA_MODE_MOUSELOOK;
- U32 old_flags = mControlFlags;
- setControlFlags(AGENT_CONTROL_MOUSELOOK);
- if (old_flags != mControlFlags)
- {
- mbFlagsDirty = TRUE;
- }
-
- if (animate)
- {
- startCameraAnimation();
- }
- else
- {
- mCameraAnimating = FALSE;
- endAnimationUpdateUI();
- }
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// changeCameraToDefault()
-//-----------------------------------------------------------------------------
-void LLAgent::changeCameraToDefault()
-{
- if (LLViewerJoystick::getInstance()->getOverrideCamera())
- {
- return;
- }
-
- if (LLFollowCamMgr::getActiveFollowCamParams())
- {
- changeCameraToFollow();
- }
- else
- {
- changeCameraToThirdPerson();
- }
-}
-
-
-// Ventrella
-//-----------------------------------------------------------------------------
-// changeCameraToFollow()
-//-----------------------------------------------------------------------------
-void LLAgent::changeCameraToFollow(BOOL animate)
-{
- if (LLViewerJoystick::getInstance()->getOverrideCamera())
- {
- return;
- }
-
- if( mCameraMode != CAMERA_MODE_FOLLOW )
- {
- if (mCameraMode == CAMERA_MODE_MOUSELOOK)
- {
- animate = FALSE;
- }
- startCameraAnimation();
-
- mLastCameraMode = mCameraMode;
- mCameraMode = CAMERA_MODE_FOLLOW;
-
- // bang-in the current focus, position, and up vector of the follow cam
- mFollowCam.reset( mCameraPositionAgent, LLViewerCamera::getInstance()->getPointOfInterest(), LLVector3::z_axis );
-
- if (gBasicToolset)
- {
- LLToolMgr::getInstance()->setCurrentToolset(gBasicToolset);
- }
-
- if (mAvatarObject.notNull())
- {
- mAvatarObject->mPelvisp->setPosition(LLVector3::zero);
- mAvatarObject->startMotion( ANIM_AGENT_BODY_NOISE );
- mAvatarObject->startMotion( ANIM_AGENT_BREATHE_ROT );
- }
-
- gSavedSettings.setBOOL("FirstPersonBtnState", FALSE);
- gSavedSettings.setBOOL("MouselookBtnState", FALSE);
- gSavedSettings.setBOOL("ThirdPersonBtnState", TRUE);
- gSavedSettings.setBOOL("BuildBtnState", FALSE);
-
- // unpause avatar animation
- mPauseRequest = NULL;
-
- U32 old_flags = mControlFlags;
- clearControlFlags(AGENT_CONTROL_MOUSELOOK);
- if (old_flags != mControlFlags)
- {
- mbFlagsDirty = TRUE;
- }
-
- if (animate)
- {
- startCameraAnimation();
- }
- else
- {
- mCameraAnimating = FALSE;
- endAnimationUpdateUI();
- }
- }
-}
-
-//-----------------------------------------------------------------------------
-// changeCameraToThirdPerson()
-//-----------------------------------------------------------------------------
-void LLAgent::changeCameraToThirdPerson(BOOL animate)
-{
- if (LLViewerJoystick::getInstance()->getOverrideCamera())
- {
- return;
- }
-
- gViewerWindow->getWindow()->resetBusyCount();
-
- mCameraZoomFraction = INITIAL_ZOOM_FRACTION;
-
- if (mAvatarObject.notNull())
- {
- if (!mAvatarObject->mIsSitting)
- {
- mAvatarObject->mPelvisp->setPosition(LLVector3::zero);
- }
- mAvatarObject->startMotion( ANIM_AGENT_BODY_NOISE );
- mAvatarObject->startMotion( ANIM_AGENT_BREATHE_ROT );
- }
-
- gSavedSettings.setBOOL("FirstPersonBtnState", FALSE);
- gSavedSettings.setBOOL("MouselookBtnState", FALSE);
- gSavedSettings.setBOOL("ThirdPersonBtnState", TRUE);
- gSavedSettings.setBOOL("BuildBtnState", FALSE);
-
- LLVector3 at_axis;
-
- // unpause avatar animation
- mPauseRequest = NULL;
-
- if( mCameraMode != CAMERA_MODE_THIRD_PERSON )
- {
- if (gBasicToolset)
- {
- LLToolMgr::getInstance()->setCurrentToolset(gBasicToolset);
- }
-
- mCameraLag.clearVec();
- if (mCameraMode == CAMERA_MODE_MOUSELOOK)
- {
- mCurrentCameraDistance = MIN_CAMERA_DISTANCE;
- mTargetCameraDistance = MIN_CAMERA_DISTANCE;
- animate = FALSE;
- }
- mLastCameraMode = mCameraMode;
- mCameraMode = CAMERA_MODE_THIRD_PERSON;
- U32 old_flags = mControlFlags;
- clearControlFlags(AGENT_CONTROL_MOUSELOOK);
- if (old_flags != mControlFlags)
- {
- mbFlagsDirty = TRUE;
- }
-
- }
-
- // Remove any pitch from the avatar
- if (mAvatarObject.notNull() && mAvatarObject->getParent())
- {
- LLQuaternion obj_rot = ((LLViewerObject*)mAvatarObject->getParent())->getRenderRotation();
- at_axis = LLViewerCamera::getInstance()->getAtAxis();
- at_axis.mV[VZ] = 0.f;
- at_axis.normalize();
- resetAxes(at_axis * ~obj_rot);
- }
- else
- {
- at_axis = mFrameAgent.getAtAxis();
- at_axis.mV[VZ] = 0.f;
- at_axis.normalize();
- resetAxes(at_axis);
- }
-
-
- if (animate)
- {
- startCameraAnimation();
- }
- else
- {
- mCameraAnimating = FALSE;
- endAnimationUpdateUI();
- }
-}
-
-//-----------------------------------------------------------------------------
-// changeCameraToCustomizeAvatar()
-//-----------------------------------------------------------------------------
-void LLAgent::changeCameraToCustomizeAvatar(BOOL avatar_animate, BOOL camera_animate)
-{
- if (LLViewerJoystick::getInstance()->getOverrideCamera())
- {
- return;
- }
-
- //
- //setControlFlags(AGENT_CONTROL_STAND_UP); // force stand up
- //
- gViewerWindow->getWindow()->resetBusyCount();
-
- if (gFaceEditToolset)
- {
- LLToolMgr::getInstance()->setCurrentToolset(gFaceEditToolset);
- }
-
- gSavedSettings.setBOOL("FirstPersonBtnState", FALSE);
- gSavedSettings.setBOOL("MouselookBtnState", FALSE);
- gSavedSettings.setBOOL("ThirdPersonBtnState", FALSE);
- gSavedSettings.setBOOL("BuildBtnState", FALSE);
-
- if (camera_animate)
- {
- //
- if(gSavedSettings.getBOOL("AppearanceCameraMovement"))
- //
- startCameraAnimation();
- }
-
- // Remove any pitch from the avatar
- //LLVector3 at = mFrameAgent.getAtAxis();
- //at.mV[VZ] = 0.f;
- //at.normalize();
- //gAgent.resetAxes(at);
-
- if( mCameraMode != CAMERA_MODE_CUSTOMIZE_AVATAR )
- {
- mLastCameraMode = mCameraMode;
- mCameraMode = CAMERA_MODE_CUSTOMIZE_AVATAR;
- U32 old_flags = mControlFlags;
- clearControlFlags(AGENT_CONTROL_MOUSELOOK);
- if (old_flags != mControlFlags)
- {
- mbFlagsDirty = TRUE;
- }
-
- gFocusMgr.setKeyboardFocus( NULL );
- gFocusMgr.setMouseCapture( NULL );
-
- LLVOAvatar::onCustomizeStart();
- }
-
- if (mAvatarObject.notNull())
- {
- if(avatar_animate)
- {
- // Remove any pitch from the avatar
- LLVector3 at = mFrameAgent.getAtAxis();
- at.mV[VZ] = 0.f;
- at.normalize();
- gAgent.resetAxes(at);
-
- sendAnimationRequest(ANIM_AGENT_CUSTOMIZE, ANIM_REQUEST_START);
- mCustomAnim = TRUE ;
- mAvatarObject->startMotion(ANIM_AGENT_CUSTOMIZE);
- LLMotion* turn_motion = mAvatarObject->findMotion(ANIM_AGENT_CUSTOMIZE);
-
- if (turn_motion)
- {
- mAnimationDuration = turn_motion->getDuration() + CUSTOMIZE_AVATAR_CAMERA_ANIM_SLOP;
-
- }
- else
- {
- mAnimationDuration = gSavedSettings.getF32("ZoomTime");
- }
- }
-
-
-
- gAgent.setFocusGlobal(LLVector3d::zero);
- }
- else
- {
- mCameraAnimating = FALSE;
- endAnimationUpdateUI();
- }
-
- //
- if(!gSavedSettings.getBOOL("AppearanceCameraMovement"))
- {
- //hmm
- mCameraAnimating = FALSE;
- endAnimationUpdateUI();
- }
-
-}
-
-
-//
-// Focus point management
-//
-
-//-----------------------------------------------------------------------------
-// startCameraAnimation()
-//-----------------------------------------------------------------------------
-void LLAgent::startCameraAnimation()
-{
- mAnimationCameraStartGlobal = getCameraPositionGlobal();
- mAnimationFocusStartGlobal = mFocusGlobal;
- mAnimationTimer.reset();
- mCameraAnimating = TRUE;
- mAnimationDuration = gSavedSettings.getF32("ZoomTime");
-}
-
-//-----------------------------------------------------------------------------
-// stopCameraAnimation()
-//-----------------------------------------------------------------------------
-void LLAgent::stopCameraAnimation()
-{
- mCameraAnimating = FALSE;
-}
-
-void LLAgent::clearFocusObject()
-{
- if (mFocusObject.notNull())
- {
- startCameraAnimation();
-
- setFocusObject(NULL);
- mFocusObjectOffset.clearVec();
- }
-}
-
-void LLAgent::setFocusObject(LLViewerObject* object)
-{
- mFocusObject = object;
-}
-
-// Focus on a point, but try to keep camera position stable.
-//-----------------------------------------------------------------------------
-// setFocusGlobal()
-//-----------------------------------------------------------------------------
-void LLAgent::setFocusGlobal(const LLPickInfo& pick)
-{
- LLViewerObject* objectp = gObjectList.findObject(pick.mObjectID);
-
- if (objectp)
- {
- // focus on object plus designated offset
- // which may or may not be same as pick.mPosGlobal
- setFocusGlobal(objectp->getPositionGlobal() + LLVector3d(pick.mObjectOffset), pick.mObjectID);
- }
- else
- {
- // focus directly on point where user clicked
- setFocusGlobal(pick.mPosGlobal, pick.mObjectID);
- }
-}
-
-
-void LLAgent::setFocusGlobal(const LLVector3d& focus, const LLUUID &object_id)
-{
- setFocusObject(gObjectList.findObject(object_id));
- LLVector3d old_focus = mFocusTargetGlobal;
- LLViewerObject *focus_obj = mFocusObject;
-
- // if focus has changed
- if (old_focus != focus)
- {
- if (focus.isExactlyZero())
- {
- if (mAvatarObject.notNull())
- {
- mFocusTargetGlobal = getPosGlobalFromAgent(mAvatarObject->mHeadp->getWorldPosition());
- }
- else
- {
- mFocusTargetGlobal = getPositionGlobal();
- }
- mCameraFocusOffsetTarget = getCameraPositionGlobal() - mFocusTargetGlobal;
- mCameraFocusOffset = mCameraFocusOffsetTarget;
- setLookAt(LOOKAT_TARGET_CLEAR);
- }
- else
- {
- mFocusTargetGlobal = focus;
- if (!focus_obj)
- {
- mCameraFOVZoomFactor = 0.f;
- }
-
- mCameraFocusOffsetTarget = gAgent.getPosGlobalFromAgent(mCameraVirtualPositionAgent) - mFocusTargetGlobal;
-
- startCameraAnimation();
-
- if (focus_obj)
- {
- if (focus_obj->isAvatar())
- {
- setLookAt(LOOKAT_TARGET_FOCUS, focus_obj);
- }
- else
- {
- setLookAt(LOOKAT_TARGET_FOCUS, focus_obj, (getPosAgentFromGlobal(focus) - focus_obj->getRenderPosition()) * ~focus_obj->getRenderRotation());
- }
- }
- else
- {
- setLookAt(LOOKAT_TARGET_FOCUS, NULL, getPosAgentFromGlobal(mFocusTargetGlobal));
- }
- }
- }
- else // focus == mFocusTargetGlobal
- {
- if (focus.isExactlyZero())
- {
- if (mAvatarObject.notNull())
- {
- mFocusTargetGlobal = getPosGlobalFromAgent(mAvatarObject->mHeadp->getWorldPosition());
- }
- else
- {
- mFocusTargetGlobal = getPositionGlobal();
- }
- }
- mCameraFocusOffsetTarget = (getCameraPositionGlobal() - mFocusTargetGlobal) / (1.f + mCameraFOVZoomFactor);;
- mCameraFocusOffset = mCameraFocusOffsetTarget;
- }
-
- if (mFocusObject.notNull())
- {
- // for attachments, make offset relative to avatar, not the attachment
- if (mFocusObject->isAttachment())
- {
- while (mFocusObject.notNull() // DEV-29123 - can crash with a messed-up attachment
- && !mFocusObject->isAvatar())
- {
- mFocusObject = (LLViewerObject*) mFocusObject->getParent();
- }
- setFocusObject((LLViewerObject*)mFocusObject);
- }
- updateFocusOffset();
- }
-}
-
-// Used for avatar customization
-//-----------------------------------------------------------------------------
-// setCameraPosAndFocusGlobal()
-//-----------------------------------------------------------------------------
-void LLAgent::setCameraPosAndFocusGlobal(const LLVector3d& camera_pos, const LLVector3d& focus, const LLUUID &object_id)
-{
- LLVector3d old_focus = mFocusTargetGlobal;
-
- F64 focus_delta_squared = (old_focus - focus).magVecSquared();
- const F64 ANIM_EPSILON_SQUARED = 0.0001;
- if( focus_delta_squared > ANIM_EPSILON_SQUARED )
- {
- startCameraAnimation();
-
- if( CAMERA_MODE_CUSTOMIZE_AVATAR == mCameraMode )
- {
- // Compensate for the fact that the camera has already been offset to make room for LLFloaterCustomize.
- mAnimationCameraStartGlobal -= LLVector3d(LLViewerCamera::getInstance()->getLeftAxis() * calcCustomizeAvatarUIOffset( mAnimationCameraStartGlobal ));
- }
- }
-
- //LLViewerCamera::getInstance()->setOrigin( gAgent.getPosAgentFromGlobal( camera_pos ) );
- setFocusObject(gObjectList.findObject(object_id));
- mFocusTargetGlobal = focus;
- mCameraFocusOffsetTarget = camera_pos - focus;
- mCameraFocusOffset = mCameraFocusOffsetTarget;
-
- if (mFocusObject)
- {
- if (mFocusObject->isAvatar())
- {
- setLookAt(LOOKAT_TARGET_FOCUS, mFocusObject);
- }
- else
- {
- setLookAt(LOOKAT_TARGET_FOCUS, mFocusObject, (getPosAgentFromGlobal(focus) - mFocusObject->getRenderPosition()) * ~mFocusObject->getRenderRotation());
- }
- }
- else
- {
- setLookAt(LOOKAT_TARGET_FOCUS, NULL, getPosAgentFromGlobal(mFocusTargetGlobal));
- }
-
- if( mCameraAnimating )
- {
- const F64 ANIM_METERS_PER_SECOND = 10.0;
- const F64 MIN_ANIM_SECONDS = 0.5;
- F64 anim_duration = llmax( MIN_ANIM_SECONDS, sqrt(focus_delta_squared) / ANIM_METERS_PER_SECOND );
- setAnimationDuration( (F32)anim_duration );
- }
-
- updateFocusOffset();
-}
-
-//-----------------------------------------------------------------------------
-// setSitCamera()
-//-----------------------------------------------------------------------------
-void LLAgent::setSitCamera(const LLUUID &object_id, const LLVector3 &camera_pos, const LLVector3 &camera_focus)
-{
- BOOL camera_enabled = !object_id.isNull();
-
- if (camera_enabled)
- {
- LLViewerObject *reference_object = gObjectList.findObject(object_id);
- if (reference_object)
- {
- //convert to root object relative?
- mSitCameraPos = camera_pos;
- mSitCameraFocus = camera_focus;
- mSitCameraReferenceObject = reference_object;
- mSitCameraEnabled = TRUE;
- }
- }
- else
- {
- mSitCameraPos.clearVec();
- mSitCameraFocus.clearVec();
- mSitCameraReferenceObject = NULL;
- mSitCameraEnabled = FALSE;
- }
-}
-
-//-----------------------------------------------------------------------------
-// setFocusOnAvatar()
-//-----------------------------------------------------------------------------
-void LLAgent::setFocusOnAvatar(BOOL focus_on_avatar, BOOL animate)
-{
- if (focus_on_avatar != mFocusOnAvatar)
- {
- if (animate)
- {
- startCameraAnimation();
- }
- else
- {
- stopCameraAnimation();
- }
- }
-
- //RN: when focused on the avatar, we're not "looking" at it
- // looking implies intent while focusing on avatar means
- // you're just walking around with a camera on you...eesh.
- if (!mFocusOnAvatar && focus_on_avatar)
- {
- setFocusGlobal(LLVector3d::zero);
- mCameraFOVZoomFactor = 0.f;
- if (mCameraMode == CAMERA_MODE_THIRD_PERSON)
- {
- LLVector3 at_axis;
- if (mAvatarObject.notNull() && mAvatarObject->getParent())
- {
- LLQuaternion obj_rot = ((LLViewerObject*)mAvatarObject->getParent())->getRenderRotation();
- at_axis = LLViewerCamera::getInstance()->getAtAxis();
- at_axis.mV[VZ] = 0.f;
- at_axis.normalize();
- resetAxes(at_axis * ~obj_rot);
- }
- else
- {
- at_axis = LLViewerCamera::getInstance()->getAtAxis();
- at_axis.mV[VZ] = 0.f;
- at_axis.normalize();
- resetAxes(at_axis);
- }
- }
- }
- // unlocking camera from avatar
- else if (mFocusOnAvatar && !focus_on_avatar)
- {
- // keep camera focus point consistent, even though it is now unlocked
- setFocusGlobal(getPositionGlobal() + calcThirdPersonFocusOffset(), gAgent.getID());
- }
-
- mFocusOnAvatar = focus_on_avatar;
-}
-
-//-----------------------------------------------------------------------------
-// heardChat()
-//-----------------------------------------------------------------------------
-void LLAgent::heardChat(const LLUUID& id)
-{
- // log text and voice chat to speaker mgr
- // for keeping track of active speakers, etc.
- LLLocalSpeakerMgr::getInstance()->speakerChatted(id);
-
- // don't respond to your own voice
- if (id == getID()) return;
-
- if (ll_rand(2) == 0)
- {
- LLViewerObject *chatter = gObjectList.findObject(mLastChatterID);
- setLookAt(LOOKAT_TARGET_AUTO_LISTEN, chatter, LLVector3::zero);
- }
-
- mLastChatterID = id;
- mChatTimer.reset();
-}
-
-//-----------------------------------------------------------------------------
-// lookAtLastChat()
-//-----------------------------------------------------------------------------
-void LLAgent::lookAtLastChat()
-{
- // Block if camera is animating or not in normal third person camera mode
- if (mCameraAnimating || !cameraThirdPerson())
- {
- return;
- }
-
- LLViewerObject *chatter = gObjectList.findObject(mLastChatterID);
- if (chatter)
- {
- LLVector3 delta_pos;
- if (chatter->isAvatar())
- {
- LLVOAvatar *chatter_av = (LLVOAvatar*)chatter;
- if (mAvatarObject.notNull() && chatter_av->mHeadp)
- {
- delta_pos = chatter_av->mHeadp->getWorldPosition() - mAvatarObject->mHeadp->getWorldPosition();
- }
- else
- {
- delta_pos = chatter->getPositionAgent() - getPositionAgent();
- }
- delta_pos.normalize();
-
- setControlFlags(AGENT_CONTROL_STOP);
-
- changeCameraToThirdPerson();
-
- LLVector3 new_camera_pos = mAvatarObject->mHeadp->getWorldPosition();
- LLVector3 left = delta_pos % LLVector3::z_axis;
- left.normalize();
- LLVector3 up = left % delta_pos;
- up.normalize();
- new_camera_pos -= delta_pos * 0.4f;
- new_camera_pos += left * 0.3f;
- new_camera_pos += up * 0.2f;
- if (chatter_av->mHeadp)
- {
- setFocusGlobal(getPosGlobalFromAgent(chatter_av->mHeadp->getWorldPosition()), mLastChatterID);
- mCameraFocusOffsetTarget = getPosGlobalFromAgent(new_camera_pos) - gAgent.getPosGlobalFromAgent(chatter_av->mHeadp->getWorldPosition());
- }
- else
- {
- setFocusGlobal(chatter->getPositionGlobal(), mLastChatterID);
- mCameraFocusOffsetTarget = getPosGlobalFromAgent(new_camera_pos) - chatter->getPositionGlobal();
- }
- setFocusOnAvatar(FALSE, TRUE);
- }
- else
- {
- delta_pos = chatter->getRenderPosition() - getPositionAgent();
- delta_pos.normalize();
-
- setControlFlags(AGENT_CONTROL_STOP);
-
- changeCameraToThirdPerson();
-
- LLVector3 new_camera_pos = mAvatarObject->mHeadp->getWorldPosition();
- LLVector3 left = delta_pos % LLVector3::z_axis;
- left.normalize();
- LLVector3 up = left % delta_pos;
- up.normalize();
- new_camera_pos -= delta_pos * 0.4f;
- new_camera_pos += left * 0.3f;
- new_camera_pos += up * 0.2f;
-
- setFocusGlobal(chatter->getPositionGlobal(), mLastChatterID);
- mCameraFocusOffsetTarget = getPosGlobalFromAgent(new_camera_pos) - chatter->getPositionGlobal();
- setFocusOnAvatar(FALSE, TRUE);
- }
- }
-}
-
-void LLAgent::lookAtObject(LLUUID object_id, ECameraPosition camera_pos)
-{
- // Block if camera is animating or not in normal third person camera mode
- if (mCameraAnimating || !cameraThirdPerson())
- {
- return;
- }
-
- LLViewerObject *chatter = gObjectList.findObject(object_id);
- if (chatter)
- {
- LLVector3 delta_pos;
- if (chatter->isAvatar())
- {
- LLVOAvatar *chatter_av = (LLVOAvatar*)chatter;
- if (!mAvatarObject.isNull() && chatter_av->mHeadp)
- {
- delta_pos = chatter_av->mHeadp->getWorldPosition() - mAvatarObject->mHeadp->getWorldPosition();
- }
- else
- {
- delta_pos = chatter->getPositionAgent() - getPositionAgent();
- }
- delta_pos.normVec();
-
- setControlFlags(AGENT_CONTROL_STOP);
-
- changeCameraToThirdPerson();
-
- LLVector3 new_camera_pos = mAvatarObject->mHeadp->getWorldPosition();
- LLVector3 left = delta_pos % LLVector3::z_axis;
- left.normVec();
- LLVector3 up = left % delta_pos;
- up.normVec();
- new_camera_pos -= delta_pos * 0.4f;
- new_camera_pos += left * 0.3f;
- new_camera_pos += up * 0.2f;
-
- F32 radius = chatter_av->getVObjRadius();
- LLVector3d view_dist(radius, radius, 0.0f);
-
- if (chatter_av->mHeadp)
- {
- setFocusGlobal(getPosGlobalFromAgent(chatter_av->mHeadp->getWorldPosition()), object_id);
- mCameraFocusOffsetTarget = getPosGlobalFromAgent(new_camera_pos) - gAgent.getPosGlobalFromAgent(chatter_av->mHeadp->getWorldPosition());
-
- switch(camera_pos)
- {
- case CAMERA_POSITION_SELF:
- mCameraFocusOffsetTarget = getPosGlobalFromAgent(new_camera_pos) - gAgent.getPosGlobalFromAgent(chatter_av->mHeadp->getWorldPosition());
- break;
- case CAMERA_POSITION_OBJECT:
- mCameraFocusOffsetTarget = view_dist;
- break;
- }
- }
- else
- {
- setFocusGlobal(chatter->getPositionGlobal(), object_id);
- mCameraFocusOffsetTarget = getPosGlobalFromAgent(new_camera_pos) - chatter->getPositionGlobal();
-
- switch(camera_pos)
- {
- case CAMERA_POSITION_SELF:
- mCameraFocusOffsetTarget = getPosGlobalFromAgent(new_camera_pos) - chatter->getPositionGlobal();
- break;
- case CAMERA_POSITION_OBJECT:
- mCameraFocusOffsetTarget = view_dist;
- break;
- }
- }
- setFocusOnAvatar(FALSE, TRUE);
- }
- else
- {
- delta_pos = chatter->getRenderPosition() - getPositionAgent();
- delta_pos.normVec();
-
- setControlFlags(AGENT_CONTROL_STOP);
-
- changeCameraToThirdPerson();
-
- LLVector3 new_camera_pos = mAvatarObject->mHeadp->getWorldPosition();
- LLVector3 left = delta_pos % LLVector3::z_axis;
- left.normVec();
- LLVector3 up = left % delta_pos;
- up.normVec();
- new_camera_pos -= delta_pos * 0.4f;
- new_camera_pos += left * 0.3f;
- new_camera_pos += up * 0.2f;
-
- setFocusGlobal(chatter->getPositionGlobal(), object_id);
-
- switch(camera_pos)
- {
- case CAMERA_POSITION_SELF:
- mCameraFocusOffsetTarget = getPosGlobalFromAgent(new_camera_pos) - chatter->getPositionGlobal();
- break;
- case CAMERA_POSITION_OBJECT:
- F32 radius = chatter->getVObjRadius();
- LLVector3d view_dist(radius, radius, 0.0f);
- mCameraFocusOffsetTarget = view_dist;
- break;
- }
-
- setFocusOnAvatar(FALSE, TRUE);
- }
- }
-}
-
-const F32 SIT_POINT_EXTENTS = 0.2f;
-
-void LLAgent::setStartPosition( U32 location_id )
-{
- LLViewerObject *object;
-
- if ( !(gAgentID == LLUUID::null) )
- {
- // we've got an ID for an agent viewerobject
- object = gObjectList.findObject(gAgentID);
- if (object)
- {
- // we've got the viewer object
- // Sometimes the agent can be velocity interpolated off of
- // this simulator. Clamp it to the region the agent is
- // in, a little bit in on each side.
- const F32 INSET = 0.5f; //meters
- const F32 REGION_WIDTH = LLWorld::getInstance()->getRegionWidthInMeters();
-
- LLVector3 agent_pos = getPositionAgent();
- LLVector3 agent_look_at = mFrameAgent.getAtAxis();
-
- if (mAvatarObject.notNull())
- {
- // the z height is at the agent's feet
- agent_pos.mV[VZ] -= 0.5f * mAvatarObject->mBodySize.mV[VZ];
- }
-
- agent_pos.mV[VX] = llclamp( agent_pos.mV[VX], INSET, REGION_WIDTH - INSET );
- agent_pos.mV[VY] = llclamp( agent_pos.mV[VY], INSET, REGION_WIDTH - INSET );
-
- // Don't let them go below ground, or too high.
- agent_pos.mV[VZ] = llclamp( agent_pos.mV[VZ],
- mRegionp->getLandHeightRegion( agent_pos ),
- LLWorld::getInstance()->getRegionMaxHeight() );
- // Send the CapReq
-
- LLSD body;
-
- std::string url = gAgent.getRegion()->getCapability("HomeLocation");
- std::ostringstream strBuffer;
- if( url.empty() )
- {
- LLMessageSystem* msg = gMessageSystem;
- msg->newMessageFast(_PREHASH_SetStartLocationRequest);
- msg->nextBlockFast( _PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, getID());
- msg->addUUIDFast(_PREHASH_SessionID, getSessionID());
- msg->nextBlockFast( _PREHASH_StartLocationData);
- // corrected by sim
- msg->addStringFast(_PREHASH_SimName, "");
- msg->addU32Fast(_PREHASH_LocationID, location_id);
- msg->addVector3Fast(_PREHASH_LocationPos, agent_pos);
- msg->addVector3Fast(_PREHASH_LocationLookAt,mFrameAgent.getAtAxis());
-
- // Reliable only helps when setting home location. Last
- // location is sent on quit, and we don't have time to ack
- // the packets.
- msg->sendReliable(mRegionp->getHost());
-
- const U32 HOME_INDEX = 1;
- if( HOME_INDEX == location_id )
- {
- setHomePosRegion( mRegionp->getHandle(), getPositionAgent() );
- }
- }
- else
- {
- strBuffer << location_id;
- body["HomeLocation"]["LocationId"] = strBuffer.str();
-
- strBuffer.str("");
- strBuffer << agent_pos.mV[VX];
- body["HomeLocation"]["LocationPos"]["X"] = strBuffer.str();
-
- strBuffer.str("");
- strBuffer << agent_pos.mV[VY];
- body["HomeLocation"]["LocationPos"]["Y"] = strBuffer.str();
-
- strBuffer.str("");
- strBuffer << agent_pos.mV[VZ];
- body["HomeLocation"]["LocationPos"]["Z"] = strBuffer.str();
-
- strBuffer.str("");
- strBuffer << agent_look_at.mV[VX];
- body["HomeLocation"]["LocationLookAt"]["X"] = strBuffer.str();
-
- strBuffer.str("");
- strBuffer << agent_look_at.mV[VY];
- body["HomeLocation"]["LocationLookAt"]["Y"] = strBuffer.str();
-
- strBuffer.str("");
- strBuffer << agent_look_at.mV[VZ];
- body["HomeLocation"]["LocationLookAt"]["Z"] = strBuffer.str();
-
- LLHTTPClient::post( url, body, new LLHomeLocationResponder() );
- }
- }
- else
- {
- llinfos << "setStartPosition - Can't find agent viewerobject id " << gAgentID << llendl;
- }
- }
-}
-
-void LLAgent::requestStopMotion( LLMotion* motion )
-{
- // Notify all avatars that a motion has stopped.
- // This is needed to clear the animation state bits
- LLUUID anim_state = motion->getID();
- onAnimStop(motion->getID());
-
- // if motion is not looping, it could have stopped by running out of time
- // so we need to tell the server this
-// llinfos << "Sending stop for motion " << motion->getName() << llendl;
- sendAnimationRequest( anim_state, ANIM_REQUEST_STOP );
-}
-
-void LLAgent::onAnimStop(const LLUUID& id)
-{
- // handle automatic state transitions (based on completion of animation playback)
- if(id == ANIM_AGENT_STAND
- //
- // I really do not like doing this
- || id == ANIM_AGENT_STAND_1
- || id == ANIM_AGENT_STAND_2
- || id == ANIM_AGENT_STAND_3
- || id == ANIM_AGENT_STAND_4)
- //
- {
- //
- if(LLAO::isEnabled())
- LLAO::mTimer->pause();//Timer only pauses if its not paused, check is inside function.
- //
- stopFidget();
- }
- else if (id == ANIM_AGENT_AWAY)
- {
- clearAFK();
- }
- else if (id == ANIM_AGENT_STANDUP)
- {
- // send stand up command
- setControlFlags(AGENT_CONTROL_FINISH_ANIM);
-
- // now trigger dusting self off animation
- if (mAvatarObject.notNull() && !mAvatarObject->mBelowWater && rand() % 3 == 0)
- sendAnimationRequest( ANIM_AGENT_BRUSH, ANIM_REQUEST_START );
- }
- else if (id == ANIM_AGENT_PRE_JUMP || id == ANIM_AGENT_LAND || id == ANIM_AGENT_MEDIUM_LAND)
- {
- setControlFlags(AGENT_CONTROL_FINISH_ANIM);
- }
-}
-
-BOOL LLAgent::isGodlike() const
-{
- return mAgentAccess.isGodlike();
-}
-
-U8 LLAgent::getGodLevel() const
-{
- return mAgentAccess.getGodLevel();
-}
-
-bool LLAgent::wantsPGOnly() const
-{
- return mAgentAccess.wantsPGOnly();
-}
-
-bool LLAgent::canAccessMature() const
-{
- return mAgentAccess.canAccessMature();
-}
-
-bool LLAgent::canAccessAdult() const
-{
- return mAgentAccess.canAccessAdult();
-}
-
-bool LLAgent::canAccessMaturityInRegion( U64 region_handle ) const
-{
- LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle( region_handle );
- if( regionp )
- {
- switch( regionp->getSimAccess() )
- {
- case SIM_ACCESS_MATURE:
- if( !canAccessMature() )
- return false;
- break;
- case SIM_ACCESS_ADULT:
- if( !canAccessAdult() )
- return false;
- break;
- default:
- // Oh, go on and hear the silly noises.
- break;
- }
- }
-
- return true;
-}
-
-bool LLAgent::canAccessMaturityAtGlobal( LLVector3d pos_global ) const
-{
- U64 region_handle = to_region_handle_global( pos_global.mdV[0], pos_global.mdV[1] );
- return canAccessMaturityInRegion( region_handle );
-}
-
-bool LLAgent::prefersPG() const
-{
- return mAgentAccess.prefersPG();
-}
-
-bool LLAgent::prefersMature() const
-{
- return mAgentAccess.prefersMature();
-}
-
-bool LLAgent::prefersAdult() const
-{
- return mAgentAccess.prefersAdult();
-}
-
-bool LLAgent::isTeen() const
-{
- return mAgentAccess.isTeen();
-}
-
-bool LLAgent::isMature() const
-{
- return mAgentAccess.isMature();
-}
-
-bool LLAgent::isAdult() const
-{
- return mAgentAccess.isAdult();
-}
-
-void LLAgent::setTeen(bool teen)
-{
- mAgentAccess.setTeen(teen);
-}
-
-//static
-int LLAgent::convertTextToMaturity(char text)
-{
- return LLAgentAccess::convertTextToMaturity(text);
-}
-
-bool LLAgent::sendMaturityPreferenceToServer(int preferredMaturity)
-{
- // Update agent access preference on the server
- std::string url = getRegion()->getCapability("UpdateAgentInformation");
- if (!url.empty())
- {
- // Set new access preference
- LLSD access_prefs = LLSD::emptyMap();
- if (preferredMaturity == SIM_ACCESS_PG)
- {
- access_prefs["max"] = "PG";
- }
- else if (preferredMaturity == SIM_ACCESS_MATURE)
- {
- access_prefs["max"] = "M";
- }
- if (preferredMaturity == SIM_ACCESS_ADULT)
- {
- access_prefs["max"] = "A";
- }
-
- LLSD body = LLSD::emptyMap();
- body["access_prefs"] = access_prefs;
- llinfos << "Sending access prefs update to " << (access_prefs["max"].asString()) << " via capability to: "
- << url << llendl;
- LLHTTPClient::post(url, body, new LLHTTPClient::Responder()); // Ignore response
- return true;
- }
- return false;
-}
-
-BOOL LLAgent::getAdminOverride() const
-{
- return mAgentAccess.getAdminOverride();
-}
-
-void LLAgent::setMaturity(char text)
-{
- mAgentAccess.setMaturity(text);
-}
-
-void LLAgent::setAdminOverride(BOOL b)
-{
- mAgentAccess.setAdminOverride(b);
-}
-
-void LLAgent::setGodLevel(U8 god_level)
-{
- mAgentAccess.setGodLevel(god_level);
-}
-
-void LLAgent::setAOTransition()
-{
- mAgentAccess.setTransition();
-}
-
-const LLAgentAccess& LLAgent::getAgentAccess()
-{
- return mAgentAccess;
-}
-
-
-void LLAgent::buildFullname(std::string& name) const
-{
- if (mAvatarObject.notNull())
- {
- name = mAvatarObject->getFullname();
- }
-}
-
-void LLAgent::buildFullnameAndTitle(std::string& name) const
-{
- if (isGroupMember())
- {
- name = mGroupTitle;
- name += ' ';
- }
- else
- {
- name.erase(0, name.length());
- }
-
- if (mAvatarObject.notNull())
- {
- name += mAvatarObject->getFullname();
- }
-}
-
-BOOL LLAgent::isInGroup(const LLUUID& group_id) const
-{
- if (isGodlike())
- return true;
-
- S32 count = mGroups.count();
- for(S32 i = 0; i < count; ++i)
- {
- if(mGroups.get(i).mID == group_id)
- {
- return TRUE;
- }
- }
- return FALSE;
-}
-
-// This implementation should mirror LLAgentInfo::hasPowerInGroup
-BOOL LLAgent::hasPowerInGroup(const LLUUID& group_id, U64 power) const
-{
- if (isGodlike())
- return true;
-
- // GP_NO_POWERS can also mean no power is enough to grant an ability.
- if (GP_NO_POWERS == power) return FALSE;
-
- S32 count = mGroups.count();
- for(S32 i = 0; i < count; ++i)
- {
- if(mGroups.get(i).mID == group_id)
- {
- return (BOOL)((mGroups.get(i).mPowers & power) > 0);
- }
- }
- return FALSE;
-}
-
-BOOL LLAgent::hasPowerInActiveGroup(U64 power) const
-{
- return (mGroupID.notNull() && (hasPowerInGroup(mGroupID, power)));
-}
-
-U64 LLAgent::getPowerInGroup(const LLUUID& group_id) const
-{
- if (isGodlike())
- return GP_ALL_POWERS;
-
- S32 count = mGroups.count();
- for(S32 i = 0; i < count; ++i)
- {
- if(mGroups.get(i).mID == group_id)
- {
- return (mGroups.get(i).mPowers);
- }
- }
-
- return GP_NO_POWERS;
-}
-
-BOOL LLAgent::getGroupData(const LLUUID& group_id, LLGroupData& data) const
-{
- S32 count = mGroups.count();
- for(S32 i = 0; i < count; ++i)
- {
- if(mGroups.get(i).mID == group_id)
- {
- data = mGroups.get(i);
- return TRUE;
- }
- }
- return FALSE;
-}
-
-S32 LLAgent::getGroupContribution(const LLUUID& group_id) const
-{
- S32 count = mGroups.count();
- for(S32 i = 0; i < count; ++i)
- {
- if(mGroups.get(i).mID == group_id)
- {
- S32 contribution = mGroups.get(i).mContribution;
- return contribution;
- }
- }
- return 0;
-}
-
-BOOL LLAgent::setGroupContribution(const LLUUID& group_id, S32 contribution)
-{
- S32 count = mGroups.count();
- for(S32 i = 0; i < count; ++i)
- {
- if(mGroups.get(i).mID == group_id)
- {
- mGroups.get(i).mContribution = contribution;
- LLMessageSystem* msg = gMessageSystem;
- msg->newMessage("SetGroupContribution");
- msg->nextBlock("AgentData");
- msg->addUUID("AgentID", gAgentID);
- msg->addUUID("SessionID", gAgentSessionID);
- msg->nextBlock("Data");
- msg->addUUID("GroupID", group_id);
- msg->addS32("Contribution", contribution);
- sendReliableMessage();
- return TRUE;
- }
- }
- return FALSE;
-}
-
-BOOL LLAgent::setUserGroupFlags(const LLUUID& group_id, BOOL accept_notices, BOOL list_in_profile)
-{
- S32 count = mGroups.count();
- for(S32 i = 0; i < count; ++i)
- {
- if(mGroups.get(i).mID == group_id)
- {
- mGroups.get(i).mAcceptNotices = accept_notices;
- mGroups.get(i).mListInProfile = list_in_profile;
- LLMessageSystem* msg = gMessageSystem;
- msg->newMessage("SetGroupAcceptNotices");
- msg->nextBlock("AgentData");
- msg->addUUID("AgentID", gAgentID);
- msg->addUUID("SessionID", gAgentSessionID);
- msg->nextBlock("Data");
- msg->addUUID("GroupID", group_id);
- msg->addBOOL("AcceptNotices", accept_notices);
- msg->nextBlock("NewData");
- msg->addBOOL("ListInProfile", list_in_profile);
- sendReliableMessage();
- return TRUE;
- }
- }
- return FALSE;
-}
-
-// utility to build a location string
-void LLAgent::buildLocationString(std::string& str)
-{
- const LLVector3& agent_pos_region = getPositionAgent();
- S32 pos_x = S32(agent_pos_region.mV[VX]);
- S32 pos_y = S32(agent_pos_region.mV[VY]);
- S32 pos_z = S32(agent_pos_region.mV[VZ]);
-
- // Round the numbers based on the velocity
- LLVector3 agent_velocity = getVelocity();
- F32 velocity_mag_sq = agent_velocity.magVecSquared();
-
- const F32 FLY_CUTOFF = 6.f; // meters/sec
- const F32 FLY_CUTOFF_SQ = FLY_CUTOFF * FLY_CUTOFF;
- const F32 WALK_CUTOFF = 1.5f; // meters/sec
- const F32 WALK_CUTOFF_SQ = WALK_CUTOFF * WALK_CUTOFF;
-
- if (velocity_mag_sq > FLY_CUTOFF_SQ)
- {
- pos_x -= pos_x % 4;
- pos_y -= pos_y % 4;
- }
- else if (velocity_mag_sq > WALK_CUTOFF_SQ)
- {
- pos_x -= pos_x % 2;
- pos_y -= pos_y % 2;
- }
-
- // create a defult name and description for the landmark
- std::string buffer;
- if( LLViewerParcelMgr::getInstance()->getAgentParcelName().empty() )
- {
- // the parcel doesn't have a name
- buffer = llformat("%.32s (%d, %d, %d)",
- getRegion()->getName().c_str(),
- pos_x, pos_y, pos_z);
- }
- else
- {
- // the parcel has a name, so include it in the landmark name
- buffer = llformat("%.32s, %.32s (%d, %d, %d)",
- LLViewerParcelMgr::getInstance()->getAgentParcelName().c_str(),
- getRegion()->getName().c_str(),
- pos_x, pos_y, pos_z);
- }
- str = buffer;
-}
-
-LLQuaternion LLAgent::getHeadRotation()
-{
- if (mAvatarObject.isNull() || !mAvatarObject->mPelvisp || !mAvatarObject->mHeadp)
- {
- return LLQuaternion::DEFAULT;
- }
-
- if (!gAgent.cameraMouselook())
- {
- return mAvatarObject->getRotation();
- }
-
- // We must be in mouselook
- LLVector3 look_dir( LLViewerCamera::getInstance()->getAtAxis() );
- LLVector3 up = look_dir % mFrameAgent.getLeftAxis();
- LLVector3 left = up % look_dir;
-
- LLQuaternion rot(look_dir, left, up);
- if (mAvatarObject->getParent())
- {
- rot = rot * ~mAvatarObject->getParent()->getRotation();
- }
-
- return rot;
-}
-
-void LLAgent::sendAnimationRequests(LLDynamicArray &anim_ids, EAnimRequest request)
-{
- if (gAgentID.isNull())
- {
- return;
- }
-
- S32 num_valid_anims = 0;
-
- LLMessageSystem* msg = gMessageSystem;
- msg->newMessageFast(_PREHASH_AgentAnimation);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, getID());
- msg->addUUIDFast(_PREHASH_SessionID, getSessionID());
-
- for (S32 i = 0; i < anim_ids.count(); i++)
- {
- if (anim_ids[i].isNull())
- {
- continue;
- }
- msg->nextBlockFast(_PREHASH_AnimationList);
- msg->addUUIDFast(_PREHASH_AnimID, (anim_ids[i]) );
- msg->addBOOLFast(_PREHASH_StartAnim, (request == ANIM_REQUEST_START) ? TRUE : FALSE);
- num_valid_anims++;
- }
-
- msg->nextBlockFast(_PREHASH_PhysicalAvatarEventList);
- msg->addBinaryDataFast(_PREHASH_TypeData, NULL, 0);
- if (num_valid_anims)
- {
- sendReliableMessage();
- }
-}
-
-void LLAgent::sendAnimationRequest(const LLUUID &anim_id, EAnimRequest request)
-{
- if (gAgentID.isNull() || anim_id.isNull() || !mRegionp)
- {
- return;
- }
-
- LLMessageSystem* msg = gMessageSystem;
- msg->newMessageFast(_PREHASH_AgentAnimation);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, getID());
- msg->addUUIDFast(_PREHASH_SessionID, getSessionID());
-
- msg->nextBlockFast(_PREHASH_AnimationList);
- msg->addUUIDFast(_PREHASH_AnimID, (anim_id) );
- msg->addBOOLFast(_PREHASH_StartAnim, (request == ANIM_REQUEST_START) ? TRUE : FALSE);
-
- msg->nextBlockFast(_PREHASH_PhysicalAvatarEventList);
- msg->addBinaryDataFast(_PREHASH_TypeData, NULL, 0);
- sendReliableMessage();
-}
-
-void LLAgent::sendWalkRun(bool running)
-{
- LLMessageSystem* msgsys = gMessageSystem;
- if (msgsys)
- {
- msgsys->newMessageFast(_PREHASH_SetAlwaysRun);
- msgsys->nextBlockFast(_PREHASH_AgentData);
- msgsys->addUUIDFast(_PREHASH_AgentID, getID());
- msgsys->addUUIDFast(_PREHASH_SessionID, getSessionID());
- msgsys->addBOOLFast(_PREHASH_AlwaysRun, BOOL(running) );
- sendReliableMessage();
- }
-}
-
-void LLAgent::friendsChanged()
-{
- LLCollectProxyBuddies collector;
- LLAvatarTracker::instance().applyFunctor(collector);
- mProxyForAgents = collector.mProxy;
-}
-
-BOOL LLAgent::isGrantedProxy(const LLPermissions& perm)
-{
- return (mProxyForAgents.count(perm.getOwner()) > 0);
-}
-
-BOOL LLAgent::allowOperation(PermissionBit op,
- const LLPermissions& perm,
- U64 group_proxy_power,
- U8 god_minimum)
-{
- // Check god level.
- if (getGodLevel() >= god_minimum) return TRUE;
-
- if (!perm.isOwned()) return FALSE;
-
- // A group member with group_proxy_power can act as owner.
- BOOL is_group_owned;
- LLUUID owner_id;
- perm.getOwnership(owner_id, is_group_owned);
- LLUUID group_id(perm.getGroup());
- LLUUID agent_proxy(getID());
-
- if (is_group_owned)
- {
- if (hasPowerInGroup(group_id, group_proxy_power))
- {
- // Let the member assume the group's id for permission requests.
- agent_proxy = owner_id;
- }
- }
- else
- {
- // Check for granted mod permissions.
- if ((PERM_OWNER != op) && isGrantedProxy(perm))
- {
- agent_proxy = owner_id;
- }
- }
-
- // This is the group id to use for permission requests.
- // Only group members may use this field.
- LLUUID group_proxy = LLUUID::null;
- if (group_id.notNull() && isInGroup(group_id))
- {
- group_proxy = group_id;
- }
-
- // We now have max ownership information.
- if (PERM_OWNER == op)
- {
- // This this was just a check for ownership, we can now return the answer.
- return (agent_proxy == owner_id);
- }
-
- return perm.allowOperationBy(op, agent_proxy, group_proxy);
-}
-
-
-void LLAgent::getName(std::string& name)
-{
- name.clear();
-
- if (mAvatarObject.notNull())
- {
- LLNameValue *first_nv = mAvatarObject->getNVPair("FirstName");
- LLNameValue *last_nv = mAvatarObject->getNVPair("LastName");
- if (first_nv && last_nv)
- {
- name = first_nv->printData() + " " + last_nv->printData();
- }
- else
- {
- llwarns << "Agent is missing FirstName and/or LastName nv pair." << llendl;
- }
- }
- else
- {
- name = gSavedSettings.getString("FirstName") + " " + gSavedSettings.getString("LastName");
- }
-}
-
-const LLColor4 &LLAgent::getEffectColor()
-{
- return mEffectColor;
-}
-
-void LLAgent::setEffectColor(const LLColor4 &color)
-{
- mEffectColor = color;
-}
-
-void LLAgent::initOriginGlobal(const LLVector3d &origin_global)
-{
- mAgentOriginGlobal = origin_global;
-}
-
-void update_group_floaters(const LLUUID& group_id)
-{
- LLFloaterGroupInfo::refreshGroup(group_id);
-
- // update avatar info
- LLFloaterAvatarInfo* fa = LLFloaterAvatarInfo::getInstance(gAgent.getID());
- if(fa)
- {
- fa->resetGroupList();
- }
-
- if (gIMMgr)
- {
- // update the talk view
- gIMMgr->refresh();
- }
-
- gAgent.fireEvent(new LLEvent(&gAgent, "new group"), "");
-}
-
-// static
-void LLAgent::processAgentDropGroup(LLMessageSystem *msg, void **)
-{
- LLUUID agent_id;
- msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id );
-
- if (agent_id != gAgentID)
- {
- llwarns << "processAgentDropGroup for agent other than me" << llendl;
- return;
- }
-
- LLUUID group_id;
- msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_GroupID, group_id );
-
- // Remove the group if it already exists remove it and add the new data to pick up changes.
- LLGroupData gd;
- gd.mID = group_id;
- S32 index = gAgent.mGroups.find(gd);
- if (index != -1)
- {
- gAgent.mGroups.remove(index);
- if (gAgent.getGroupID() == group_id)
- {
- gAgent.mGroupID.setNull();
- gAgent.mGroupPowers = 0;
- gAgent.mGroupName.clear();
- gAgent.mGroupTitle.clear();
- }
-
- // refresh all group information
- gAgent.sendAgentDataUpdateRequest();
-
- LLGroupMgr::getInstance()->clearGroupData(group_id);
- // close the floater for this group, if any.
- LLFloaterGroupInfo::closeGroup(group_id);
- // refresh the group panel of the search window, if necessary.
- LLFloaterDirectory::refreshGroup(group_id);
- }
- else
- {
- llwarns << "processAgentDropGroup, agent is not part of group " << group_id << llendl;
- }
-}
-
-class LLAgentDropGroupViewerNode : public LLHTTPNode
-{
- virtual void post(
- LLHTTPNode::ResponsePtr response,
- const LLSD& context,
- const LLSD& input) const
- {
-
- if (
- !input.isMap() ||
- !input.has("body") )
- {
- //what to do with badly formed message?
- response->status(400);
- response->result(LLSD("Invalid message parameters"));
- }
-
- LLSD body = input["body"];
- if ( body.has("body") )
- {
- //stupid message system doubles up the "body"s
- body = body["body"];
- }
-
- if (
- body.has("AgentData") &&
- body["AgentData"].isArray() &&
- body["AgentData"][0].isMap() )
- {
- llinfos << "VALID DROP GROUP" << llendl;
-
- //there is only one set of data in the AgentData block
- LLSD agent_data = body["AgentData"][0];
- LLUUID agent_id;
- LLUUID group_id;
-
- agent_id = agent_data["AgentID"].asUUID();
- group_id = agent_data["GroupID"].asUUID();
-
- if (agent_id != gAgentID)
- {
- llwarns
- << "AgentDropGroup for agent other than me" << llendl;
-
- response->notFound();
- return;
- }
-
- // Remove the group if it already exists remove it
- // and add the new data to pick up changes.
- LLGroupData gd;
- gd.mID = group_id;
- S32 index = gAgent.mGroups.find(gd);
- if (index != -1)
- {
- gAgent.mGroups.remove(index);
- if (gAgent.getGroupID() == group_id)
- {
- gAgent.mGroupID.setNull();
- gAgent.mGroupPowers = 0;
- gAgent.mGroupName.clear();
- gAgent.mGroupTitle.clear();
- }
-
- // refresh all group information
- gAgent.sendAgentDataUpdateRequest();
-
- LLGroupMgr::getInstance()->clearGroupData(group_id);
- // close the floater for this group, if any.
- LLFloaterGroupInfo::closeGroup(group_id);
- // refresh the group panel of the search window,
- //if necessary.
- LLFloaterDirectory::refreshGroup(group_id);
- }
- else
- {
- llwarns
- << "AgentDropGroup, agent is not part of group "
- << group_id << llendl;
- }
-
- response->result(LLSD());
- }
- else
- {
- //what to do with badly formed message?
- response->status(400);
- response->result(LLSD("Invalid message parameters"));
- }
- }
-};
-
-LLHTTPRegistration
- gHTTPRegistrationAgentDropGroupViewerNode(
- "/message/AgentDropGroup");
-
-// static
-void LLAgent::processAgentGroupDataUpdate(LLMessageSystem *msg, void **)
-{
- LLUUID agent_id;
-
- msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id );
-
- if (agent_id != gAgentID)
- {
- llwarns << "processAgentGroupDataUpdate for agent other than me" << llendl;
- return;
- }
-
- S32 count = msg->getNumberOfBlocksFast(_PREHASH_GroupData);
- LLGroupData group;
- S32 index = -1;
- bool need_floater_update = false;
- for(S32 i = 0; i < count; ++i)
- {
- msg->getUUIDFast(_PREHASH_GroupData, _PREHASH_GroupID, group.mID, i);
- msg->getUUIDFast(_PREHASH_GroupData, _PREHASH_GroupInsigniaID, group.mInsigniaID, i);
- msg->getU64(_PREHASH_GroupData, "GroupPowers", group.mPowers, i);
- msg->getBOOL(_PREHASH_GroupData, "AcceptNotices", group.mAcceptNotices, i);
- msg->getS32(_PREHASH_GroupData, "Contribution", group.mContribution, i);
- msg->getStringFast(_PREHASH_GroupData, _PREHASH_GroupName, group.mName, i);
-
- if(group.mID.notNull())
- {
- need_floater_update = true;
- // Remove the group if it already exists remove it and add the new data to pick up changes.
- index = gAgent.mGroups.find(group);
- if (index != -1)
- {
- gAgent.mGroups.remove(index);
- }
- gAgent.mGroups.put(group);
- }
- if (need_floater_update)
- {
- update_group_floaters(group.mID);
- }
- }
-
-}
-
-class LLAgentGroupDataUpdateViewerNode : public LLHTTPNode
-{
- virtual void post(
- LLHTTPNode::ResponsePtr response,
- const LLSD& context,
- const LLSD& input) const
- {
- LLSD body = input["body"];
- if(body.has("body"))
- body = body["body"];
- LLUUID agent_id = body["AgentData"][0]["AgentID"].asUUID();
-
- if (agent_id != gAgentID)
- {
- llwarns << "processAgentGroupDataUpdate for agent other than me" << llendl;
- return;
- }
-
- LLSD group_data = body["GroupData"];
-
- LLSD::array_iterator iter_group =
- group_data.beginArray();
- LLSD::array_iterator end_group =
- group_data.endArray();
- int group_index = 0;
- for(; iter_group != end_group; ++iter_group)
- {
-
- LLGroupData group;
- S32 index = -1;
- bool need_floater_update = false;
-
- group.mID = (*iter_group)["GroupID"].asUUID();
- group.mPowers = ll_U64_from_sd((*iter_group)["GroupPowers"]);
- group.mAcceptNotices = (*iter_group)["AcceptNotices"].asBoolean();
- group.mListInProfile = body["NewGroupData"][group_index]["ListInProfile"].asBoolean();
- group.mInsigniaID = (*iter_group)["GroupInsigniaID"].asUUID();
- group.mName = (*iter_group)["GroupName"].asString();
- group.mContribution = (*iter_group)["Contribution"].asInteger();
-
- group_index++;
-
- if(group.mID.notNull())
- {
- need_floater_update = true;
- // Remove the group if it already exists remove it and add the new data to pick up changes.
- index = gAgent.mGroups.find(group);
- if (index != -1)
- {
- gAgent.mGroups.remove(index);
- }
- gAgent.mGroups.put(group);
- }
- if (need_floater_update)
- {
- update_group_floaters(group.mID);
- }
- }
- }
-};
-
-LLHTTPRegistration
- gHTTPRegistrationAgentGroupDataUpdateViewerNode ("/message/AgentGroupDataUpdate");
-
-// static
-void LLAgent::processAgentDataUpdate(LLMessageSystem *msg, void **)
-{
- LLUUID agent_id;
-
- msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id );
-
- if (agent_id != gAgentID)
- {
- llwarns << "processAgentDataUpdate for agent other than me" << llendl;
- return;
- }
-
- msg->getStringFast(_PREHASH_AgentData, _PREHASH_GroupTitle, gAgent.mGroupTitle);
- LLUUID active_id;
- msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_ActiveGroupID, active_id);
-
-
- if(active_id.notNull())
- {
- gAgent.mGroupID = active_id;
- msg->getU64(_PREHASH_AgentData, "GroupPowers", gAgent.mGroupPowers);
- msg->getString(_PREHASH_AgentData, _PREHASH_GroupName, gAgent.mGroupName);
- }
- else
- {
- gAgent.mGroupID.setNull();
- gAgent.mGroupPowers = 0;
- gAgent.mGroupName.clear();
- }
-
- update_group_floaters(active_id);
-}
-
-// static
-void LLAgent::processScriptControlChange(LLMessageSystem *msg, void **)
-{
- S32 block_count = msg->getNumberOfBlocks("Data");
- for (S32 block_index = 0; block_index < block_count; block_index++)
- {
- BOOL take_controls;
- U32 controls;
- BOOL passon;
- U32 i;
- msg->getBOOL("Data", "TakeControls", take_controls, block_index);
- if (take_controls)
- {
- // take controls
- msg->getU32("Data", "Controls", controls, block_index );
- msg->getBOOL("Data", "PassToAgent", passon, block_index );
- U32 total_count = 0;
- for (i = 0; i < TOTAL_CONTROLS; i++)
- {
- if (controls & ( 1 << i))
- {
- if (passon)
- {
- gAgent.mControlsTakenPassedOnCount[i]++;
- }
- else
- {
- gAgent.mControlsTakenCount[i]++;
- }
- total_count++;
- }
- }
-
- // Any control taken? If so, might be first time.
- if (total_count > 0)
- {
- LLFirstUse::useOverrideKeys();
- }
- }
- else
- {
- // release controls
- msg->getU32("Data", "Controls", controls, block_index );
- msg->getBOOL("Data", "PassToAgent", passon, block_index );
- for (i = 0; i < TOTAL_CONTROLS; i++)
- {
- if (controls & ( 1 << i))
- {
- if (passon)
- {
- gAgent.mControlsTakenPassedOnCount[i]--;
- if (gAgent.mControlsTakenPassedOnCount[i] < 0)
- {
- gAgent.mControlsTakenPassedOnCount[i] = 0;
- }
- }
- else
- {
- gAgent.mControlsTakenCount[i]--;
- if (gAgent.mControlsTakenCount[i] < 0)
- {
- gAgent.mControlsTakenCount[i] = 0;
- }
- }
- }
- }
- }
- }
-}
-
-/*
-// static
-void LLAgent::processControlTake(LLMessageSystem *msg, void **)
-{
- U32 controls;
- msg->getU32("Data", "Controls", controls );
- U32 passon;
- msg->getBOOL("Data", "PassToAgent", passon );
-
- S32 i;
- S32 total_count = 0;
- for (i = 0; i < TOTAL_CONTROLS; i++)
- {
- if (controls & ( 1 << i))
- {
- if (passon)
- {
- gAgent.mControlsTakenPassedOnCount[i]++;
- }
- else
- {
- gAgent.mControlsTakenCount[i]++;
- }
- total_count++;
- }
- }
-
- // Any control taken? If so, might be first time.
- if (total_count > 0)
- {
- LLFirstUse::useOverrideKeys();
- }
-}
-
-// static
-void LLAgent::processControlRelease(LLMessageSystem *msg, void **)
-{
- U32 controls;
- msg->getU32("Data", "Controls", controls );
- U32 passon;
- msg->getBOOL("Data", "PassToAgent", passon );
-
- S32 i;
- for (i = 0; i < TOTAL_CONTROLS; i++)
- {
- if (controls & ( 1 << i))
- {
- if (passon)
- {
- gAgent.mControlsTakenPassedOnCount[i]--;
- if (gAgent.mControlsTakenPassedOnCount[i] < 0)
- {
- gAgent.mControlsTakenPassedOnCount[i] = 0;
- }
- }
- else
- {
- gAgent.mControlsTakenCount[i]--;
- if (gAgent.mControlsTakenCount[i] < 0)
- {
- gAgent.mControlsTakenCount[i] = 0;
- }
- }
- }
- }
-}
-*/
-
-//static
-void LLAgent::processAgentCachedTextureResponse(LLMessageSystem *mesgsys, void **user_data)
-{
- gAgent.mNumPendingQueries--;
-
- LLVOAvatar* avatarp = gAgent.getAvatarObject();
- if (!avatarp || avatarp->isDead())
- {
- llwarns << "No avatar for user in cached texture update!" << llendl;
- return;
- }
-
- if (gAgent.cameraCustomizeAvatar())
- {
- // ignore baked textures when in customize mode
- return;
- }
-
- S32 query_id;
- mesgsys->getS32Fast(_PREHASH_AgentData, _PREHASH_SerialNum, query_id);
-
- S32 num_texture_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_WearableData);
-
-
- S32 num_results = 0;
- for (S32 texture_block = 0; texture_block < num_texture_blocks; texture_block++)
- {
- LLUUID texture_id;
- U8 texture_index;
-
- mesgsys->getUUIDFast(_PREHASH_WearableData, _PREHASH_TextureID, texture_id, texture_block);
- mesgsys->getU8Fast(_PREHASH_WearableData, _PREHASH_TextureIndex, texture_index, texture_block);
-
- if (texture_id.notNull()
- && (S32)texture_index < BAKED_NUM_INDICES
- && gAgent.mActiveCacheQueries[ texture_index ] == query_id)
- {
- //llinfos << "Received cached texture " << (U32)texture_index << ": " << texture_id << llendl;
- avatarp->setCachedBakedTexture(getTextureIndex((EBakedTextureIndex)texture_index), texture_id);
- //avatarp->setTETexture( LLVOAvatar::sBakedTextureIndices[texture_index], texture_id );
- gAgent.mActiveCacheQueries[ texture_index ] = 0;
- num_results++;
- }
- }
-
- llinfos << "Received cached texture response for " << num_results << " textures." << llendl;
-
- avatarp->updateMeshTextures();
-
- if (gAgent.mNumPendingQueries == 0)
- {
- // RN: not sure why composites are disabled at this point
- avatarp->setCompositeUpdatesEnabled(TRUE);
- gAgent.sendAgentSetAppearance();
- }
-}
-
-BOOL LLAgent::anyControlGrabbed() const
-{
- U32 i;
- for (i = 0; i < TOTAL_CONTROLS; i++)
- {
- if (gAgent.mControlsTakenCount[i] > 0)
- return TRUE;
- if (gAgent.mControlsTakenPassedOnCount[i] > 0)
- return TRUE;
- }
- return FALSE;
-}
-
-BOOL LLAgent::isControlGrabbed(S32 control_index) const
-{
- return mControlsTakenCount[control_index] > 0;
-}
-
-void LLAgent::forceReleaseControls()
-{
- gMessageSystem->newMessage("ForceScriptControlRelease");
- gMessageSystem->nextBlock("AgentData");
- gMessageSystem->addUUID("AgentID", getID());
- gMessageSystem->addUUID("SessionID", getSessionID());
- sendReliableMessage();
-}
-
-void LLAgent::setHomePosRegion( const U64& region_handle, const LLVector3& pos_region)
-{
- mHaveHomePosition = TRUE;
- mHomeRegionHandle = region_handle;
- mHomePosRegion = pos_region;
-}
-
-BOOL LLAgent::getHomePosGlobal( LLVector3d* pos_global )
-{
- if(!mHaveHomePosition)
- {
- return FALSE;
- }
- F32 x = 0;
- F32 y = 0;
- from_region_handle( mHomeRegionHandle, &x, &y);
- pos_global->setVec( x + mHomePosRegion.mV[VX], y + mHomePosRegion.mV[VY], mHomePosRegion.mV[VZ] );
- return TRUE;
-}
-
-void LLAgent::clearVisualParams(void *data)
-{
- LLVOAvatar* avatarp = gAgent.getAvatarObject();
- if (avatarp)
- {
- avatarp->clearVisualParamWeights();
- avatarp->updateVisualParams();
- }
-}
-
-//---------------------------------------------------------------------------
-// Teleport
-//---------------------------------------------------------------------------
-
-// teleportCore() - stuff to do on any teleport
-// protected
-bool LLAgent::teleportCore(bool is_local)
-{
- if(TELEPORT_NONE != mTeleportState)
- {
- llwarns << "Attempt to teleport when already teleporting." << llendl;
- //
- //return false;
- teleportCancel();
- //
- }
-
-#if 0
- // This should not exist. It has been added, removed, added, and now removed again.
- // This change needs to come from the simulator. Otherwise, the agent ends up out of
- // sync with other viewers. Discuss in DEV-14145/VWR-6744 before reenabling.
-
- // Stop all animation before actual teleporting
- LLVOAvatar* avatarp = gAgent.getAvatarObject();
- if (avatarp)
- {
- for ( LLVOAvatar::AnimIterator anim_it= avatarp->mPlayingAnimations.begin();
- anim_it != avatarp->mPlayingAnimations.end();
- ++anim_it)
- {
- avatarp->stopMotion(anim_it->first);
- }
- avatarp->processAnimationStateChanges();
- }
-#endif
-
- // Don't call LLFirstUse::useTeleport because we don't know
- // yet if the teleport will succeed. Look in
- // process_teleport_location_reply
-
- // close the map and find panels so we can see our destination
- LLFloaterWorldMap::hide(NULL);
- LLFloaterDirectory::hide(NULL);
-
- // hide land floater too - it'll be out of date
- LLFloaterLand::hideInstance();
-
- LLViewerParcelMgr::getInstance()->deselectLand();
- LLViewerMediaFocus::getInstance()->setFocusFace(false, NULL, 0, NULL);
-
- // Close all pie menus, deselect land, etc.
- // Don't change the camera until we know teleport succeeded. JC
- //
- if(gAgent.getFocusOnAvatar())
- //
- resetView(FALSE);
-
- // local logic
- LLViewerStats::getInstance()->incStat(LLViewerStats::ST_TELEPORT_COUNT);
- if (is_local)
- {
- gAgent.setTeleportState( LLAgent::TELEPORT_LOCAL );
- }
- else
- {
- gTeleportDisplay = TRUE;
- gAgent.setTeleportState( LLAgent::TELEPORT_START );
-
- //release geometry from old location
- gPipeline.resetVertexBuffers();
-
- if (gSavedSettings.getBOOL("SpeedRez"))
- {
- F32 draw_distance = gSavedSettings.getF32("RenderFarClip");
- if (gSavedDrawDistance < draw_distance)
- {
- gSavedDrawDistance = draw_distance;
- }
- gSavedSettings.setF32("SavedRenderFarClip", gSavedDrawDistance);
- gSavedSettings.setF32("RenderFarClip", 32.0f);
- }
- if(gSavedSettings.getBOOL("OptionPlayTpSound"))
- make_ui_sound("UISndTeleportOut");
- }
-
- // MBW -- Let the voice client know a teleport has begun so it can leave the existing channel.
- // This was breaking the case of teleporting within a single sim. Backing it out for now.
-// gVoiceClient->leaveChannel();
-
- return true;
-}
-
-void LLAgent::teleportRequest(
- const U64& region_handle,
- const LLVector3& pos_local,
- bool look_at_from_camera)
-{
- LLViewerRegion* regionp = getRegion();
- bool is_local = (region_handle == to_region_handle(getPositionGlobal()));
- if(regionp && teleportCore(is_local))
- {
- llinfos << "TeleportLocationRequest: '" << region_handle << "':" << pos_local
- << llendl;
- LLMessageSystem* msg = gMessageSystem;
- msg->newMessage("TeleportLocationRequest");
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, getID());
- msg->addUUIDFast(_PREHASH_SessionID, getSessionID());
- msg->nextBlockFast(_PREHASH_Info);
- msg->addU64("RegionHandle", region_handle);
- msg->addVector3("Position", pos_local);
- //
- //LLVector3 look_at(0,1,0);
- LLVector3 look_at = LLViewerCamera::getInstance()->getAtAxis();
- /*if (look_at_from_camera)
- {
- look_at = LLViewerCamera::getInstance()->getAtAxis();
- }*/
- //
- msg->addVector3("LookAt", look_at);
- sendReliableMessage();
- }
-}
-
-// Landmark ID = LLUUID::null means teleport home
-void LLAgent::teleportViaLandmark(const LLUUID& landmark_asset_id)
-{
- LLViewerRegion *regionp = getRegion();
- if(regionp && teleportCore())
- {
- LLMessageSystem* msg = gMessageSystem;
- msg->newMessageFast(_PREHASH_TeleportLandmarkRequest);
- msg->nextBlockFast(_PREHASH_Info);
- msg->addUUIDFast(_PREHASH_AgentID, getID());
- msg->addUUIDFast(_PREHASH_SessionID, getSessionID());
- msg->addUUIDFast(_PREHASH_LandmarkID, landmark_asset_id);
- sendReliableMessage();
- }
-}
-
-void LLAgent::teleportViaLure(const LLUUID& lure_id, BOOL godlike)
-{
- LLViewerRegion* regionp = getRegion();
- if(regionp && teleportCore())
- {
- U32 teleport_flags = 0x0;
- if (godlike)
- {
- teleport_flags |= TELEPORT_FLAGS_VIA_GODLIKE_LURE;
- teleport_flags |= TELEPORT_FLAGS_DISABLE_CANCEL;
- }
- else
- {
- teleport_flags |= TELEPORT_FLAGS_VIA_LURE;
- }
-
- // send the message
- LLMessageSystem* msg = gMessageSystem;
- msg->newMessageFast(_PREHASH_TeleportLureRequest);
- msg->nextBlockFast(_PREHASH_Info);
- msg->addUUIDFast(_PREHASH_AgentID, getID());
- msg->addUUIDFast(_PREHASH_SessionID, getSessionID());
- msg->addUUIDFast(_PREHASH_LureID, lure_id);
- // teleport_flags is a legacy field, now derived sim-side:
- msg->addU32("TeleportFlags", teleport_flags);
- sendReliableMessage();
- }
-}
-
-
-// James Cook, July 28, 2005
-void LLAgent::teleportCancel()
-{
- LLViewerRegion* regionp = getRegion();
- if(regionp)
- {
- // send the message
- LLMessageSystem* msg = gMessageSystem;
- msg->newMessage("TeleportCancel");
- msg->nextBlockFast(_PREHASH_Info);
- msg->addUUIDFast(_PREHASH_AgentID, getID());
- msg->addUUIDFast(_PREHASH_SessionID, getSessionID());
- sendReliableMessage();
- }
- gTeleportDisplay = FALSE;
- gAgent.setTeleportState( LLAgent::TELEPORT_NONE );
-}
-
-
-void LLAgent::teleportViaLocation(const LLVector3d& pos_global)
-{
- LLViewerRegion* regionp = getRegion();
- U64 handle = to_region_handle(pos_global);
- LLSimInfo* info = LLWorldMap::getInstance()->simInfoFromHandle(handle);
- if(regionp && info)
- {
- LLVector3d region_origin = info->getGlobalOrigin();
- LLVector3 pos_local(
- (F32)(pos_global.mdV[VX] - region_origin.mdV[VX]),
- (F32)(pos_global.mdV[VY] - region_origin.mdV[VY]),
- (F32)(pos_global.mdV[VZ]));
- teleportRequest(handle, pos_local);
- }
- else if(regionp &&
- teleportCore(regionp->getHandle() == to_region_handle_global((F32)pos_global.mdV[VX], (F32)pos_global.mdV[VY])))
- {
- llwarns << "Using deprecated teleportlocationrequest." << llendl;
- // send the message
- LLMessageSystem* msg = gMessageSystem;
- msg->newMessageFast(_PREHASH_TeleportLocationRequest);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, getID());
- msg->addUUIDFast(_PREHASH_SessionID, getSessionID());
-
- msg->nextBlockFast(_PREHASH_Info);
- F32 width = regionp->getWidth();
- LLVector3 pos(fmod((F32)pos_global.mdV[VX], width),
- fmod((F32)pos_global.mdV[VY], width),
- (F32)pos_global.mdV[VZ]);
- F32 region_x = (F32)(pos_global.mdV[VX]);
- F32 region_y = (F32)(pos_global.mdV[VY]);
- U64 region_handle = to_region_handle_global(region_x, region_y);
- msg->addU64Fast(_PREHASH_RegionHandle, region_handle);
- msg->addVector3Fast(_PREHASH_Position, pos);
- pos.mV[VX] += 1;
- //
- LLVector3 lookat = LLViewerCamera::getInstance()->getAtAxis();
- //msg->addVector3Fast(_PREHASH_LookAt, pos);
- msg->addVector3Fast(_PREHASH_LookAt, lookat);
- //
- sendReliableMessage();
- }
-}
-
-// Teleport to global position, but keep facing in the same direction
-void LLAgent::teleportViaLocationLookAt(const LLVector3d& pos_global)
-{
- mbTeleportKeepsLookAt = true;
- setFocusOnAvatar(FALSE, ANIMATE); // detach camera form avatar, so it keeps direction
- U64 region_handle = to_region_handle(pos_global);
- LLVector3 pos_local = (LLVector3)(pos_global - from_region_handle(region_handle));
- teleportRequest(region_handle, pos_local, getTeleportKeepsLookAt());
-}
-
-void LLAgent::setTeleportState(ETeleportState state)
-{
- mTeleportState = state;
- if (mTeleportState > TELEPORT_NONE && gSavedSettings.getBOOL("FreezeTime"))
- {
- LLFloaterSnapshot::hide(0);
- }
- if (mTeleportState == TELEPORT_NONE)
- {
- mbTeleportKeepsLookAt = false;
- }
- // OGPX : Only compute a 'slurl' in non-OGP mode. In OGP, set it to regionuri in floaterteleport.
- if ((mTeleportState == TELEPORT_MOVING)&& (!gSavedSettings.getBOOL("OpenGridProtocol")))
- {
- // We're outa here. Save "back" slurl.
- mTeleportSourceSLURL = getSLURL();
- }
-}
-
-void LLAgent::stopCurrentAnimations()
-{
- // This function stops all current overriding animations on this
- // avatar, propagating this change back to the server.
-
- LLVOAvatar* avatarp = gAgent.getAvatarObject();
- if (avatarp)
- {
- for ( LLVOAvatar::AnimIterator anim_it =
- avatarp->mPlayingAnimations.begin();
- anim_it != avatarp->mPlayingAnimations.end();
- anim_it++)
- {
- if (anim_it->first ==
- ANIM_AGENT_SIT_GROUND_CONSTRAINED)
- {
- // don't cancel a ground-sit anim, as viewers
- // use this animation's status in
- // determining whether we're sitting. ick.
- }
- else
- {
- // stop this animation locally
- avatarp->stopMotion(anim_it->first, TRUE);
- // ...and tell the server to tell everyone.
- sendAnimationRequest(anim_it->first, ANIM_REQUEST_STOP);
- }
- }
-
- // re-assert at least the default standing animation, because
- // viewers get confused by avs with no associated anims.
- sendAnimationRequest(ANIM_AGENT_STAND,
- ANIM_REQUEST_START);
- }
-}
-
-void LLAgent::fidget()
-{
- if (!getAFK())
- {
- F32 curTime = mFidgetTimer.getElapsedTimeF32();
- if (curTime > mNextFidgetTime)
- {
- // pick a random fidget anim here
- S32 oldFidget = mCurrentFidget;
-
- mCurrentFidget = ll_rand(NUM_AGENT_STAND_ANIMS);
-
- if (mCurrentFidget != oldFidget)
- {
- //LLAgent::stopFidget();
- //
- // for the sack of smaller packets, make this cancel the last one only
- if(oldFidget != 0)
- sendAnimationRequest(AGENT_STAND_ANIMS[oldFidget],ANIM_REQUEST_STOP);
- //
-
- switch(mCurrentFidget)
- {
- case 0:
- mCurrentFidget = 0;
- break;
- case 1:
- sendAnimationRequest(ANIM_AGENT_STAND_1, ANIM_REQUEST_START);
- mCurrentFidget = 1;
- break;
- case 2:
- sendAnimationRequest(ANIM_AGENT_STAND_2, ANIM_REQUEST_START);
- mCurrentFidget = 2;
- break;
- case 3:
- sendAnimationRequest(ANIM_AGENT_STAND_3, ANIM_REQUEST_START);
- mCurrentFidget = 3;
- break;
- case 4:
- sendAnimationRequest(ANIM_AGENT_STAND_4, ANIM_REQUEST_START);
- mCurrentFidget = 4;
- break;
- }
- }
-
- // calculate next fidget time
- mNextFidgetTime = curTime + ll_frand(MAX_FIDGET_TIME - MIN_FIDGET_TIME) + MIN_FIDGET_TIME;
- }
- }
-}
-
-void LLAgent::stopFidget()
-{
- LLDynamicArray anims;
- anims.put(ANIM_AGENT_STAND_1);
- anims.put(ANIM_AGENT_STAND_2);
- anims.put(ANIM_AGENT_STAND_3);
- anims.put(ANIM_AGENT_STAND_4);
-
- gAgent.sendAnimationRequests(anims, ANIM_REQUEST_STOP);
-}
-
-
-void LLAgent::requestEnterGodMode()
-{
- LLMessageSystem* msg = gMessageSystem;
- msg->newMessageFast(_PREHASH_RequestGodlikePowers);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
- msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- msg->nextBlockFast(_PREHASH_RequestBlock);
- msg->addBOOLFast(_PREHASH_Godlike, TRUE);
- msg->addUUIDFast(_PREHASH_Token, LLUUID::null);
-
- // simulators need to know about your request
- sendReliableMessage();
-}
-
-void LLAgent::requestLeaveGodMode()
-{
- LLMessageSystem* msg = gMessageSystem;
- msg->newMessageFast(_PREHASH_RequestGodlikePowers);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
- msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- msg->nextBlockFast(_PREHASH_RequestBlock);
- msg->addBOOLFast(_PREHASH_Godlike, FALSE);
- msg->addUUIDFast(_PREHASH_Token, LLUUID::null);
-
- // simulator needs to know about your request
- sendReliableMessage();
-}
-
-// wearables
-LLAgent::createStandardWearablesAllDoneCallback::~createStandardWearablesAllDoneCallback()
-{
- gAgent.createStandardWearablesAllDone();
-}
-
-LLAgent::sendAgentWearablesUpdateCallback::~sendAgentWearablesUpdateCallback()
-{
- gAgent.sendAgentWearablesUpdate();
-}
-
-LLAgent::addWearableToAgentInventoryCallback::addWearableToAgentInventoryCallback(
- LLPointer cb, S32 index, LLWearable* wearable, U32 todo) :
- mIndex(index),
- mWearable(wearable),
- mTodo(todo),
- mCB(cb)
-{
-}
-
-void LLAgent::addWearableToAgentInventoryCallback::fire(const LLUUID& inv_item)
-{
- if (inv_item.isNull())
- return;
-
- gAgent.addWearabletoAgentInventoryDone(mIndex, inv_item, mWearable);
-
- if (mTodo & CALL_UPDATE)
- {
- gAgent.sendAgentWearablesUpdate();
- }
- if (mTodo & CALL_RECOVERDONE)
- {
- gAgent.recoverMissingWearableDone();
- }
- /*
- * Do this for every one in the loop
- */
- if (mTodo & CALL_CREATESTANDARDDONE)
- {
- gAgent.createStandardWearablesDone(mIndex);
- }
- if (mTodo & CALL_MAKENEWOUTFITDONE)
- {
- gAgent.makeNewOutfitDone(mIndex);
- }
-}
-
-void LLAgent::addWearabletoAgentInventoryDone(
- S32 index,
- const LLUUID& item_id,
- LLWearable* wearable)
-{
- if (item_id.isNull())
- return;
-
- LLUUID old_item_id = mWearableEntry[index].mItemID;
- mWearableEntry[index].mItemID = item_id;
- mWearableEntry[index].mWearable = wearable;
- if (old_item_id.notNull())
- gInventory.addChangedMask(LLInventoryObserver::LABEL, old_item_id);
- gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id);
- LLViewerInventoryItem* item = gInventory.getItem(item_id);
- if(item && wearable)
- {
- // We're changing the asset id, so we both need to set it
- // locally via setAssetUUID() and via setTransactionID() which
- // will be decoded on the server. JC
- item->setAssetUUID(wearable->getID());
- item->setTransactionID(wearable->getTransactionID());
- gInventory.addChangedMask(LLInventoryObserver::INTERNAL, item_id);
- item->updateServer(FALSE);
- }
- gInventory.notifyObservers();
-}
-
-void LLAgent::sendAgentWearablesUpdate()
-{
- // First make sure that we have inventory items for each wearable
- S32 i;
- for(i=0; i < WT_COUNT; ++i)
- {
- LLWearable* wearable = mWearableEntry[ i ].mWearable;
- if (wearable)
- {
- if( mWearableEntry[ i ].mItemID.isNull() )
- {
- LLPointer cb =
- new addWearableToAgentInventoryCallback(
- LLPointer(NULL),
- i,
- wearable,
- addWearableToAgentInventoryCallback::CALL_NONE);
- addWearableToAgentInventory(cb, wearable);
- }
- else
- {
- gInventory.addChangedMask( LLInventoryObserver::LABEL,
- mWearableEntry[i].mItemID );
- }
- }
- }
-
- // Then make sure the inventory is in sync with the avatar.
- gInventory.notifyObservers();
-
- // Send the AgentIsNowWearing
- gMessageSystem->newMessageFast(_PREHASH_AgentIsNowWearing);
-
- gMessageSystem->nextBlockFast(_PREHASH_AgentData);
- gMessageSystem->addUUIDFast(_PREHASH_AgentID, getID());
- gMessageSystem->addUUIDFast(_PREHASH_SessionID, getSessionID());
-
- LL_DEBUGS("Wearables") << "sendAgentWearablesUpdate()" << LL_ENDL;
- for(i=0; i < WT_COUNT; ++i)
- {
- gMessageSystem->nextBlockFast(_PREHASH_WearableData);
-
- U8 type_u8 = (U8)i;
- gMessageSystem->addU8Fast(_PREHASH_WearableType, type_u8 );
-
- LLWearable* wearable = mWearableEntry[ i ].mWearable;
- if( wearable )
- {
- LL_DEBUGS("Wearables") << "Sending wearable " << wearable->getName() << " mItemID = " << mWearableEntry[ i ].mItemID << LL_ENDL;
- gMessageSystem->addUUIDFast(_PREHASH_ItemID, mWearableEntry[ i ].mItemID );
- }
- else
- {
- LL_DEBUGS("Wearables") << "Not wearing wearable type " << LLWearable::typeToTypeName((EWearableType)i) << LL_ENDL;
- gMessageSystem->addUUIDFast(_PREHASH_ItemID, LLUUID::null );
- }
-
- LL_DEBUGS("Wearables") << " " << LLWearable::typeToTypeLabel((EWearableType)i) << " : " << (wearable ? wearable->getID() : LLUUID::null) << LL_ENDL;
- }
- gAgent.sendReliableMessage();
-}
-
-void LLAgent::saveWearable( EWearableType type, BOOL send_update )
-{
- LLWearable* old_wearable = mWearableEntry[(S32)type].mWearable;
- if( old_wearable && (old_wearable->isDirty() || old_wearable->isOldVersion()) )
- {
- LLWearable* new_wearable = gWearableList.createCopyFromAvatar( old_wearable );
- mWearableEntry[(S32)type].mWearable = new_wearable;
-
- LLInventoryItem* item = gInventory.getItem(mWearableEntry[(S32)type].mItemID);
- if( item )
- {
- // Update existing inventory item
- LLPointer template_item =
- new LLViewerInventoryItem(item->getUUID(),
- item->getParentUUID(),
- item->getPermissions(),
- new_wearable->getID(),
- new_wearable->getAssetType(),
- item->getInventoryType(),
- item->getName(),
- item->getDescription(),
- item->getSaleInfo(),
- item->getFlags(),
- item->getCreationDate());
- template_item->setTransactionID(new_wearable->getTransactionID());
- template_item->updateServer(FALSE);
- gInventory.updateItem(template_item);
- }
- else
- {
- // Add a new inventory item (shouldn't ever happen here)
- U32 todo = addWearableToAgentInventoryCallback::CALL_NONE;
- if (send_update)
- {
- todo |= addWearableToAgentInventoryCallback::CALL_UPDATE;
- }
- LLPointer cb =
- new addWearableToAgentInventoryCallback(
- LLPointer(NULL),
- (S32)type,
- new_wearable,
- todo);
- addWearableToAgentInventory(cb, new_wearable);
- return;
- }
-
- getAvatarObject()->wearableUpdated( type );
-
- if( send_update )
- {
- sendAgentWearablesUpdate();
- }
- }
-}
-
-void LLAgent::saveWearableAs(
- EWearableType type,
- const std::string& new_name,
- BOOL save_in_lost_and_found)
-{
- if(!isWearableCopyable(type))
- {
- llwarns << "LLAgent::saveWearableAs() not copyable." << llendl;
- return;
- }
- LLWearable* old_wearable = getWearable(type);
- if(!old_wearable)
- {
- llwarns << "LLAgent::saveWearableAs() no old wearable." << llendl;
- return;
- }
- LLInventoryItem* item = gInventory.getItem(mWearableEntry[type].mItemID);
- if(!item)
- {
- llwarns << "LLAgent::saveWearableAs() no inventory item." << llendl;
- return;
- }
- std::string trunc_name(new_name);
- LLStringUtil::truncate(trunc_name, DB_INV_ITEM_NAME_STR_LEN);
- LLWearable* new_wearable = gWearableList.createCopyFromAvatar(
- old_wearable,
- trunc_name);
- LLPointer cb =
- new addWearableToAgentInventoryCallback(
- LLPointer(NULL),
- type,
- new_wearable,
- addWearableToAgentInventoryCallback::CALL_UPDATE);
- LLUUID category_id;
- if (save_in_lost_and_found)
- {
- category_id = gInventory.findCategoryUUIDForType(
- LLAssetType::AT_LOST_AND_FOUND);
- }
- else
- {
- // put in same folder as original
- category_id = item->getParentUUID();
- }
-
- copy_inventory_item(
- gAgent.getID(),
- item->getPermissions().getOwner(),
- item->getUUID(),
- category_id,
- new_name,
- cb);
-
-/*
- LLWearable* old_wearable = getWearable( type );
- if( old_wearable )
- {
- std::string old_name = old_wearable->getName();
- old_wearable->setName( new_name );
- LLWearable* new_wearable = gWearableList.createCopyFromAvatar( old_wearable );
- old_wearable->setName( old_name );
-
- LLUUID category_id;
- LLInventoryItem* item = gInventory.getItem( mWearableEntry[ type ].mItemID );
- if( item )
- {
- new_wearable->setPermissions(item->getPermissions());
- if (save_in_lost_and_found)
- {
- category_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_LOST_AND_FOUND);
- }
- else
- {
- // put in same folder as original
- category_id = item->getParentUUID();
- }
- LLInventoryView* view = LLInventoryView::getActiveInventory();
- if(view)
- {
- view->getPanel()->setSelection(item->getUUID(), TAKE_FOCUS_NO);
- }
- }
-
- mWearableEntry[ type ].mWearable = new_wearable;
- LLPointer cb =
- new addWearableToAgentInventoryCallback(
- LLPointer(NULL),
- type,
- addWearableToAgentInventoryCallback::CALL_UPDATE);
- addWearableToAgentInventory(cb, new_wearable, category_id);
- }
-*/
-}
-
-void LLAgent::revertWearable( EWearableType type )
-{
- LLWearable* wearable = mWearableEntry[(S32)type].mWearable;
- if( wearable )
- {
- wearable->writeToAvatar( TRUE );
- }
- sendAgentSetAppearance();
-}
-
-void LLAgent::revertAllWearables()
-{
- for( S32 i=0; i < WT_COUNT; i++ )
- {
- revertWearable( (EWearableType)i );
- }
-}
-
-void LLAgent::saveAllWearables()
-{
- //if(!gInventory.isLoaded())
- //{
- // return;
- //}
-
- for( S32 i=0; i < WT_COUNT; i++ )
- {
- saveWearable( (EWearableType)i, FALSE );
- }
- sendAgentWearablesUpdate();
-}
-
-// Called when the user changes the name of a wearable inventory item that is currenlty being worn.
-void LLAgent::setWearableName( const LLUUID& item_id, const std::string& new_name )
-{
- for( S32 i=0; i < WT_COUNT; i++ )
- {
- if( mWearableEntry[i].mItemID == item_id )
- {
- LLWearable* old_wearable = mWearableEntry[i].mWearable;
- llassert( old_wearable );
-
- std::string old_name = old_wearable->getName();
- old_wearable->setName( new_name );
- LLWearable* new_wearable = gWearableList.createCopy( old_wearable );
- LLInventoryItem* item = gInventory.getItem(item_id);
- if(item)
- {
- new_wearable->setPermissions(item->getPermissions());
- }
- old_wearable->setName( old_name );
-
- mWearableEntry[i].mWearable = new_wearable;
- sendAgentWearablesUpdate();
- break;
- }
- }
-}
-
-
-BOOL LLAgent::isWearableModifiable(EWearableType type)
-{
- LLUUID item_id = getWearableItem(type);
- if(!item_id.isNull())
- {
- LLInventoryItem* item = gInventory.getItem(item_id);
- if(item && item->getPermissions().allowModifyBy(gAgent.getID(),
- gAgent.getGroupID()))
- {
- return TRUE;
- }
- }
- return FALSE;
-}
-
-BOOL LLAgent::isWearableCopyable(EWearableType type)
-{
- LLUUID item_id = getWearableItem(type);
- if(!item_id.isNull())
- {
- LLInventoryItem* item = gInventory.getItem(item_id);
- if(item && item->getPermissions().allowCopyBy(gAgent.getID(),
- gAgent.getGroupID()))
- {
- return TRUE;
- }
- }
- return FALSE;
-}
-
-U32 LLAgent::getWearablePermMask(EWearableType type)
-{
- LLUUID item_id = getWearableItem(type);
- if(!item_id.isNull())
- {
- LLInventoryItem* item = gInventory.getItem(item_id);
- if(item)
- {
- return item->getPermissions().getMaskOwner();
- }
- }
- return PERM_NONE;
-}
-
-LLInventoryItem* LLAgent::getWearableInventoryItem(EWearableType type)
-{
- LLUUID item_id = getWearableItem(type);
- LLInventoryItem* item = NULL;
- if(item_id.notNull())
- {
- item = gInventory.getItem(item_id);
- }
- return item;
-}
-
-LLWearable* LLAgent::getWearableFromWearableItem( const LLUUID& item_id )
-{
- for( S32 i=0; i < WT_COUNT; i++ )
- {
- if( mWearableEntry[i].mItemID == item_id )
- {
- return mWearableEntry[i].mWearable;
- }
- }
- return NULL;
-}
-
-
-void LLAgent::sendAgentWearablesRequest()
-{
- gMessageSystem->newMessageFast(_PREHASH_AgentWearablesRequest);
- gMessageSystem->nextBlockFast(_PREHASH_AgentData);
- gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
- gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID() );
- sendReliableMessage();
-}
-
-// Used to enable/disable menu items.
-// static
-BOOL LLAgent::selfHasWearable( void* userdata )
-{
- EWearableType type = (EWearableType)(intptr_t)userdata;
- return gAgent.getWearable( type ) != NULL;
-}
-
-BOOL LLAgent::isWearingItem( const LLUUID& item_id )
-{
- return (getWearableFromWearableItem( item_id ) != NULL);
-}
-
-// static
-void LLAgent::processAgentInitialWearablesUpdate( LLMessageSystem* mesgsys, void** user_data )
-{
- // We should only receive this message a single time. Ignore subsequent AgentWearablesUpdates
- // that may result from AgentWearablesRequest having been sent more than once.
- static bool first = true;
- if (!first) return;
- first = false;
-
- LLUUID agent_id;
- gMessageSystem->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id );
-
- LLVOAvatar* avatar = gAgent.getAvatarObject();
- if( avatar && (agent_id == avatar->getID()) )
- {
- gMessageSystem->getU32Fast(_PREHASH_AgentData, _PREHASH_SerialNum, gAgent.mAgentWearablesUpdateSerialNum );
-
- S32 num_wearables = gMessageSystem->getNumberOfBlocksFast(_PREHASH_WearableData);
- if( num_wearables < 4 )
- {
- // Transitional state. Avatars should always have at least their body parts (hair, eyes, shape and skin).
- // The fact that they don't have any here (only a dummy is sent) implies that this account existed
- // before we had wearables, or that the database has gotten messed up.
- return;
- }
- //else
- //{
- // // OGPX HACK: OGP authentication does not pass back login-flags,
- // // thus doesn't check for "gendered" flag
- // // so this isn't an ideal place for this because the check in idle_startup in STATE_WEARABLES_WAIT
- // // is happening *before* this call. That causes the welcomechoosesex dialog to be displayed
- // // but I'm torn on removing this commented out code because I'm unsure how the initial wearables
- // // code will work out.
- // gAgent.setGenderChosen(TRUE);
- //}
-
- //lldebugs << "processAgentInitialWearablesUpdate()" << llendl;
- // Add wearables
- LLUUID asset_id_array[ WT_COUNT ];
- S32 i;
- for( i=0; i < num_wearables; i++ )
- {
- U8 type_u8 = 0;
- gMessageSystem->getU8Fast(_PREHASH_WearableData, _PREHASH_WearableType, type_u8, i );
- if( type_u8 >= WT_COUNT )
- {
- continue;
- }
- EWearableType type = (EWearableType) type_u8;
-
- LLUUID item_id;
- gMessageSystem->getUUIDFast(_PREHASH_WearableData, _PREHASH_ItemID, item_id, i );
-
- LLUUID asset_id;
- gMessageSystem->getUUIDFast(_PREHASH_WearableData, _PREHASH_AssetID, asset_id, i );
- if( asset_id.isNull() )
- {
- LLWearable::removeFromAvatar( type, FALSE );
- }
- else
- {
- LLAssetType::EType asset_type = LLWearable::typeToAssetType( type );
- if( asset_type == LLAssetType::AT_NONE )
- {
- continue;
- }
-
- gAgent.mWearableEntry[type].mItemID = item_id;
- asset_id_array[type] = asset_id;
- }
-
- LL_DEBUGS("Wearables") << " " << LLWearable::typeToTypeLabel(type) << " " << asset_id << " item id " << gAgent.mWearableEntry[type].mItemID.asString() << LL_ENDL;
- }
-
- // now that we have the asset ids...request the wearable assets
- for( i = 0; i < WT_COUNT; i++ )
- {
- LL_DEBUGS("Wearables") << " fetching " << asset_id_array[i] << LL_ENDL;
- if( !gAgent.mWearableEntry[i].mItemID.isNull() )
- {
- gWearableList.getAsset(
- asset_id_array[i],
- LLStringUtil::null,
- LLWearable::typeToAssetType( (EWearableType) i ),
- LLAgent::onInitialWearableAssetArrived, (void*)(intptr_t)i );
- }
- }
- }
-}
-
-// A single wearable that the avatar was wearing on start-up has arrived from the database.
-// static
-void LLAgent::onInitialWearableAssetArrived( LLWearable* wearable, void* userdata )
-{
- EWearableType type = (EWearableType)(intptr_t)userdata;
-
- LLVOAvatar* avatar = gAgent.getAvatarObject();
- if( !avatar )
- {
- return;
- }
-
- if( wearable )
- {
- llassert( type == wearable->getType() );
- gAgent.mWearableEntry[ type ].mWearable = wearable;
-
- // disable composites if initial textures are baked
- avatar->setupComposites();
- gAgent.queryWearableCache();
-
- wearable->writeToAvatar( FALSE );
- avatar->setCompositeUpdatesEnabled(TRUE);
- gInventory.addChangedMask( LLInventoryObserver::LABEL, gAgent.mWearableEntry[type].mItemID );
- }
- else
- {
- // Somehow the asset doesn't exist in the database.
- gAgent.recoverMissingWearable( type );
- }
-
- gInventory.notifyObservers();
-
- // Have all the wearables that the avatar was wearing at log-in arrived?
- if( !gAgent.mWearablesLoaded )
- {
- gAgent.mWearablesLoaded = TRUE;
- for( S32 i = 0; i < WT_COUNT; i++ )
- {
- if( !gAgent.mWearableEntry[i].mItemID.isNull() && !gAgent.mWearableEntry[i].mWearable )
- {
- gAgent.mWearablesLoaded = FALSE;
- break;
- }
- }
- }
-
- if( gAgent.mWearablesLoaded )
- {
- // Make sure that the server's idea of the avatar's wearables actually match the wearables.
- gAgent.sendAgentSetAppearance();
-
- // Check to see if there are any baked textures that we hadn't uploaded before we logged off last time.
- // If there are any, schedule them to be uploaded as soon as the layer textures they depend on arrive.
- if( !gAgent.cameraCustomizeAvatar() )
- {
- avatar->requestLayerSetUploads();
- }
- }
-}
-
-// Normally, all wearables referred to "AgentWearablesUpdate" will correspond to actual assets in the
-// database. If for some reason, we can't load one of those assets, we can try to reconstruct it so that
-// the user isn't left without a shape, for example. (We can do that only after the inventory has loaded.)
-void LLAgent::recoverMissingWearable( EWearableType type )
-{
- // Try to recover by replacing missing wearable with a new one.
- LLNotifications::instance().add("ReplacedMissingWearable");
- lldebugs << "Wearable " << LLWearable::typeToTypeLabel( type ) << " could not be downloaded. Replaced inventory item with default wearable." << llendl;
- LLWearable* new_wearable = gWearableList.createNewWearable(type);
-
- S32 type_s32 = (S32) type;
- mWearableEntry[type_s32].mWearable = new_wearable;
- new_wearable->writeToAvatar( TRUE );
-
- // Add a new one in the lost and found folder.
- // (We used to overwrite the "not found" one, but that could potentially
- // destory content.) JC
- LLUUID lost_and_found_id =
- gInventory.findCategoryUUIDForType(LLAssetType::AT_LOST_AND_FOUND);
- LLPointer cb =
- new addWearableToAgentInventoryCallback(
- LLPointer(NULL),
- type_s32,
- new_wearable,
- addWearableToAgentInventoryCallback::CALL_RECOVERDONE);
- addWearableToAgentInventory( cb, new_wearable, lost_and_found_id, TRUE);
-}
-
-void LLAgent::recoverMissingWearableDone()
-{
- // Have all the wearables that the avatar was wearing at log-in arrived or been fabricated?
- mWearablesLoaded = TRUE;
- for( S32 i = 0; i < WT_COUNT; i++ )
- {
- if( !mWearableEntry[i].mItemID.isNull() && !mWearableEntry[i].mWearable )
- {
- mWearablesLoaded = FALSE;
- break;
- }
- }
-
- if( mWearablesLoaded )
- {
- // Make sure that the server's idea of the avatar's wearables actually match the wearables.
- sendAgentSetAppearance();
- }
- else
- {
- gInventory.addChangedMask( LLInventoryObserver::LABEL, LLUUID::null );
- gInventory.notifyObservers();
- }
-}
-
-void LLAgent::createStandardWearables(BOOL female)
-{
- llwarns << "Creating Standard " << (female ? "female" : "male" )
- << " Wearables" << llendl;
-
- if (mAvatarObject.isNull())
- {
- return;
- }
-
- if(female) mAvatarObject->setSex(SEX_FEMALE);
- else mAvatarObject->setSex(SEX_MALE);
-
- BOOL create[WT_COUNT] =
- {
- TRUE, //WT_SHAPE
- TRUE, //WT_SKIN
- TRUE, //WT_HAIR
- TRUE, //WT_EYES
- TRUE, //WT_SHIRT
- TRUE, //WT_PANTS
- TRUE, //WT_SHOES
- TRUE, //WT_SOCKS
- FALSE, //WT_JACKET
- FALSE, //WT_GLOVES
- TRUE, //WT_UNDERSHIRT
- TRUE, //WT_UNDERPANTS
- FALSE, //WT_SKIRT
- FALSE, //WT_ALPHA
- FALSE //WT_TATTOO
- };
-
- for( S32 i=0; i < WT_COUNT; i++ )
- {
- bool once = false;
- LLPointer donecb = NULL;
- if( create[i] )
- {
- if (!once)
- {
- once = true;
- donecb = new createStandardWearablesAllDoneCallback;
- }
- llassert( mWearableEntry[i].mWearable == NULL );
- LLWearable* wearable = gWearableList.createNewWearable((EWearableType)i);
- mWearableEntry[i].mWearable = wearable;
- // no need to update here...
- LLPointer cb =
- new addWearableToAgentInventoryCallback(
- donecb,
- i,
- wearable,
- addWearableToAgentInventoryCallback::CALL_CREATESTANDARDDONE);
- addWearableToAgentInventory(cb, wearable, LLUUID::null, FALSE);
- }
- }
-}
-void LLAgent::createStandardWearablesDone(S32 index)
-{
- LLWearable* wearable = mWearableEntry[index].mWearable;
-
- if (wearable)
- {
- wearable->writeToAvatar(TRUE);
- }
-}
-
-void LLAgent::createStandardWearablesAllDone()
-{
- // ... because sendAgentWearablesUpdate will notify inventory
- // observers.
- mWearablesLoaded = TRUE;
- sendAgentWearablesUpdate();
- sendAgentSetAppearance();
-
- // Treat this as the first texture entry message, if none received yet
- mAvatarObject->onFirstTEMessageReceived();
-}
-
-void LLAgent::makeNewOutfit(
- const std::string& new_folder_name,
- const LLDynamicArray& wearables_to_include,
- const LLDynamicArray& attachments_to_include,
- BOOL rename_clothing)
-{
- if (mAvatarObject.isNull())
- {
- return;
- }
-
- // First, make a folder in the Clothes directory.
- LLUUID folder_id = gInventory.createNewCategory(
- gInventory.findCategoryUUIDForType(LLAssetType::AT_CLOTHING),
- LLAssetType::AT_NONE,
- new_folder_name);
-
- bool found_first_item = false;
-
- ///////////////////
- // Wearables
-
- if( wearables_to_include.count() )
- {
- // Then, iterate though each of the wearables and save copies of them in the folder.
- S32 i;
- S32 count = wearables_to_include.count();
- LLDynamicArray delete_items;
- LLPointer cbdone = NULL;
- for( i = 0; i < count; ++i )
- {
- S32 index = wearables_to_include[i];
- LLWearable* old_wearable = mWearableEntry[ index ].mWearable;
- if( old_wearable )
- {
- std::string new_name;
- LLWearable* new_wearable;
- new_wearable = gWearableList.createCopy(old_wearable);
- if (rename_clothing)
- {
- new_name = new_folder_name;
- new_name.append(" ");
- new_name.append(old_wearable->getTypeLabel());
- LLStringUtil::truncate(new_name, DB_INV_ITEM_NAME_STR_LEN);
- new_wearable->setName(new_name);
- }
-
- LLViewerInventoryItem* item = gInventory.getItem(mWearableEntry[index].mItemID);
- S32 todo = addWearableToAgentInventoryCallback::CALL_NONE;
- if (!found_first_item)
- {
- found_first_item = true;
- /* set the focus to the first item */
- todo |= addWearableToAgentInventoryCallback::CALL_MAKENEWOUTFITDONE;
- /* send the agent wearables update when done */
- cbdone = new sendAgentWearablesUpdateCallback;
- }
- LLPointer cb =
- new addWearableToAgentInventoryCallback(
- cbdone,
- index,
- new_wearable,
- todo);
- if (isWearableCopyable((EWearableType)index))
- {
- copy_inventory_item(
- gAgent.getID(),
- item->getPermissions().getOwner(),
- item->getUUID(),
- folder_id,
- new_name,
- cb);
- }
- else
- {
- move_inventory_item(
- gAgent.getID(),
- gAgent.getSessionID(),
- item->getUUID(),
- folder_id,
- new_name,
- cb);
- }
- }
- }
- gInventory.notifyObservers();
- }
-
-
- ///////////////////
- // Attachments
-
- if( attachments_to_include.count() )
- {
- BOOL msg_started = FALSE;
- LLMessageSystem* msg = gMessageSystem;
- for( S32 i = 0; i < attachments_to_include.count(); i++ )
- {
- S32 attachment_pt = attachments_to_include[i];
- LLViewerJointAttachment* attachment = get_if_there(mAvatarObject->mAttachmentPoints, attachment_pt, (LLViewerJointAttachment*)NULL );
- if(!attachment) continue;
- LLViewerObject* attached_object = attachment->getObject();
- if(!attached_object) continue;
- const LLUUID& item_id = attachment->getItemID();
- if(item_id.isNull()) continue;
- LLInventoryItem* item = gInventory.getItem(item_id);
- if(!item) continue;
- if(!msg_started)
- {
- msg_started = TRUE;
- msg->newMessage("CreateNewOutfitAttachments");
- msg->nextBlock("AgentData");
- msg->addUUID("AgentID", getID());
- msg->addUUID("SessionID", getSessionID());
- msg->nextBlock("HeaderData");
- msg->addUUID("NewFolderID", folder_id);
- }
- msg->nextBlock("ObjectData");
- msg->addUUID("OldItemID", item_id);
- msg->addUUID("OldFolderID", item->getParentUUID());
- }
-
- if( msg_started )
- {
- sendReliableMessage();
- }
-
- }
-}
-
-void LLAgent::makeNewOutfitDone(S32 index)
-{
- LLUUID first_item_id = mWearableEntry[index].mItemID;
- // Open the inventory and select the first item we added.
- if( first_item_id.notNull() )
- {
- LLInventoryView* view = LLInventoryView::getActiveInventory();
- if(view)
- {
- view->getPanel()->setSelection(first_item_id, TAKE_FOCUS_NO);
- }
- }
-}
-
-
-void LLAgent::addWearableToAgentInventory(
- LLPointer cb,
- LLWearable* wearable,
- const LLUUID& category_id,
- BOOL notify)
-{
- create_inventory_item(
- gAgent.getID(),
- gAgent.getSessionID(),
- category_id,
- wearable->getTransactionID(),
- wearable->getName(),
- wearable->getDescription(),
- wearable->getAssetType(),
- LLInventoryType::IT_WEARABLE,
- wearable->getType(),
- wearable->getPermissions().getMaskNextOwner(),
- cb);
-}
-
-//-----------------------------------------------------------------------------
-// sendAgentSetAppearance()
-//-----------------------------------------------------------------------------
-void LLAgent::sendAgentSetAppearance()
-{
- if (mAvatarObject.isNull()) return;
-
- if (mNumPendingQueries > 0 && !gAgent.cameraCustomizeAvatar())
- {
- return;
- }
-
-
- llinfos << "TAT: Sent AgentSetAppearance: " << mAvatarObject->getBakedStatusForPrintout() << llendl;
- //dumpAvatarTEs( "sendAgentSetAppearance()" );
-
- LLMessageSystem* msg = gMessageSystem;
- msg->newMessageFast(_PREHASH_AgentSetAppearance);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, getID());
- msg->addUUIDFast(_PREHASH_SessionID, getSessionID());
-
- // correct for the collision tolerance (to make it look like the
- // agent is actually walking on the ground/object)
- // NOTE -- when we start correcting all of the other Havok geometry
- // to compensate for the COLLISION_TOLERANCE ugliness we will have
- // to tweak this number again
- const LLVector3 body_size = mAvatarObject->mBodySize;
- msg->addVector3Fast(_PREHASH_Size, body_size);
-
- // To guard against out of order packets
- // Note: always start by sending 1. This resets the server's count. 0 on the server means "uninitialized"
- mAppearanceSerialNum++;
- msg->addU32Fast(_PREHASH_SerialNum, mAppearanceSerialNum );
-
- // is texture data current relative to wearables?
- // KLW - TAT this will probably need to check the local queue.
- BOOL textures_current = !mAvatarObject->hasPendingBakedUploads() && mWearablesLoaded;
-
- for(U8 baked_index = 0; baked_index < BAKED_NUM_INDICES; baked_index++ )
- {
- const ETextureIndex texture_index = getTextureIndex((EBakedTextureIndex)baked_index);
-
- // if we're not wearing a skirt, we don't need the texture to be baked
- if (texture_index == TEX_SKIRT_BAKED && !mAvatarObject->isWearingWearableType(WT_SKIRT))
- {
- continue;
- }
-
- // IMG_DEFAULT_AVATAR means not baked
- if (!mAvatarObject->isTextureDefined(texture_index))
- {
- textures_current = FALSE;
- break;
- }
- }
-
- // only update cache entries if we have all our baked textures
- if (textures_current)
- {
- llinfos << "TAT: Sending cached texture data" << llendl;
- for (U8 baked_index = 0; baked_index < BAKED_NUM_INDICES; baked_index++)
- {
- const LLVOAvatarDictionary::WearableDictionaryEntry *wearable_dict = LLVOAvatarDictionary::getInstance()->getWearable((EBakedTextureIndex)baked_index);
- LLUUID hash;
- for (U8 i=0; i < wearable_dict->mWearablesVec.size(); i++)
- {
- // EWearableType wearable_type = gBakedWearableMap[baked_index][wearable_num];
- const EWearableType wearable_type = wearable_dict->mWearablesVec[i];
- const LLWearable* wearable = getWearable(wearable_type);
- if (wearable)
- {
- hash ^= wearable->getID();
- }
- }
- if (hash.notNull())
- {
- hash ^= wearable_dict->mHashID;
- }
-
- const ETextureIndex texture_index = getTextureIndex((EBakedTextureIndex)baked_index);
-
- msg->nextBlockFast(_PREHASH_WearableData);
- msg->addUUIDFast(_PREHASH_CacheID, hash);
- msg->addU8Fast(_PREHASH_TextureIndex, (U8)texture_index);
- }
- msg->nextBlockFast(_PREHASH_ObjectData);
-
- // Tag changing support
- if (!gSavedSettings.controlExists("SpoofClientUUID"))
- {
- gSavedSettings.declareString("SpoofClientUUID", "8873757c-092a-98fb-1afd-ecd347566fcd", "FAKIN' BAKE-IN");
- gSavedSettings.setString("SpoofClientUUID", "8873757c-092a-98fb-1afd-ecd347566fcd");
- }
-
- mAvatarObject->packTEMessage( gMessageSystem, 1, gSavedSettings.getString("SpoofClientUUID") );
- }
- else
- {
- // If the textures aren't baked, send NULL for texture IDs
- // This means the baked texture IDs on the server will be untouched.
- // Once all textures are baked, another AvatarAppearance message will be sent to update the TEs
- msg->nextBlockFast(_PREHASH_ObjectData);
- gMessageSystem->addBinaryDataFast(_PREHASH_TextureEntry, NULL, 0);
- }
-
-
- S32 transmitted_params = 0;
- for (LLViewerVisualParam* param = (LLViewerVisualParam*)mAvatarObject->getFirstVisualParam();
- param;
- param = (LLViewerVisualParam*)mAvatarObject->getNextVisualParam())
- {
- if (param->getGroup() == VISUAL_PARAM_GROUP_TWEAKABLE)
- {
- msg->nextBlockFast(_PREHASH_VisualParam );
-
- // We don't send the param ids. Instead, we assume that the receiver has the same params in the same sequence.
- const F32 param_value = param->getWeight();
- const U8 new_weight = F32_to_U8(param_value, param->getMinWeight(), param->getMaxWeight());
- msg->addU8Fast(_PREHASH_ParamValue, new_weight );
- transmitted_params++;
- }
- }
-
-// llinfos << "Avatar XML num VisualParams transmitted = " << transmitted_params << llendl;
- sendReliableMessage();
-}
-
-void LLAgent::sendAgentDataUpdateRequest()
-{
- gMessageSystem->newMessageFast(_PREHASH_AgentDataUpdateRequest);
- gMessageSystem->nextBlockFast(_PREHASH_AgentData);
- gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
- gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- sendReliableMessage();
-}
-
-void LLAgent::removeWearable( EWearableType type )
-{
- LLWearable* old_wearable = mWearableEntry[ type ].mWearable;
-
- if ( (gAgent.isTeen())
- && (type == WT_UNDERSHIRT || type == WT_UNDERPANTS))
- {
- // Can't take off underclothing in simple UI mode or on PG accounts
- return;
- }
-
- if( old_wearable )
- {
- if( old_wearable->isDirty() )
- {
- LLSD payload;
- payload["wearable_type"] = (S32)type;
- // Bring up view-modal dialog: Save changes? Yes, No, Cancel
- LLNotifications::instance().add("WearableSave", LLSD(), payload, &LLAgent::onRemoveWearableDialog);
- return;
- }
- else
- {
- removeWearableFinal( type );
- }
- }
-}
-
-// static
-bool LLAgent::onRemoveWearableDialog(const LLSD& notification, const LLSD& response )
-{
- S32 option = LLNotification::getSelectedOption(notification, response);
- EWearableType type = (EWearableType)notification["payload"]["wearable_type"].asInteger();
- switch( option )
- {
- case 0: // "Save"
- gAgent.saveWearable( type );
- gAgent.removeWearableFinal( type );
- break;
-
- case 1: // "Don't Save"
- gAgent.removeWearableFinal( type );
- break;
-
- case 2: // "Cancel"
- break;
-
- default:
- llassert(0);
- break;
- }
- return false;
-}
-
-// Called by removeWearable() and onRemoveWearableDialog() to actually do the removal.
-void LLAgent::removeWearableFinal( EWearableType type )
-{
- LLWearable* old_wearable = mWearableEntry[ type ].mWearable;
-
- gInventory.addChangedMask( LLInventoryObserver::LABEL, mWearableEntry[type].mItemID );
-
- mWearableEntry[ type ].mWearable = NULL;
- mWearableEntry[ type ].mItemID.setNull();
-
- queryWearableCache();
-
- if( old_wearable )
- {
- old_wearable->removeFromAvatar( TRUE );
- }
-
- // Update the server
- sendAgentWearablesUpdate();
- sendAgentSetAppearance();
- gInventory.notifyObservers();
-}
-
-void LLAgent::copyWearableToInventory( EWearableType type )
-{
- LLWearable* wearable = mWearableEntry[ type ].mWearable;
- if( wearable )
- {
- // Save the old wearable if it has changed.
- if( wearable->isDirty() )
- {
- wearable = gWearableList.createCopyFromAvatar( wearable );
- mWearableEntry[ type ].mWearable = wearable;
- }
-
- // Make a new entry in the inventory. (Put it in the same folder as the original item if possible.)
- LLUUID category_id;
- LLInventoryItem* item = gInventory.getItem( mWearableEntry[ type ].mItemID );
- if( item )
- {
- category_id = item->getParentUUID();
- wearable->setPermissions(item->getPermissions());
- }
- LLPointer cb =
- new addWearableToAgentInventoryCallback(
- LLPointer(NULL),
- type,
- wearable);
- addWearableToAgentInventory(cb, wearable, category_id);
- }
-}
-
-
-// A little struct to let setWearable() communicate more than one value with onSetWearableDialog().
-struct LLSetWearableData
-{
- LLSetWearableData( const LLUUID& new_item_id, LLWearable* new_wearable ) :
- mNewItemID( new_item_id ), mNewWearable( new_wearable ) {}
- LLUUID mNewItemID;
- LLWearable* mNewWearable;
-};
-
-BOOL LLAgent::needsReplacement(EWearableType wearableType, S32 remove)
-{
- return TRUE;
- /*if (remove) return TRUE;
-
- return getWearable(wearableType) ? TRUE : FALSE;*/
-}
-
-// Assumes existing wearables are not dirty.
-void LLAgent::setWearableOutfit(
- const LLInventoryItem::item_array_t& items,
- const LLDynamicArray< LLWearable* >& wearables,
- BOOL remove )
-{
- lldebugs << "setWearableOutfit() start" << llendl;
-
- BOOL wearables_to_remove[WT_COUNT];
- wearables_to_remove[WT_SHAPE] = FALSE;
- wearables_to_remove[WT_SKIN] = FALSE;
- wearables_to_remove[WT_HAIR] = FALSE;
- wearables_to_remove[WT_EYES] = FALSE;
- wearables_to_remove[WT_SHIRT] = remove;
- wearables_to_remove[WT_PANTS] = remove;
- wearables_to_remove[WT_SHOES] = remove;
- wearables_to_remove[WT_SOCKS] = remove;
- wearables_to_remove[WT_JACKET] = remove;
- wearables_to_remove[WT_GLOVES] = remove;
- wearables_to_remove[WT_UNDERSHIRT] = (!gAgent.isTeen()) & remove;
- wearables_to_remove[WT_UNDERPANTS] = (!gAgent.isTeen()) & remove;
- wearables_to_remove[WT_SKIRT] = remove;
- wearables_to_remove[WT_ALPHA] = remove;
- wearables_to_remove[WT_TATTOO] = remove;
-
- S32 count = wearables.count();
- llassert( items.count() == count );
-
- S32 i;
- for( i = 0; i < count; i++ )
- {
- LLWearable* new_wearable = wearables[i];
- LLPointer new_item = items[i];
-
- EWearableType type = new_wearable->getType();
- wearables_to_remove[type] = FALSE;
-
- LLWearable* old_wearable = mWearableEntry[ type ].mWearable;
- if( old_wearable )
- {
- const LLUUID& old_item_id = mWearableEntry[ type ].mItemID;
- if( (old_wearable->getID() == new_wearable->getID()) &&
- (old_item_id == new_item->getUUID()) )
- {
- lldebugs << "No change to wearable asset and item: " << LLWearable::typeToTypeName( type ) << llendl;
- continue;
- }
-
- gInventory.addChangedMask(LLInventoryObserver::LABEL, old_item_id);
-
- // Assumes existing wearables are not dirty.
- if( old_wearable->isDirty() )
- {
- llassert(0);
- continue;
- }
- }
-
- mWearableEntry[ type ].mItemID = new_item->getUUID();
- mWearableEntry[ type ].mWearable = new_wearable;
- }
-
- std::vector wearables_being_removed;
-
- for( i = 0; i < WT_COUNT; i++ )
- {
- if( wearables_to_remove[i] )
- {
- wearables_being_removed.push_back(mWearableEntry[ i ].mWearable);
- mWearableEntry[ i ].mWearable = NULL;
-
- gInventory.addChangedMask(LLInventoryObserver::LABEL, mWearableEntry[ i ].mItemID);
- mWearableEntry[ i ].mItemID.setNull();
- }
- }
-
- gInventory.notifyObservers();
-
- queryWearableCache();
-
- std::vector::iterator wearable_iter;
-
- for( wearable_iter = wearables_being_removed.begin();
- wearable_iter != wearables_being_removed.end();
- ++wearable_iter)
- {
- LLWearable* wearablep = *wearable_iter;
- if (wearablep)
- {
- wearablep->removeFromAvatar( TRUE );
- }
- }
-
- for( i = 0; i < count; i++ )
- {
- wearables[i]->writeToAvatar( TRUE );
- }
-
- // Start rendering & update the server
- mWearablesLoaded = TRUE;
- sendAgentWearablesUpdate();
- sendAgentSetAppearance();
-
- lldebugs << "setWearableOutfit() end" << llendl;
-}
-
-
-// User has picked "wear on avatar" from a menu.
-void LLAgent::setWearable( LLInventoryItem* new_item, LLWearable* new_wearable )
-{
- EWearableType type = new_wearable->getType();
-
- LLWearable* old_wearable = mWearableEntry[ type ].mWearable;
- if( old_wearable )
- {
- const LLUUID& old_item_id = mWearableEntry[ type ].mItemID;
- if( (old_wearable->getID() == new_wearable->getID()) &&
- (old_item_id == new_item->getUUID()) )
- {
- lldebugs << "No change to wearable asset and item: " << LLWearable::typeToTypeName( type ) << llendl;
- return;
- }
-
- if( old_wearable->isDirty() )
- {
- // Bring up modal dialog: Save changes? Yes, No, Cancel
- LLSD payload;
- payload["item_id"] = new_item->getUUID();
- LLNotifications::instance().add( "WearableSave", LLSD(), payload, boost::bind(LLAgent::onSetWearableDialog, _1, _2, new_wearable));
- return;
- }
- }
-
- setWearableFinal( new_item, new_wearable );
-}
-
-// static
-bool LLAgent::onSetWearableDialog( const LLSD& notification, const LLSD& response, LLWearable* wearable )
-{
- S32 option = LLNotification::getSelectedOption(notification, response);
- LLInventoryItem* new_item = gInventory.getItem( notification["payload"]["item_id"].asUUID());
- if( !new_item )
- {
- delete wearable;
- return false;
- }
-
- switch( option )
- {
- case 0: // "Save"
- gAgent.saveWearable( wearable->getType() );
- gAgent.setWearableFinal( new_item, wearable );
- break;
-
- case 1: // "Don't Save"
- gAgent.setWearableFinal( new_item, wearable );
- break;
-
- case 2: // "Cancel"
- break;
-
- default:
- llassert(0);
- break;
- }
-
- delete wearable;
- return false;
-}
-
-// Called from setWearable() and onSetWearableDialog() to actually set the wearable.
-void LLAgent::setWearableFinal( LLInventoryItem* new_item, LLWearable* new_wearable )
-{
- EWearableType type = new_wearable->getType();
-
- // Replace the old wearable with a new one.
- llassert( new_item->getAssetUUID() == new_wearable->getID() );
- LLUUID old_item_id = mWearableEntry[ type ].mItemID;
- mWearableEntry[ type ].mItemID = new_item->getUUID();
- mWearableEntry[ type ].mWearable = new_wearable;
-
- if (old_item_id.notNull())
- {
- gInventory.addChangedMask( LLInventoryObserver::LABEL, old_item_id );
- gInventory.notifyObservers();
- }
-
- //llinfos << "LLVOAvatar::setWearable()" << llendl;
- queryWearableCache();
- new_wearable->writeToAvatar( TRUE );
-
- // Update the server
- sendAgentWearablesUpdate();
- sendAgentSetAppearance();
-}
-
-void LLAgent::queryWearableCache()
-{
- if (!mWearablesLoaded)
- {
- return;
- }
-
- // Look up affected baked textures.
- // If they exist:
- // disallow updates for affected layersets (until dataserver responds with cache request.)
- // If cache miss, turn updates back on and invalidate composite.
- // If cache hit, modify baked texture entries.
- //
- // Cache requests contain list of hashes for each baked texture entry.
- // Response is list of valid baked texture assets. (same message)
-
- gMessageSystem->newMessageFast(_PREHASH_AgentCachedTexture);
- gMessageSystem->nextBlockFast(_PREHASH_AgentData);
- gMessageSystem->addUUIDFast(_PREHASH_AgentID, getID());
- gMessageSystem->addUUIDFast(_PREHASH_SessionID, getSessionID());
- gMessageSystem->addS32Fast(_PREHASH_SerialNum, mTextureCacheQueryID);
-
- S32 num_queries = 0;
- for (U8 baked_index = 0; baked_index < BAKED_NUM_INDICES; baked_index++ )
- {
- const LLVOAvatarDictionary::WearableDictionaryEntry *wearable_dict = LLVOAvatarDictionary::getInstance()->getWearable((EBakedTextureIndex)baked_index);
- LLUUID hash;
- for (U8 i=0; i < wearable_dict->mWearablesVec.size(); i++)
- {
- // EWearableType wearable_type = gBakedWearableMap[baked_index][wearable_num];
- const EWearableType wearable_type = wearable_dict->mWearablesVec[i];
- const LLWearable* wearable = getWearable(wearable_type);
- if (wearable)
- {
- hash ^= wearable->getID();
- }
- }
- if (hash.notNull())
- {
- hash ^= wearable_dict->mHashID;
- num_queries++;
- // *NOTE: make sure at least one request gets packed
-
- //llinfos << "Requesting texture for hash " << hash << " in baked texture slot " << baked_index << llendl;
- gMessageSystem->nextBlockFast(_PREHASH_WearableData);
- gMessageSystem->addUUIDFast(_PREHASH_ID, hash);
- gMessageSystem->addU8Fast(_PREHASH_TextureIndex, (U8)baked_index);
- }
-
- mActiveCacheQueries[ baked_index ] = mTextureCacheQueryID;
- }
-
- llinfos << "Requesting texture cache entry for " << num_queries << " baked textures" << llendl;
- gMessageSystem->sendReliable(getRegion()->getHost());
- mNumPendingQueries++;
- mTextureCacheQueryID++;
-}
-
-// User has picked "remove from avatar" from a menu.
-// static
-void LLAgent::userRemoveWearable( void* userdata )
-{
- EWearableType type = (EWearableType)(intptr_t)userdata;
-
- if( !(type==WT_SHAPE || type==WT_SKIN || type==WT_HAIR || type==WT_EYES) ) //&&
- //!((!gAgent.isTeen()) && ( type==WT_UNDERPANTS || type==WT_UNDERSHIRT )) )
- {
- gAgent.removeWearable( type );
- }
-}
-
-void LLAgent::userRemoveAllClothes( void* userdata )
-{
- // We have to do this up front to avoid having to deal with the case of multiple wearables being dirty.
- if( gFloaterCustomize )
- {
- gFloaterCustomize->askToSaveIfDirty( LLAgent::userRemoveAllClothesStep2, NULL );
- }
- else
- {
- LLAgent::userRemoveAllClothesStep2( TRUE, NULL );
- }
-}
-
-void LLAgent::userRemoveAllClothesStep2( BOOL proceed, void* userdata )
-{
- if( proceed )
- {
- gAgent.removeWearable( WT_SHIRT );
- gAgent.removeWearable( WT_PANTS );
- gAgent.removeWearable( WT_SHOES );
- gAgent.removeWearable( WT_SOCKS );
- gAgent.removeWearable( WT_JACKET );
- gAgent.removeWearable( WT_GLOVES );
- gAgent.removeWearable( WT_UNDERSHIRT );
- gAgent.removeWearable( WT_UNDERPANTS );
- gAgent.removeWearable( WT_SKIRT );
- gAgent.removeWearable( WT_ALPHA );
- gAgent.removeWearable( WT_TATTOO );
- }
-}
-
-void LLAgent::userRemoveAllAttachments( void* userdata )
-{
- LLVOAvatar* avatarp = gAgent.getAvatarObject();
- if(!avatarp)
- {
- llwarns << "No avatar found." << llendl;
- return;
- }
-
- gMessageSystem->newMessage("ObjectDetach");
- gMessageSystem->nextBlockFast(_PREHASH_AgentData);
- gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
- gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
-
- for (LLVOAvatar::attachment_map_t::iterator iter = avatarp->mAttachmentPoints.begin();
- iter != avatarp->mAttachmentPoints.end(); )
- {
- LLVOAvatar::attachment_map_t::iterator curiter = iter++;
- LLViewerJointAttachment* attachment = curiter->second;
- LLViewerObject* objectp = attachment->getObject();
- if (objectp)
- {
- gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
- gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, objectp->getLocalID());
- }
- }
- gMessageSystem->sendReliable( gAgent.getRegionHost() );
-}
-
-void LLAgent::observeFriends()
-{
- if(!mFriendObserver)
- {
- mFriendObserver = new LLAgentFriendObserver;
- LLAvatarTracker::instance().addObserver(mFriendObserver);
- friendsChanged();
- }
-}
-
-void LLAgent::parseTeleportMessages(const std::string& xml_filename)
-{
- LLXMLNodePtr root;
- BOOL success = LLUICtrlFactory::getLayeredXMLNode(xml_filename, root);
-
- if (!success || !root || !root->hasName( "teleport_messages" ))
- {
- llerrs << "Problem reading teleport string XML file: "
- << xml_filename << llendl;
- return;
- }
-
- for (LLXMLNode* message_set = root->getFirstChild();
- message_set != NULL;
- message_set = message_set->getNextSibling())
- {
- if ( !message_set->hasName("message_set") ) continue;
-
- std::map *teleport_msg_map = NULL;
- std::string message_set_name;
-
- if ( message_set->getAttributeString("name", message_set_name) )
- {
- //now we loop over all the string in the set and add them
- //to the appropriate set
- if ( message_set_name == "errors" )
- {
- teleport_msg_map = &sTeleportErrorMessages;
- }
- else if ( message_set_name == "progress" )
- {
- teleport_msg_map = &sTeleportProgressMessages;
- }
- }
-
- if ( !teleport_msg_map ) continue;
-
- std::string message_name;
- for (LLXMLNode* message_node = message_set->getFirstChild();
- message_node != NULL;
- message_node = message_node->getNextSibling())
- {
- if ( message_node->hasName("message") &&
- message_node->getAttributeString("name", message_name) )
- {
- (*teleport_msg_map)[message_name] =
- message_node->getTextContents();
- } //end if ( message exists and has a name)
- } //end for (all message in set)
- }//end for (all message sets in xml file)
-}
-
-// OGPX - This code will change when capabilities get refactored.
-// Right now this is used for capabilities that we get from OGP agent domain
-void LLAgent::setCapability(const std::string& name, const std::string& url)
-{
-#if 0 // OGPX : I think (hope?) we don't need this
- // but I'm leaving it here commented out because I'm not quite
- // sure why the region capabilities code had it wedged in setCap call
- // Maybe the agent domain capabilities will need something like this as well
-
- if (name == "EventQueueGet")
- {
- delete mEventPoll;
- mEventPoll = NULL;
- mEventPoll = new LLEventPoll(url, getHost());
- }
- else if (name == "UntrustedSimulatorMessage")
- {
- LLHTTPSender::setSender(mHost, new LLCapHTTPSender(url));
- }
- else
-#endif
- {
- mCapabilities[name] = url;
- }
-}
-
-//OGPX : Agent Domain capabilities... this needs to be refactored
-std::string LLAgent::getCapability(const std::string& name) const
-{
- CapabilityMap::const_iterator iter = mCapabilities.find(name);
- if (iter == mCapabilities.end())
- {
- return "";
- }
- return iter->second;
-}
-//
-
-void LLAgent::showLureDestination(const std::string fromname, const int global_x, const int global_y, const int x, const int y, const int z, const std::string maturity)
-{
- const LLVector3d posglobal = LLVector3d(F64(global_x), F64(global_y), F64(0));
- LLSimInfo* siminfo;
- siminfo = LLWorldMap::getInstance()->simInfoFromPosGlobal(posglobal);
- if(siminfo)
- {
- llinfos << fromname << "'s teleport lure is to " << siminfo->getName() << " (" << maturity << ")" << llendl;
- std::string url = LLURLDispatcher::buildSLURL(siminfo->getName(), S32(x), S32(y), S32(z));
- std::string msg;
- msg = llformat("%s's teleport lure is to %s", fromname.c_str(), url.c_str());
- if(maturity != "")
- msg.append(llformat(" (%s)", maturity.c_str()));
- LLChat chat(msg);
- LLFloaterChat::addChat(chat);
- }
- else
- {
- LLAgent::lure_show = TRUE;
- LLAgent::lure_name = fromname;
- LLAgent::lure_posglobal = posglobal;
- LLAgent::lure_global_x = U16(global_x / 256);
- LLAgent::lure_global_y = U16(global_y / 256);
- LLAgent::lure_x = x;
- LLAgent::lure_y = y;
- LLAgent::lure_z = z;
- LLAgent::lure_maturity = maturity;
- LLWorldMapMessage::getInstance()->sendMapBlockRequest(lure_global_x, lure_global_y, lure_global_x, lure_global_y, true);
- }
-}
-
-void LLAgent::onFoundLureDestination()
-{
- LLAgent::lure_show = FALSE;
- LLSimInfo* siminfo;
- siminfo = LLWorldMap::getInstance()->simInfoFromPosGlobal(LLAgent::lure_posglobal);
- if(siminfo)
- {
- llinfos << LLAgent::lure_name << "'s teleport lure is to " << siminfo->getName() << " (" << LLAgent::lure_maturity << ")" << llendl;
- std::string url = LLURLDispatcher::buildSLURL(siminfo->getName(), S32(LLAgent::lure_x), S32(LLAgent::lure_y), S32(LLAgent::lure_z));
- std::string msg;
- msg = llformat("%s's teleport lure is to %s", LLAgent::lure_name.c_str(), url.c_str());
- if(LLAgent::lure_maturity != "")
- msg.append(llformat(" (%s)", LLAgent::lure_maturity.c_str()));
- LLChat chat(msg);
- LLFloaterChat::addChat(chat);
- }
- else
- llwarns << "Grand scheme failed" << llendl;
-}
-
-//
-
-// EOF
-
+/**
+ * @file llagent.cpp
+ * @brief LLAgent class implementation
+ *
+ * $LicenseInfo:firstyear=2001&license=viewergpl$
+ *
+ * Copyright (c) 2001-2009, Linden Research, Inc.
+ *
+ * Second Life Viewer Source Code
+ * The source code in this file ("Source Code") is provided by Linden Lab
+ * to you under the terms of the GNU General Public License, version 2.0
+ * ("GPL"), unless you have obtained a separate licensing agreement
+ * ("Other License"), formally executed by you and Linden Lab. Terms of
+ * the GPL can be found in doc/GPL-license.txt in this distribution, or
+ * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * There are special exceptions to the terms and conditions of the GPL as
+ * it is applied to this Source Code. View the full text of the exception
+ * in the file doc/FLOSS-exception.txt in this software distribution, or
+ * online at
+ * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * By copying, modifying or distributing this software, you acknowledge
+ * that you have read and understood your obligations described above,
+ * and agree to abide by those obligations.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "stdtypes.h"
+#include "stdenums.h"
+
+#include "llagent.h"
+
+#include "llcamera.h"
+#include "llcoordframe.h"
+#include "indra_constants.h"
+#include "llmath.h"
+#include "llcriticaldamp.h"
+#include "llfocusmgr.h"
+#include "llglheaders.h"
+#include "llparcel.h"
+#include "llpermissions.h"
+#include "llregionhandle.h"
+#include "m3math.h"
+#include "m4math.h"
+#include "message.h"
+#include "llquaternion.h"
+#include "v3math.h"
+#include "v4math.h"
+#include "llsmoothstep.h"
+#include "llsdutil.h"
+//#include "vmath.h"
+
+#include "imageids.h"
+#include "llbox.h"
+#include "llbutton.h"
+#include "llcallingcard.h"
+#include "llchatbar.h"
+#include "llconsole.h"
+#include "lldrawable.h"
+#include "llface.h"
+#include "llfirstuse.h"
+#include "llfloater.h"
+#include "llfloateractivespeakers.h"
+#include "llfloateravatarinfo.h"
+#include "llfloaterbuildoptions.h"
+#include "llfloatercamera.h"
+#include "llfloaterchat.h"
+#include "llfloatercustomize.h"
+#include "llfloaterdirectory.h"
+#include "llfloatergroupinfo.h"
+#include "llfloatergroups.h"
+#include "llfloaterland.h"
+#include "llfloatermap.h"
+#include "llfloatermute.h"
+#include "llfloatersnapshot.h"
+#include "llfloatertools.h"
+#include "llfloaterworldmap.h"
+#include "llgroupmgr.h"
+#include "llhomelocationresponder.h"
+#include "llhudeffectlookat.h"
+#include "llhudmanager.h"
+#include "llinventorymodel.h"
+#include "llinventoryview.h"
+#include "lljoystickbutton.h"
+#include "llmenugl.h"
+#include "llmorphview.h"
+#include "llmoveview.h"
+#include "llnotify.h"
+#include "llquantize.h"
+#include "llsdutil.h"
+#include "llselectmgr.h"
+#include "llsky.h"
+#include "llrendersphere.h"
+#include "llstatusbar.h"
+#include "llstartup.h"
+#include "llimview.h"
+#include "lltexturestats.h"
+#include "lltool.h"
+#include "lltoolcomp.h"
+#include "lltoolfocus.h"
+#include "lltoolgrab.h"
+#include "lltoolmgr.h"
+#include "lltoolpie.h"
+#include "lltoolview.h"
+#include "llui.h" // for make_ui_sound
+#include "llurldispatcher.h"
+#include "llviewercamera.h"
+#include "llviewerinventory.h"
+#include "llviewermediafocus.h"
+#include "llviewermenu.h"
+#include "llviewernetwork.h"
+#include "llviewerobjectlist.h"
+#include "llviewerparcelmgr.h"
+#include "llviewerparceloverlay.h"
+#include "llviewerregion.h"
+#include "llviewerstats.h"
+#include "llviewerwindow.h"
+#include "llviewerdisplay.h"
+#include "llvoavatar.h"
+#include "llvoground.h"
+#include "llvosky.h"
+#include "llwearable.h"
+#include "llwearablelist.h"
+#include "llworld.h"
+#include "llworldmap.h"
+#include "pipeline.h"
+#include "roles_constants.h"
+#include "llviewercontrol.h"
+#include "llappviewer.h"
+#include "llviewerjoystick.h"
+#include "llfollowcam.h"
+//
+#include "llao.h"
+#include "llworldmapmessage.h"
+//
+using namespace LLVOAvatarDefines;
+
+extern LLMenuBarGL* gMenuBarView;
+
+//drone wandering constants
+const F32 MAX_WANDER_TIME = 20.f; // seconds
+const F32 MAX_HEADING_HALF_ERROR = 0.2f; // radians
+const F32 WANDER_MAX_SLEW_RATE = 2.f * DEG_TO_RAD; // radians / frame
+const F32 WANDER_TARGET_MIN_DISTANCE = 10.f; // meters
+
+// Autopilot constants
+const F32 AUTOPILOT_HEADING_HALF_ERROR = 10.f * DEG_TO_RAD; // radians
+const F32 AUTOPILOT_MAX_SLEW_RATE = 1.f * DEG_TO_RAD; // radians / frame
+const F32 AUTOPILOT_STOP_DISTANCE = 2.f; // meters
+const F32 AUTOPILOT_HEIGHT_ADJUST_DISTANCE = 8.f; // meters
+const F32 AUTOPILOT_MIN_TARGET_HEIGHT_OFF_GROUND = 1.f; // meters
+const F32 AUTOPILOT_MAX_TIME_NO_PROGRESS = 1.5f; // seconds
+
+// face editing constants
+const LLVector3d FACE_EDIT_CAMERA_OFFSET(0.4f, -0.05f, 0.07f);
+const LLVector3d FACE_EDIT_TARGET_OFFSET(0.f, 0.f, 0.05f);
+
+// 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 METERS_PER_WHEEL_CLICK = 1.f;
+
+const F32 MAX_TIME_DELTA = 1.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.0f;
+const F32 MIN_CAMERA_DISTANCE = 0.0f;
+const F32 AVATAR_ZOOM_MIN_X_FACTOR = 0.0f;
+const F32 AVATAR_ZOOM_MIN_Y_FACTOR = 0.0f;
+const F32 AVATAR_ZOOM_MIN_Z_FACTOR = 0.0f;
+
+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.2f;
+
+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;
+
+// fidget constants
+const F32 MIN_FIDGET_TIME = 8.f; // seconds
+const F32 MAX_FIDGET_TIME = 20.f; // seconds
+
+const S32 MAX_NUM_CHAT_POSITIONS = 10;
+const F32 GROUND_TO_AIR_CAMERA_TRANSITION_TIME = 0.5f;
+const F32 GROUND_TO_AIR_CAMERA_TRANSITION_START_TIME = 0.5f;
+
+const F32 MAX_VELOCITY_AUTO_LAND_SQUARED = 4.f * 4.f;
+
+const F32 MAX_FOCUS_OFFSET = 20.f;
+
+const F32 OBJECT_EXTENTS_PADDING = 0.5f;
+
+const F32 MIN_RADIUS_ALPHA_SIZZLE = 0.5f;
+
+const F64 CHAT_AGE_FAST_RATE = 3.0;
+
+// The agent instance.
+LLAgent gAgent;
+//
+LLUUID gReSitTargetID;
+LLVector3 gReSitOffset;
+//
+//
+// Statics
+//
+
+//
+// For MapBlockReply funk 'cause I dunno what I'm doing
+BOOL LLAgent::lure_show = FALSE;
+std::string LLAgent::lure_name;
+LLVector3d LLAgent::lure_posglobal;
+U16 LLAgent::lure_global_x;
+U16 LLAgent::lure_global_y;
+int LLAgent::lure_x;
+int LLAgent::lure_y;
+int LLAgent::lure_z;
+std::string LLAgent::lure_maturity;
+
+//
+
+BOOL LLAgent::exlPhantom = 0;
+LLVector3 LLAgent::exlStartMeasurePoint = LLVector3::zero;
+LLVector3 LLAgent::exlEndMeasurePoint = LLVector3::zero;
+
+const F32 LLAgent::TYPING_TIMEOUT_SECS = 5.f;
+
+std::map LLAgent::sTeleportErrorMessages;
+std::map LLAgent::sTeleportProgressMessages;
+
+class LLAgentFriendObserver : public LLFriendObserver
+{
+public:
+ LLAgentFriendObserver() {}
+ virtual ~LLAgentFriendObserver() {}
+ virtual void changed(U32 mask);
+};
+
+void LLAgentFriendObserver::changed(U32 mask)
+{
+ // if there's a change we're interested in.
+ if((mask & (LLFriendObserver::POWERS)) != 0)
+ {
+ gAgent.friendsChanged();
+ }
+}
+
+// ************************************************************
+// Enabled this definition to compile a 'hacked' viewer that
+// locally believes the end user has godlike powers.
+// #define HACKED_GODLIKE_VIEWER
+// For a toggled version, see viewer.h for the
+// TOGGLE_HACKED_GODLIKE_VIEWER define, instead.
+// ************************************************************
+
+// Constructors and Destructors
+
+// JC - Please try to make this order match the order in the header
+// file. Otherwise it's hard to find variables that aren't initialized.
+//-----------------------------------------------------------------------------
+// LLAgent()
+//-----------------------------------------------------------------------------
+LLAgent::LLAgent() :
+ mDrawDistance( DEFAULT_FAR_PLANE ),
+
+ mGroupPowers(0),
+ mHideGroupTitle(FALSE),
+ mGroupID(),
+
+ mMapOriginX(0.F),
+ mMapOriginY(0.F),
+ mMapWidth(0),
+ mMapHeight(0),
+
+ mLookAt(NULL),
+ mPointAt(NULL),
+
+ mHUDTargetZoom(1.f),
+ mHUDCurZoom(1.f),
+ mInitialized(FALSE),
+ mNumPendingQueries(0),
+ mActiveCacheQueries(NULL),
+ mForceMouselook(FALSE),
+
+ mDoubleTapRunTimer(),
+ mDoubleTapRunMode(DOUBLETAP_NONE),
+
+ mbAlwaysRun(false),
+ mbRunning(false),
+
+ mAgentAccess(gSavedSettings),
+ mTeleportState( TELEPORT_NONE ),
+ mRegionp(NULL),
+
+ mAgentOriginGlobal(),
+ mPositionGlobal(),
+
+ mDistanceTraveled(0.F),
+ mLastPositionGlobal(LLVector3d::zero),
+
+ mAvatarObject(NULL),
+
+ mRenderState(0),
+ mTypingTimer(),
+
+ mCameraMode( CAMERA_MODE_THIRD_PERSON ),
+ mLastCameraMode( CAMERA_MODE_THIRD_PERSON ),
+ mViewsPushed(FALSE),
+
+ mCustomAnim(FALSE),
+ mShowAvatar(TRUE),
+ mCameraAnimating( FALSE ),
+ mAnimationCameraStartGlobal(),
+ mAnimationFocusStartGlobal(),
+ mAnimationTimer(),
+ mAnimationDuration(0.33f),
+
+ mCameraFOVZoomFactor(0.f),
+ mCameraCurrentFOVZoomFactor(0.f),
+ mCameraFocusOffset(),
+ mCameraFOVDefault(DEFAULT_FIELD_OF_VIEW),
+
+ mCameraOffsetDefault(),
+ 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),
+ mUIOffset(0.f),
+
+ mFrameAgent(),
+
+ mIsBusy(FALSE),
+
+ 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),
+
+ 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),
+
+ mControlFlags(0x00000000),
+ mbFlagsDirty(FALSE),
+ mbFlagsNeedReset(FALSE),
+
+ mbJump(FALSE),
+
+ mAutoPilot(FALSE),
+ mAutoPilotFlyOnStop(FALSE),
+ mAutoPilotTargetGlobal(),
+ mAutoPilotStopDistance(1.f),
+ mAutoPilotUseRotation(FALSE),
+ mAutoPilotTargetFacing(LLVector3::zero),
+ mAutoPilotTargetDist(0.f),
+ mAutoPilotNoProgressFrameCount(0),
+ mAutoPilotRotationThreshold(0.f),
+ mAutoPilotFinishedCallback(NULL),
+ mAutoPilotCallbackData(NULL),
+
+ mCapabilities(),
+
+ mEffectColor(0.f, 1.f, 1.f, 1.f),
+
+ mHaveHomePosition(FALSE),
+ mHomeRegionHandle( 0 ),
+ mNearChatRadius(CHAT_NORMAL_RADIUS / 2.f),
+
+ mNextFidgetTime(0.f),
+ mCurrentFidget(0),
+ mFirstLogin(FALSE),
+ mGenderChosen(FALSE),
+
+ mAgentWearablesUpdateSerialNum(0),
+ mWearablesLoaded(FALSE),
+ mTextureCacheQueryID(0),
+ mAppearanceSerialNum(0),
+ mbTeleportKeepsLookAt(false)
+{
+ U32 i;
+ for (i = 0; i < TOTAL_CONTROLS; i++)
+ {
+ mControlsTakenCount[i] = 0;
+ mControlsTakenPassedOnCount[i] = 0;
+ }
+
+ mActiveCacheQueries = new S32[BAKED_NUM_INDICES];
+ for (i = 0; i < (U32)BAKED_NUM_INDICES; i++)
+ {
+ mActiveCacheQueries[i] = 0;
+ }
+
+ mFollowCam.setMaxCameraDistantFromSubject( MAX_CAMERA_DISTANCE_FROM_AGENT );
+}
+
+// Requires gSavedSettings to be initialized.
+//-----------------------------------------------------------------------------
+// init()
+//-----------------------------------------------------------------------------
+void LLAgent::init()
+{
+ mDrawDistance = gSavedSettings.getF32("RenderFarClip");
+
+ // *Note: this is where LLViewerCamera::getInstance() used to be constructed.
+
+ 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->getDisplayAspectRatio() ); // default, overridden in LLViewerWindow::reshape
+ LLViewerCamera::getInstance()->setViewHeightInPixels(768); // default, overridden in LLViewerWindow::reshape
+
+ setFlying( gSavedSettings.getBOOL("FlyingAtExit") );
+
+ mCameraFocusOffsetTarget = LLVector4(gSavedSettings.getVector3("CameraOffsetBuild"));
+ mCameraOffsetDefault = gSavedSettings.getVector3("CameraOffsetDefault");
+ mCameraCollidePlane.clearVec();
+ mCurrentCameraDistance = mCameraOffsetDefault.magVec() * gSavedSettings.getF32("CameraOffsetScale");
+ mTargetCameraDistance = mCurrentCameraDistance;
+ mCameraZoomFraction = 1.f;
+ mTrackFocusObject = gSavedSettings.getBOOL("TrackFocusObject");
+
+// LLDebugVarMessageBox::show("Camera Lag", &CAMERA_FOCUS_HALF_LIFE, 0.5f, 0.01f);
+
+ if (!gSavedSettings.getBOOL("AscentStoreSettingsPerAccount"))
+ {
+ llinfos << "Using client effect color." << llendl;
+ mEffectColor = gSavedSettings.getColor4("EffectColor");
+ }
+ else
+ {
+ llinfos << "Using account effect color." << llendl;
+ mEffectColor = gSavedPerAccountSettings.getColor4("EffectColor");
+ }
+
+ mInitialized = TRUE;
+}
+
+//-----------------------------------------------------------------------------
+// cleanup()
+//-----------------------------------------------------------------------------
+void LLAgent::cleanup()
+{
+ setSitCamera(LLUUID::null);
+ mAvatarObject = NULL;
+ if(mLookAt)
+ {
+ mLookAt->markDead() ;
+ mLookAt = NULL;
+ }
+ if(mPointAt)
+ {
+ mPointAt->markDead() ;
+ mPointAt = NULL;
+ }
+ mRegionp = NULL;
+ setFocusObject(NULL);
+}
+
+//-----------------------------------------------------------------------------
+// LLAgent()
+//-----------------------------------------------------------------------------
+LLAgent::~LLAgent()
+{
+ cleanup();
+
+ delete [] mActiveCacheQueries;
+ mActiveCacheQueries = NULL;
+
+ // *Note: this is where LLViewerCamera::getInstance() used to be deleted.
+}
+
+// Change camera back to third person, stop the autopilot,
+// deselect stuff, etc.
+//-----------------------------------------------------------------------------
+// resetView()
+//-----------------------------------------------------------------------------
+void LLAgent::resetView(BOOL reset_camera, BOOL change_camera)
+{
+ if (mAutoPilot)
+ {
+ stopAutoPilot(TRUE);
+ }
+
+ if (!gNoRender)
+ {
+ 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();
+ }
+
+ // 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);
+ }
+
+ gFloaterTools->close();
+
+ gViewerWindow->showCursor();
+
+ // Switch back to basic toolset
+ LLToolMgr::getInstance()->setCurrentToolset(gBasicToolset);
+ }
+
+
+ if (reset_camera && !gSavedSettings.getBOOL("FreezeTime"))
+ {
+ if (!gViewerWindow->getLeftMouseDown() && cameraThirdPerson())
+ {
+ // leaving mouse-steer mode
+ LLVector3 agent_at_axis = getAtAxis();
+ agent_at_axis -= projected_vec(agent_at_axis, getReferenceUpVector());
+ agent_at_axis.normalize();
+ gAgent.resetAxes(lerp(getAtAxis(), agent_at_axis, LLCriticalDamp::getInterpolant(0.3f)));
+ }
+
+ setFocusOnAvatar(TRUE, ANIMATE);
+ }
+
+ mHUDTargetZoom = 1.f;
+}
+
+// Handle any actions that need to be performed when the main app gains focus
+// (such as through alt-tab).
+//-----------------------------------------------------------------------------
+// onAppFocusGained()
+//-----------------------------------------------------------------------------
+void LLAgent::onAppFocusGained()
+{
+ if (CAMERA_MODE_MOUSELOOK == mCameraMode)
+ {
+ changeCameraToDefault();
+ LLToolMgr::getInstance()->clearSavedTool();
+ }
+}
+
+
+void LLAgent::ageChat()
+{
+ if (mAvatarObject.notNull())
+ {
+ // get amount of time since I last chatted
+ F64 elapsed_time = (F64)mAvatarObject->mChatTimer.getElapsedTimeF32();
+ // add in frame time * 3 (so it ages 4x)
+ mAvatarObject->mChatTimer.setAge(elapsed_time + (F64)gFrameDTClamped * (CHAT_AGE_FAST_RATE - 1.0));
+ }
+}
+
+// Allow camera to be moved somewhere other than behind avatar.
+//-----------------------------------------------------------------------------
+// unlockView()
+//-----------------------------------------------------------------------------
+void LLAgent::unlockView()
+{
+ if (getFocusOnAvatar())
+ {
+ if (mAvatarObject.notNull())
+ {
+ setFocusGlobal( LLVector3d::zero, mAvatarObject->mID );
+ }
+ setFocusOnAvatar(FALSE, FALSE); // no animation
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// moveAt()
+//-----------------------------------------------------------------------------
+void LLAgent::moveAt(S32 direction, bool reset)
+{
+ // age chat timer so it fades more quickly when you are intentionally moving
+ ageChat();
+
+ setKey(direction, mAtKey);
+
+ if (direction > 0)
+ {
+ setControlFlags(AGENT_CONTROL_AT_POS | AGENT_CONTROL_FAST_AT);
+ }
+ else if (direction < 0)
+ {
+ setControlFlags(AGENT_CONTROL_AT_NEG | AGENT_CONTROL_FAST_AT);
+ }
+
+ if (reset)
+ {
+ resetView();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// moveAtNudge()
+//-----------------------------------------------------------------------------
+void LLAgent::moveAtNudge(S32 direction)
+{
+ // age chat timer so it fades more quickly when you are intentionally moving
+ ageChat();
+
+ setKey(direction, mWalkKey);
+
+ if (direction > 0)
+ {
+ setControlFlags(AGENT_CONTROL_NUDGE_AT_POS);
+ }
+ else if (direction < 0)
+ {
+ setControlFlags(AGENT_CONTROL_NUDGE_AT_NEG);
+ }
+
+ resetView();
+}
+
+//-----------------------------------------------------------------------------
+// moveLeft()
+//-----------------------------------------------------------------------------
+void LLAgent::moveLeft(S32 direction)
+{
+ // age chat timer so it fades more quickly when you are intentionally moving
+ ageChat();
+
+ setKey(direction, mLeftKey);
+
+ if (direction > 0)
+ {
+ setControlFlags(AGENT_CONTROL_LEFT_POS | AGENT_CONTROL_FAST_LEFT);
+ }
+ else if (direction < 0)
+ {
+ setControlFlags(AGENT_CONTROL_LEFT_NEG | AGENT_CONTROL_FAST_LEFT);
+ }
+
+ resetView();
+}
+
+//-----------------------------------------------------------------------------
+// moveLeftNudge()
+//-----------------------------------------------------------------------------
+void LLAgent::moveLeftNudge(S32 direction)
+{
+ // age chat timer so it fades more quickly when you are intentionally moving
+ ageChat();
+
+ setKey(direction, mLeftKey);
+
+ if (direction > 0)
+ {
+ setControlFlags(AGENT_CONTROL_NUDGE_LEFT_POS);
+ }
+ else if (direction < 0)
+ {
+ setControlFlags(AGENT_CONTROL_NUDGE_LEFT_NEG);
+ }
+
+ resetView();
+}
+
+//-----------------------------------------------------------------------------
+// moveUp()
+//-----------------------------------------------------------------------------
+void LLAgent::moveUp(S32 direction)
+{
+ // age chat timer so it fades more quickly when you are intentionally moving
+ ageChat();
+
+ setKey(direction, mUpKey);
+
+ if (direction > 0)
+ {
+ setControlFlags(AGENT_CONTROL_UP_POS | AGENT_CONTROL_FAST_UP);
+ }
+ else if (direction < 0)
+ {
+ setControlFlags(AGENT_CONTROL_UP_NEG | AGENT_CONTROL_FAST_UP);
+ }
+
+ resetView();
+}
+
+//-----------------------------------------------------------------------------
+// moveYaw()
+//-----------------------------------------------------------------------------
+void LLAgent::moveYaw(F32 mag, bool reset_view)
+{
+ mYawKey = mag;
+
+ if (mag > 0)
+ {
+ setControlFlags(AGENT_CONTROL_YAW_POS);
+ }
+ else if (mag < 0)
+ {
+ setControlFlags(AGENT_CONTROL_YAW_NEG);
+ }
+
+ if (reset_view)
+ {
+ resetView();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// movePitch()
+//-----------------------------------------------------------------------------
+void LLAgent::movePitch(S32 direction)
+{
+ setKey(direction, mPitchKey);
+
+ if (direction > 0)
+ {
+ setControlFlags(AGENT_CONTROL_PITCH_POS );
+ }
+ else if (direction < 0)
+ {
+ setControlFlags(AGENT_CONTROL_PITCH_NEG);
+ }
+}
+
+
+// Does this parcel allow you to fly?
+BOOL LLAgent::canFly()
+{
+ if (isGodlike()) return TRUE;
+
+ //
+ if(gSavedSettings.getBOOL("AlwaysAllowFly")) return TRUE;
+ //
+
+ LLViewerRegion* regionp = getRegion();
+ if (regionp && regionp->getBlockFly()) return FALSE;
+
+ LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
+ if (!parcel) return FALSE;
+
+ // Allow owners to fly on their own land.
+ if (LLViewerParcelMgr::isParcelOwnedByAgent(parcel, GP_LAND_ALLOW_FLY))
+ {
+ return TRUE;
+ }
+
+ return parcel->getAllowFly();
+}
+
+// Better Set Phantom options ~Charbl
+void LLAgent::setPhantom(BOOL phantom)
+{
+ exlPhantom = phantom;
+}
+
+BOOL LLAgent::getPhantom()
+{
+ return exlPhantom;
+}
+//
+
+//-----------------------------------------------------------------------------
+// setFlying()
+//-----------------------------------------------------------------------------
+void LLAgent::setFlying(BOOL fly)
+{
+ if (mAvatarObject.notNull())
+ {
+ if(mAvatarObject->mSignaledAnimations.find(ANIM_AGENT_STANDUP) != mAvatarObject->mSignaledAnimations.end())
+ {
+ return;
+ }
+
+ // don't allow taking off while sitting
+ if (fly && mAvatarObject->mIsSitting)
+ {
+ return;
+ }
+ }
+
+ if (fly)
+ {
+ BOOL was_flying = getFlying();
+ if (!canFly() && !was_flying)
+ {
+ // parcel doesn't let you start fly
+ // gods can always fly
+ // and it's OK if you're already flying
+ make_ui_sound("UISndBadKeystroke");
+ return;
+ }
+ if( !was_flying )
+ {
+ LLViewerStats::getInstance()->incStat(LLViewerStats::ST_FLY_COUNT);
+ }
+ setControlFlags(AGENT_CONTROL_FLY);
+ gSavedSettings.setBOOL("FlyBtnState", TRUE);
+ }
+ else
+ {
+ clearControlFlags(AGENT_CONTROL_FLY);
+ gSavedSettings.setBOOL("FlyBtnState", FALSE);
+ }
+ mbFlagsDirty = TRUE;
+}
+
+
+// UI based mechanism of setting fly state
+//-----------------------------------------------------------------------------
+// toggleFlying()
+//-----------------------------------------------------------------------------
+void LLAgent::toggleFlying()
+{
+ BOOL fly = !(mControlFlags & AGENT_CONTROL_FLY);
+
+ setFlying( fly );
+ resetView();
+}
+
+void LLAgent::togglePhantom()
+{
+ BOOL phan = !(exlPhantom);
+
+ setPhantom( phan );
+}
+
+
+//-----------------------------------------------------------------------------
+// setRegion()
+//-----------------------------------------------------------------------------
+void LLAgent::setRegion(LLViewerRegion *regionp)
+{
+ llassert(regionp);
+ if (mRegionp != regionp)
+ {
+ // std::string host_name;
+ // host_name = regionp->getHost().getHostName();
+
+ std::string ip = regionp->getHost().getString();
+ llinfos << "Moving agent into region: " << regionp->getName()
+ << " located at " << ip << llendl;
+ if (mRegionp)
+ {
+ // We've changed regions, we're now going to change our agent coordinate frame.
+ mAgentOriginGlobal = regionp->getOriginGlobal();
+ LLVector3d agent_offset_global = mRegionp->getOriginGlobal();
+
+ LLVector3 delta;
+ delta.setVec(regionp->getOriginGlobal() - mRegionp->getOriginGlobal());
+
+ setPositionAgent(getPositionAgent() - delta);
+
+ LLVector3 camera_position_agent = LLViewerCamera::getInstance()->getOrigin();
+ LLViewerCamera::getInstance()->setOrigin(camera_position_agent - delta);
+
+ // Update all of the regions.
+ LLWorld::getInstance()->updateAgentOffset(agent_offset_global);
+
+ // Hack to keep sky in the agent's region, otherwise it may get deleted - DJS 08/02/02
+ // *TODO: possibly refactor into gSky->setAgentRegion(regionp)? -Brad
+ if (gSky.mVOSkyp)
+ {
+ gSky.mVOSkyp->setRegion(regionp);
+ }
+ if (gSky.mVOGroundp)
+ {
+ gSky.mVOGroundp->setRegion(regionp);
+ }
+
+ }
+ else
+ {
+ // First time initialization.
+ // We've changed regions, we're now going to change our agent coordinate frame.
+ mAgentOriginGlobal = regionp->getOriginGlobal();
+
+ LLVector3 delta;
+ delta.setVec(regionp->getOriginGlobal());
+
+ setPositionAgent(getPositionAgent() - delta);
+ LLVector3 camera_position_agent = LLViewerCamera::getInstance()->getOrigin();
+ LLViewerCamera::getInstance()->setOrigin(camera_position_agent - delta);
+
+ // Update all of the regions.
+ LLWorld::getInstance()->updateAgentOffset(mAgentOriginGlobal);
+ }
+ }
+ mRegionp = regionp;
+
+ // Must shift hole-covering water object locations because local
+ // coordinate frame changed.
+ LLWorld::getInstance()->updateWaterObjects();
+
+ // keep a list of regions we've been too
+ // this is just an interesting stat, logged at the dataserver
+ // we could trake this at the dataserver side, but that's harder
+ U64 handle = regionp->getHandle();
+ mRegionsVisited.insert(handle);
+
+ LLSelectMgr::getInstance()->updateSelectionCenter();
+}
+
+
+//-----------------------------------------------------------------------------
+// getRegion()
+//-----------------------------------------------------------------------------
+LLViewerRegion *LLAgent::getRegion() const
+{
+ return mRegionp;
+}
+
+
+const LLHost& LLAgent::getRegionHost() const
+{
+ if (mRegionp)
+ {
+ return mRegionp->getHost();
+ }
+ else
+ {
+ return LLHost::invalid;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// getSLURL()
+// returns empty() if getRegion() == NULL
+//-----------------------------------------------------------------------------
+std::string LLAgent::getSLURL() const
+{
+ std::string slurl;
+ LLViewerRegion *regionp = getRegion();
+ if (regionp)
+ {
+ LLVector3d agentPos = getPositionGlobal();
+ S32 x = llround( (F32)fmod( agentPos.mdV[VX], (F64)REGION_WIDTH_METERS ) );
+ S32 y = llround( (F32)fmod( agentPos.mdV[VY], (F64)REGION_WIDTH_METERS ) );
+ S32 z = llround( (F32)agentPos.mdV[VZ] );
+ slurl = LLURLDispatcher::buildSLURL(regionp->getName(), x, y, z);
+ }
+ return slurl;
+}
+
+//-----------------------------------------------------------------------------
+// inPrelude()
+//-----------------------------------------------------------------------------
+BOOL LLAgent::inPrelude()
+{
+ return mRegionp && mRegionp->isPrelude();
+}
+
+
+//-----------------------------------------------------------------------------
+// canManageEstate()
+//-----------------------------------------------------------------------------
+
+BOOL LLAgent::canManageEstate() const
+{
+ return mRegionp && mRegionp->canManageEstate();
+}
+
+//-----------------------------------------------------------------------------
+// sendMessage()
+//-----------------------------------------------------------------------------
+void LLAgent::sendMessage()
+{
+ if (gDisconnected)
+ {
+ llwarns << "Trying to send message when disconnected!" << llendl;
+ return;
+ }
+ if (!mRegionp)
+ {
+ llerrs << "No region for agent yet!" << llendl;
+ }
+ gMessageSystem->sendMessage(mRegionp->getHost());
+}
+
+
+//-----------------------------------------------------------------------------
+// sendReliableMessage()
+//-----------------------------------------------------------------------------
+void LLAgent::sendReliableMessage()
+{
+ if (gDisconnected)
+ {
+ lldebugs << "Trying to send message when disconnected!" << llendl;
+ return;
+ }
+ if (!mRegionp)
+ {
+ lldebugs << "LLAgent::sendReliableMessage No region for agent yet, not sending message!" << llendl;
+ return;
+ }
+ gMessageSystem->sendReliable(mRegionp->getHost());
+}
+
+//-----------------------------------------------------------------------------
+// getVelocity()
+//-----------------------------------------------------------------------------
+LLVector3 LLAgent::getVelocity() const
+{
+ if (mAvatarObject.notNull())
+ {
+ return mAvatarObject->getVelocity();
+ }
+ else
+ {
+ return LLVector3::zero;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// setPositionAgent()
+//-----------------------------------------------------------------------------
+void LLAgent::setPositionAgent(const LLVector3 &pos_agent)
+{
+ if (!pos_agent.isFinite())
+ {
+ llerrs << "setPositionAgent is not a number" << llendl;
+ }
+
+ if (mAvatarObject.notNull() && mAvatarObject->getParent())
+ {
+ LLVector3 pos_agent_sitting;
+ LLVector3d pos_agent_d;
+ LLViewerObject *parent = (LLViewerObject*)mAvatarObject->getParent();
+
+ pos_agent_sitting = mAvatarObject->getPosition() * parent->getRotation() + parent->getPositionAgent();
+ pos_agent_d.setVec(pos_agent_sitting);
+
+ mFrameAgent.setOrigin(pos_agent_sitting);
+ mPositionGlobal = pos_agent_d + mAgentOriginGlobal;
+ }
+ else
+ {
+ mFrameAgent.setOrigin(pos_agent);
+
+ LLVector3d pos_agent_d;
+ pos_agent_d.setVec(pos_agent);
+ mPositionGlobal = pos_agent_d + mAgentOriginGlobal;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// slamLookAt()
+//-----------------------------------------------------------------------------
+void LLAgent::slamLookAt(const LLVector3 &look_at)
+{
+ LLVector3 look_at_norm = look_at;
+ look_at_norm.mV[VZ] = 0.f;
+ look_at_norm.normalize();
+ resetAxes(look_at_norm);
+}
+
+//-----------------------------------------------------------------------------
+// getPositionGlobal()
+//-----------------------------------------------------------------------------
+const LLVector3d &LLAgent::getPositionGlobal() const
+{
+ if (mAvatarObject.notNull() && !mAvatarObject->mDrawable.isNull())
+ {
+ mPositionGlobal = getPosGlobalFromAgent(mAvatarObject->getRenderPosition());
+ }
+ else
+ {
+ mPositionGlobal = getPosGlobalFromAgent(mFrameAgent.getOrigin());
+ }
+
+ return mPositionGlobal;
+}
+
+//-----------------------------------------------------------------------------
+// getPositionAgent()
+//-----------------------------------------------------------------------------
+const LLVector3 &LLAgent::getPositionAgent()
+{
+ if(mAvatarObject.notNull() && !mAvatarObject->mDrawable.isNull())
+ {
+ mFrameAgent.setOrigin(mAvatarObject->getRenderPosition());
+ }
+
+ return mFrameAgent.getOrigin();
+}
+
+//-----------------------------------------------------------------------------
+// getRegionsVisited()
+//-----------------------------------------------------------------------------
+S32 LLAgent::getRegionsVisited() const
+{
+ return mRegionsVisited.size();
+}
+
+//-----------------------------------------------------------------------------
+// getDistanceTraveled()
+//-----------------------------------------------------------------------------
+F64 LLAgent::getDistanceTraveled() const
+{
+ return mDistanceTraveled;
+}
+
+
+//-----------------------------------------------------------------------------
+// getPosAgentFromGlobal()
+//-----------------------------------------------------------------------------
+LLVector3 LLAgent::getPosAgentFromGlobal(const LLVector3d &pos_global) const
+{
+ LLVector3 pos_agent;
+ pos_agent.setVec(pos_global - mAgentOriginGlobal);
+ return pos_agent;
+}
+
+
+//-----------------------------------------------------------------------------
+// getPosGlobalFromAgent()
+//-----------------------------------------------------------------------------
+LLVector3d LLAgent::getPosGlobalFromAgent(const LLVector3 &pos_agent) const
+{
+ LLVector3d pos_agent_d;
+ pos_agent_d.setVec(pos_agent);
+ return pos_agent_d + mAgentOriginGlobal;
+}
+
+
+//-----------------------------------------------------------------------------
+// resetAxes()
+//-----------------------------------------------------------------------------
+void LLAgent::resetAxes()
+{
+ mFrameAgent.resetAxes();
+}
+
+
+// Copied from LLCamera::setOriginAndLookAt
+// Look_at must be unit vector
+//-----------------------------------------------------------------------------
+// resetAxes()
+//-----------------------------------------------------------------------------
+void LLAgent::resetAxes(const LLVector3 &look_at)
+{
+ LLVector3 skyward = getReferenceUpVector();
+
+ // if look_at has zero length, fail
+ // if look_at and skyward are parallel, fail
+ //
+ // Test both of these conditions with a cross product.
+ LLVector3 cross(look_at % skyward);
+ if (cross.isNull())
+ {
+ llinfos << "LLAgent::resetAxes cross-product is zero" << llendl;
+ return;
+ }
+
+ // Make sure look_at and skyward are not parallel
+ // and neither are zero length
+ LLVector3 left(skyward % look_at);
+ LLVector3 up(look_at % left);
+
+ mFrameAgent.setAxes(look_at, left, up);
+}
+
+
+//-----------------------------------------------------------------------------
+// rotate()
+//-----------------------------------------------------------------------------
+void LLAgent::rotate(F32 angle, const LLVector3 &axis)
+{
+ mFrameAgent.rotate(angle, axis);
+}
+
+
+//-----------------------------------------------------------------------------
+// rotate()
+//-----------------------------------------------------------------------------
+void LLAgent::rotate(F32 angle, F32 x, F32 y, F32 z)
+{
+ mFrameAgent.rotate(angle, x, y, z);
+}
+
+
+//-----------------------------------------------------------------------------
+// rotate()
+//-----------------------------------------------------------------------------
+void LLAgent::rotate(const LLMatrix3 &matrix)
+{
+ mFrameAgent.rotate(matrix);
+}
+
+
+//-----------------------------------------------------------------------------
+// rotate()
+//-----------------------------------------------------------------------------
+void LLAgent::rotate(const LLQuaternion &quaternion)
+{
+ mFrameAgent.rotate(quaternion);
+}
+
+
+//-----------------------------------------------------------------------------
+// getReferenceUpVector()
+//-----------------------------------------------------------------------------
+LLVector3 LLAgent::getReferenceUpVector()
+{
+ // this vector is in the coordinate frame of the avatar's parent object, or the world if none
+ LLVector3 up_vector = LLVector3::z_axis;
+ if (mAvatarObject.notNull() &&
+ mAvatarObject->getParent() &&
+ mAvatarObject->mDrawable.notNull())
+ {
+ U32 camera_mode = mCameraAnimating ? mLastCameraMode : mCameraMode;
+ // and in third person...
+ if (camera_mode == CAMERA_MODE_THIRD_PERSON)
+ {
+ // make the up vector point to the absolute +z axis
+ up_vector = up_vector * ~((LLViewerObject*)mAvatarObject->getParent())->getRenderRotation();
+ }
+ else if (camera_mode == CAMERA_MODE_MOUSELOOK)
+ {
+ // make the up vector point to the avatar's +z axis
+ up_vector = up_vector * mAvatarObject->mDrawable->getRotation();
+ }
+ }
+
+ return up_vector;
+}
+
+
+// Radians, positive is forward into ground
+//-----------------------------------------------------------------------------
+// pitch()
+//-----------------------------------------------------------------------------
+void LLAgent::pitch(F32 angle)
+{
+ // don't let user pitch if pointed almost all the way down or up
+ mFrameAgent.pitch(clampPitchToLimits(angle));
+}
+
+
+// Radians, positive is forward into ground
+//-----------------------------------------------------------------------------
+// clampPitchToLimits()
+//-----------------------------------------------------------------------------
+F32 LLAgent::clampPitchToLimits(F32 angle)
+{
+ // A dot B = mag(A) * mag(B) * cos(angle between A and B)
+ // so... cos(angle between A and B) = A dot B / mag(A) / mag(B)
+ // = A dot B for unit vectors
+
+ LLVector3 skyward = getReferenceUpVector();
+
+ F32 look_down_limit;
+ F32 look_up_limit = 10.f * DEG_TO_RAD;
+
+ F32 angle_from_skyward = acos( mFrameAgent.getAtAxis() * skyward );
+
+ if (mAvatarObject.notNull() && mAvatarObject->mIsSitting)
+ {
+ look_down_limit = 130.f * DEG_TO_RAD;
+ }
+ else
+ {
+ look_down_limit = 170.f * DEG_TO_RAD;
+ }
+
+ // clamp pitch to limits
+ if ((angle >= 0.f) && (angle_from_skyward + angle > look_down_limit))
+ {
+ angle = look_down_limit - angle_from_skyward;
+ }
+ else if ((angle < 0.f) && (angle_from_skyward + angle < look_up_limit))
+ {
+ angle = look_up_limit - angle_from_skyward;
+ }
+
+ return angle;
+}
+
+
+//-----------------------------------------------------------------------------
+// roll()
+//-----------------------------------------------------------------------------
+void LLAgent::roll(F32 angle)
+{
+ mFrameAgent.roll(angle);
+}
+
+
+//-----------------------------------------------------------------------------
+// yaw()
+//-----------------------------------------------------------------------------
+void LLAgent::yaw(F32 angle)
+{
+ if (!rotateGrabbed())
+ {
+ mFrameAgent.rotate(angle, getReferenceUpVector());
+ }
+}
+
+
+// Returns a quat that represents the rotation of the agent in the absolute frame
+//-----------------------------------------------------------------------------
+// getQuat()
+//-----------------------------------------------------------------------------
+LLQuaternion LLAgent::getQuat() const
+{
+ return mFrameAgent.getQuaternion();
+}
+
+
+//-----------------------------------------------------------------------------
+// calcFocusOffset()
+//-----------------------------------------------------------------------------
+LLVector3 LLAgent::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 LLAgent::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())
+ {
+ 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() - 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 LLAgent::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 LLAgent::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 LLAgent::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))
+ {
+ mFrameAgent.rotate(radians, getReferenceUpVector());
+ }
+ else
+ {
+ mCameraFocusOffsetTarget.rotVec(radians, 0.f, 0.f, 1.f);
+
+ cameraZoomIn(1.f);
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// cameraOrbitOver()
+//-----------------------------------------------------------------------------
+void LLAgent::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)
+ {
+ pitch(angle);
+ }
+ else
+ {
+ LLVector3 camera_offset_unit(mCameraFocusOffsetTarget);
+ camera_offset_unit.normalize();
+
+ F32 angle_from_up = acos( camera_offset_unit * 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 LLAgent::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)
+ {
+ // screw cam constraints
+ //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 LLAgent::cameraOrbitIn(const F32 meters)
+{
+ if (mFocusOnAvatar && mCameraMode == CAMERA_MODE_THIRD_PERSON)
+ {
+ F32 camera_offset_dist = llmax(0.001f, mCameraOffsetDefault.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 LLAgent::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 LLAgent::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 LLAgent::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();
+}
+
+//-----------------------------------------------------------------------------
+// setKey()
+//-----------------------------------------------------------------------------
+void LLAgent::setKey(const S32 direction, S32 &key)
+{
+ if (direction > 0)
+ {
+ key = 1;
+ }
+ else if (direction < 0)
+ {
+ key = -1;
+ }
+ else
+ {
+ key = 0;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// getControlFlags()
+//-----------------------------------------------------------------------------
+U32 LLAgent::getControlFlags()
+{
+/*
+ // HACK -- avoids maintenance of control flags when camera mode is turned on or off,
+ // only worries about it when the flags are measured
+ if (mCameraMode == CAMERA_MODE_MOUSELOOK)
+ {
+ if ( !(mControlFlags & AGENT_CONTROL_MOUSELOOK) )
+ {
+ mControlFlags |= AGENT_CONTROL_MOUSELOOK;
+ }
+ }
+*/
+ return mControlFlags;
+}
+
+//-----------------------------------------------------------------------------
+// setControlFlags()
+//-----------------------------------------------------------------------------
+void LLAgent::setControlFlags(U32 mask)
+{
+ mControlFlags |= mask;
+ mbFlagsDirty = TRUE;
+}
+
+
+//-----------------------------------------------------------------------------
+// clearControlFlags()
+//-----------------------------------------------------------------------------
+void LLAgent::clearControlFlags(U32 mask)
+{
+ U32 old_flags = mControlFlags;
+ mControlFlags &= ~mask;
+ if (old_flags != mControlFlags)
+ {
+ mbFlagsDirty = TRUE;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// controlFlagsDirty()
+//-----------------------------------------------------------------------------
+BOOL LLAgent::controlFlagsDirty() const
+{
+ return mbFlagsDirty;
+}
+
+//-----------------------------------------------------------------------------
+// enableControlFlagReset()
+//-----------------------------------------------------------------------------
+void LLAgent::enableControlFlagReset()
+{
+ mbFlagsNeedReset = TRUE;
+}
+
+//-----------------------------------------------------------------------------
+// resetControlFlags()
+//-----------------------------------------------------------------------------
+void LLAgent::resetControlFlags()
+{
+ if (mbFlagsNeedReset)
+ {
+ mbFlagsNeedReset = FALSE;
+ mbFlagsDirty = FALSE;
+ // reset all of the ephemeral flags
+ // some flags are managed elsewhere
+ mControlFlags &= AGENT_CONTROL_AWAY | AGENT_CONTROL_FLY | AGENT_CONTROL_MOUSELOOK;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// setAFK()
+//-----------------------------------------------------------------------------
+void LLAgent::setAFK()
+{
+ // Drones can't go AFK
+ if (gNoRender)
+ {
+ return;
+ }
+
+ if (!gAgent.getRegion())
+ {
+ // Don't set AFK if we're not talking to a region yet.
+ return;
+ }
+
+ if (!(mControlFlags & AGENT_CONTROL_AWAY))
+ {
+ sendAnimationRequest(ANIM_AGENT_AWAY, ANIM_REQUEST_START);
+ setControlFlags(AGENT_CONTROL_AWAY | AGENT_CONTROL_STOP);
+ gAwayTimer.start();
+ if (gAFKMenu)
+ {
+ //*TODO:Translate
+ gAFKMenu->setLabel(std::string("Set Not Away"));
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// clearAFK()
+//-----------------------------------------------------------------------------
+void LLAgent::clearAFK()
+{
+ gAwayTriggerTimer.reset();
+ if (!gSavedSettings.controlExists("FakeAway")) gSavedSettings.declareBOOL("FakeAway", FALSE, "", NO_PERSIST);
+ if (gSavedSettings.getBOOL("FakeAway") == TRUE) return;
+
+ // Gods can sometimes get into away state (via gestures)
+ // without setting the appropriate control flag. JC
+ LLVOAvatar* av = mAvatarObject;
+ if (mControlFlags & AGENT_CONTROL_AWAY
+ || (av
+ && (av->mSignaledAnimations.find(ANIM_AGENT_AWAY) != av->mSignaledAnimations.end())))
+ {
+ sendAnimationRequest(ANIM_AGENT_AWAY, ANIM_REQUEST_STOP);
+ clearControlFlags(AGENT_CONTROL_AWAY);
+ if (gAFKMenu)
+ {
+ //*TODO:Translate
+ gAFKMenu->setLabel(std::string("Set Away"));
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// getAFK()
+//-----------------------------------------------------------------------------
+BOOL LLAgent::getAFK() const
+{
+ return (mControlFlags & AGENT_CONTROL_AWAY) != 0;
+}
+
+//-----------------------------------------------------------------------------
+// setBusy()
+//-----------------------------------------------------------------------------
+void LLAgent::setBusy()
+{
+ sendAnimationRequest(ANIM_AGENT_BUSY, ANIM_REQUEST_START);
+ mIsBusy = TRUE;
+ if (gBusyMenu)
+ {
+ //*TODO:Translate
+ gBusyMenu->setLabel(std::string("Set Not Busy"));
+ }
+ LLFloaterMute::getInstance()->updateButtons();
+}
+
+//-----------------------------------------------------------------------------
+// clearBusy()
+//-----------------------------------------------------------------------------
+void LLAgent::clearBusy()
+{
+ mIsBusy = FALSE;
+ sendAnimationRequest(ANIM_AGENT_BUSY, ANIM_REQUEST_STOP);
+ if (gBusyMenu)
+ {
+ //*TODO:Translate
+ gBusyMenu->setLabel(std::string("Set Busy"));
+ }
+ LLFloaterMute::getInstance()->updateButtons();
+}
+
+//-----------------------------------------------------------------------------
+// getBusy()
+//-----------------------------------------------------------------------------
+BOOL LLAgent::getBusy() const
+{
+ return mIsBusy;
+}
+
+
+//-----------------------------------------------------------------------------
+// startAutoPilotGlobal()
+//-----------------------------------------------------------------------------
+void LLAgent::startAutoPilotGlobal(const LLVector3d &target_global, const std::string& behavior_name, const LLQuaternion *target_rotation, void (*finish_callback)(BOOL, void *), void *callback_data, F32 stop_distance, F32 rot_threshold)
+{
+ if (!gAgent.getAvatarObject())
+ {
+ return;
+ }
+
+ mAutoPilotFinishedCallback = finish_callback;
+ mAutoPilotCallbackData = callback_data;
+ mAutoPilotRotationThreshold = rot_threshold;
+ mAutoPilotBehaviorName = behavior_name;
+
+ LLVector3d delta_pos( target_global );
+ delta_pos -= getPositionGlobal();
+ F64 distance = delta_pos.magVec();
+ LLVector3d trace_target = target_global;
+
+ trace_target.mdV[VZ] -= 10.f;
+
+ LLVector3d intersection;
+ LLVector3 normal;
+ LLViewerObject *hit_obj;
+ F32 heightDelta = LLWorld::getInstance()->resolveStepHeightGlobal(NULL, target_global, trace_target, intersection, normal, &hit_obj);
+
+ if (stop_distance > 0.f)
+ {
+ mAutoPilotStopDistance = stop_distance;
+ }
+ else
+ {
+ // Guess at a reasonable stop distance.
+ mAutoPilotStopDistance = fsqrtf( distance );
+ if (mAutoPilotStopDistance < 0.5f)
+ {
+ mAutoPilotStopDistance = 0.5f;
+ }
+ }
+
+ mAutoPilotFlyOnStop = getFlying();
+
+ if (distance > 30.0)
+ {
+ setFlying(TRUE);
+ }
+
+ if ( distance > 1.f && heightDelta > (sqrtf(mAutoPilotStopDistance) + 1.f))
+ {
+ setFlying(TRUE);
+ mAutoPilotFlyOnStop = TRUE;
+ }
+
+ mAutoPilot = TRUE;
+ mAutoPilotTargetGlobal = target_global;
+
+ // trace ray down to find height of destination from ground
+ LLVector3d traceEndPt = target_global;
+ traceEndPt.mdV[VZ] -= 20.f;
+
+ LLVector3d targetOnGround;
+ LLVector3 groundNorm;
+ LLViewerObject *obj;
+
+ LLWorld::getInstance()->resolveStepHeightGlobal(NULL, target_global, traceEndPt, targetOnGround, groundNorm, &obj);
+ F64 target_height = llmax((F64)gAgent.getAvatarObject()->getPelvisToFoot(), target_global.mdV[VZ] - targetOnGround.mdV[VZ]);
+
+ // clamp z value of target to minimum height above ground
+ mAutoPilotTargetGlobal.mdV[VZ] = targetOnGround.mdV[VZ] + target_height;
+ mAutoPilotTargetDist = (F32)dist_vec(gAgent.getPositionGlobal(), mAutoPilotTargetGlobal);
+ if (target_rotation)
+ {
+ mAutoPilotUseRotation = TRUE;
+ mAutoPilotTargetFacing = LLVector3::x_axis * *target_rotation;
+ mAutoPilotTargetFacing.mV[VZ] = 0.f;
+ mAutoPilotTargetFacing.normalize();
+ }
+ else
+ {
+ mAutoPilotUseRotation = FALSE;
+ }
+
+ mAutoPilotNoProgressFrameCount = 0;
+}
+
+
+//-----------------------------------------------------------------------------
+// startFollowPilot()
+//-----------------------------------------------------------------------------
+void LLAgent::startFollowPilot(const LLUUID &leader_id)
+{
+ if (!mAutoPilot) return;
+
+ mLeaderID = leader_id;
+ if ( mLeaderID.isNull() ) return;
+
+ LLViewerObject* object = gObjectList.findObject(mLeaderID);
+ if (!object)
+ {
+ mLeaderID = LLUUID::null;
+ return;
+ }
+
+ startAutoPilotGlobal(object->getPositionGlobal());
+}
+
+
+//-----------------------------------------------------------------------------
+// stopAutoPilot()
+//-----------------------------------------------------------------------------
+void LLAgent::stopAutoPilot(BOOL user_cancel)
+{
+ if (mAutoPilot)
+ {
+ mAutoPilot = FALSE;
+ if (mAutoPilotUseRotation && !user_cancel)
+ {
+ resetAxes(mAutoPilotTargetFacing);
+ }
+ //NB: auto pilot can terminate for a reason other than reaching the destination
+ if (mAutoPilotFinishedCallback)
+ {
+ mAutoPilotFinishedCallback(!user_cancel && dist_vec(gAgent.getPositionGlobal(), mAutoPilotTargetGlobal) < mAutoPilotStopDistance, mAutoPilotCallbackData);
+ }
+ mLeaderID = LLUUID::null;
+
+ // If the user cancelled, don't change the fly state
+ if (!user_cancel)
+ {
+ setFlying(mAutoPilotFlyOnStop);
+ }
+ setControlFlags(AGENT_CONTROL_STOP);
+
+ if (user_cancel && !mAutoPilotBehaviorName.empty())
+ {
+ if (mAutoPilotBehaviorName == "Sit")
+ LLNotifications::instance().add("CancelledSit");
+ else if (mAutoPilotBehaviorName == "Attach")
+ LLNotifications::instance().add("CancelledAttach");
+ else
+ LLNotifications::instance().add("Cancelled");
+ }
+ }
+}
+
+
+// Returns necessary agent pitch and yaw changes, radians.
+//-----------------------------------------------------------------------------
+// autoPilot()
+//-----------------------------------------------------------------------------
+void LLAgent::autoPilot(F32 *delta_yaw)
+{
+ if (mAutoPilot)
+ {
+ if (!mLeaderID.isNull())
+ {
+ LLViewerObject* object = gObjectList.findObject(mLeaderID);
+ if (!object)
+ {
+ stopAutoPilot();
+ return;
+ }
+ mAutoPilotTargetGlobal = object->getPositionGlobal();
+ }
+
+ if (mAvatarObject.isNull())
+ {
+ return;
+ }
+
+ if (mAvatarObject->mInAir)
+ {
+ setFlying(TRUE);
+ }
+
+ LLVector3 at;
+ at.setVec(mFrameAgent.getAtAxis());
+ LLVector3 target_agent = getPosAgentFromGlobal(mAutoPilotTargetGlobal);
+ LLVector3 direction = target_agent - getPositionAgent();
+
+ F32 target_dist = direction.magVec();
+
+ if (target_dist >= mAutoPilotTargetDist)
+ {
+ mAutoPilotNoProgressFrameCount++;
+ if (mAutoPilotNoProgressFrameCount > AUTOPILOT_MAX_TIME_NO_PROGRESS * gFPSClamped)
+ {
+ stopAutoPilot();
+ return;
+ }
+ }
+
+ mAutoPilotTargetDist = target_dist;
+
+ // Make this a two-dimensional solution
+ at.mV[VZ] = 0.f;
+ direction.mV[VZ] = 0.f;
+
+ at.normalize();
+ F32 xy_distance = direction.normalize();
+
+ F32 yaw = 0.f;
+ if (mAutoPilotTargetDist > mAutoPilotStopDistance)
+ {
+ yaw = angle_between(mFrameAgent.getAtAxis(), direction);
+ }
+ else if (mAutoPilotUseRotation)
+ {
+ // we're close now just aim at target facing
+ yaw = angle_between(at, mAutoPilotTargetFacing);
+ direction = mAutoPilotTargetFacing;
+ }
+
+ yaw = 4.f * yaw / gFPSClamped;
+
+ // figure out which direction to turn
+ LLVector3 scratch(at % direction);
+
+ if (scratch.mV[VZ] > 0.f)
+ {
+ setControlFlags(AGENT_CONTROL_YAW_POS);
+ }
+ else
+ {
+ yaw = -yaw;
+ setControlFlags(AGENT_CONTROL_YAW_NEG);
+ }
+
+ *delta_yaw = yaw;
+
+ // Compute when to start slowing down and when to stop
+ F32 stop_distance = mAutoPilotStopDistance;
+ F32 slow_distance;
+ if (getFlying())
+ {
+ slow_distance = llmax(6.f, mAutoPilotStopDistance + 5.f);
+ stop_distance = llmax(2.f, mAutoPilotStopDistance);
+ }
+ else
+ {
+ slow_distance = llmax(3.f, mAutoPilotStopDistance + 2.f);
+ }
+
+ // If we're flying, handle autopilot points above or below you.
+ if (getFlying() && xy_distance < AUTOPILOT_HEIGHT_ADJUST_DISTANCE)
+ {
+ if (mAvatarObject.notNull())
+ {
+ F64 current_height = mAvatarObject->getPositionGlobal().mdV[VZ];
+ F32 delta_z = (F32)(mAutoPilotTargetGlobal.mdV[VZ] - current_height);
+ F32 slope = delta_z / xy_distance;
+ if (slope > 0.45f && delta_z > 6.f)
+ {
+ setControlFlags(AGENT_CONTROL_FAST_UP | AGENT_CONTROL_UP_POS);
+ }
+ else if (slope > 0.002f && delta_z > 0.5f)
+ {
+ setControlFlags(AGENT_CONTROL_UP_POS);
+ }
+ else if (slope < -0.45f && delta_z < -6.f && current_height > AUTOPILOT_MIN_TARGET_HEIGHT_OFF_GROUND)
+ {
+ setControlFlags(AGENT_CONTROL_FAST_UP | AGENT_CONTROL_UP_NEG);
+ }
+ else if (slope < -0.002f && delta_z < -0.5f && current_height > AUTOPILOT_MIN_TARGET_HEIGHT_OFF_GROUND)
+ {
+ setControlFlags(AGENT_CONTROL_UP_NEG);
+ }
+ }
+ }
+
+ // calculate delta rotation to target heading
+ F32 delta_target_heading = angle_between(mFrameAgent.getAtAxis(), mAutoPilotTargetFacing);
+
+ if (xy_distance > slow_distance && yaw < (F_PI / 10.f))
+ {
+ // walking/flying fast
+ setControlFlags(AGENT_CONTROL_FAST_AT | AGENT_CONTROL_AT_POS);
+ }
+ else if (mAutoPilotTargetDist > mAutoPilotStopDistance)
+ {
+ // walking/flying slow
+ if (at * direction > 0.9f)
+ {
+ setControlFlags(AGENT_CONTROL_AT_POS);
+ }
+ else if (at * direction < -0.9f)
+ {
+ setControlFlags(AGENT_CONTROL_AT_NEG);
+ }
+ }
+
+ // check to see if we need to keep rotating to target orientation
+ if (mAutoPilotTargetDist < mAutoPilotStopDistance)
+ {
+ setControlFlags(AGENT_CONTROL_STOP);
+ if(!mAutoPilotUseRotation || (delta_target_heading < mAutoPilotRotationThreshold))
+ {
+ stopAutoPilot();
+ }
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// propagate()
+//-----------------------------------------------------------------------------
+void LLAgent::propagate(const F32 dt)
+{
+ // Update UI based on agent motion
+ LLFloaterMove *floater_move = LLFloaterMove::getInstance();
+ if (floater_move)
+ {
+ floater_move->mForwardButton ->setToggleState( mAtKey > 0 || mWalkKey > 0 );
+ floater_move->mBackwardButton ->setToggleState( mAtKey < 0 || mWalkKey < 0 );
+ floater_move->mSlideLeftButton ->setToggleState( mLeftKey > 0 );
+ floater_move->mSlideRightButton->setToggleState( mLeftKey < 0 );
+ floater_move->mTurnLeftButton ->setToggleState( mYawKey > 0.f );
+ floater_move->mTurnRightButton ->setToggleState( mYawKey < 0.f );
+ floater_move->mMoveUpButton ->setToggleState( mUpKey > 0 );
+ floater_move->mMoveDownButton ->setToggleState( mUpKey < 0 );
+ }
+
+ // handle rotation based on keyboard levels
+ const F32 YAW_RATE = 90.f * DEG_TO_RAD; // radians per second
+ yaw( YAW_RATE * mYawKey * dt );
+
+ const F32 PITCH_RATE = 90.f * DEG_TO_RAD; // radians per second
+ pitch(PITCH_RATE * (F32) mPitchKey * dt);
+
+ // handle auto-land behavior
+ if (mAvatarObject.notNull())
+ {
+ BOOL in_air = mAvatarObject->mInAir;
+ LLVector3 land_vel = getVelocity();
+ land_vel.mV[VZ] = 0.f;
+
+ if (!in_air
+ && mUpKey < 0
+ && land_vel.magVecSquared() < MAX_VELOCITY_AUTO_LAND_SQUARED
+ && gSavedSettings.getBOOL("AutomaticFly"))
+ {
+ // land automatically
+ setFlying(FALSE);
+ }
+ }
+
+ // clear keys
+ mAtKey = 0;
+ mWalkKey = 0;
+ mLeftKey = 0;
+ mUpKey = 0;
+ mYawKey = 0.f;
+ mPitchKey = 0;
+}
+
+//-----------------------------------------------------------------------------
+// updateAgentPosition()
+//-----------------------------------------------------------------------------
+void LLAgent::updateAgentPosition(const F32 dt, const F32 yaw_radians, const S32 mouse_x, const S32 mouse_y)
+{
+ propagate(dt);
+
+ // static S32 cameraUpdateCount = 0;
+
+ rotate(yaw_radians, 0, 0, 1);
+
+ //
+ // Check for water and land collision, set underwater flag
+ //
+
+ updateLookAt(mouse_x, mouse_y);
+}
+
+//-----------------------------------------------------------------------------
+// updateLookAt()
+//-----------------------------------------------------------------------------
+void LLAgent::updateLookAt(const S32 mouse_x, const S32 mouse_y)
+{
+ static LLVector3 last_at_axis;
+
+
+ if (mAvatarObject.isNull())
+ {
+ return;
+ }
+
+ LLQuaternion av_inv_rot = ~mAvatarObject->mRoot.getWorldRotation();
+ LLVector3 root_at = LLVector3::x_axis * mAvatarObject->mRoot.getWorldRotation();
+
+ if ((gViewerWindow->getMouseVelocityStat()->getCurrent() < 0.01f) &&
+ (root_at * last_at_axis > 0.95f ))
+ {
+ LLVector3 vel = mAvatarObject->getVelocity();
+ if (vel.magVecSquared() > 4.f)
+ {
+ setLookAt(LOOKAT_TARGET_IDLE, mAvatarObject, vel * av_inv_rot);
+ }
+ else
+ {
+ // *FIX: rotate mframeagent by sit object's rotation?
+ LLQuaternion look_rotation = mAvatarObject->mIsSitting ? mAvatarObject->getRenderRotation() : mFrameAgent.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, mAvatarObject, look_offset);
+ }
+ last_at_axis = root_at;
+ return;
+ }
+
+ last_at_axis = root_at;
+
+ if (CAMERA_MODE_CUSTOMIZE_AVATAR == getCameraMode())
+ {
+ setLookAt(LOOKAT_TARGET_NONE, mAvatarObject, 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->getWindowWidth() ) - 0.5f;
+ F32 y_from_center =
+ ((F32) mouse_y / (F32) gViewerWindow->getWindowHeight() ) - 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, mAvatarObject, headLookAxis);
+ }
+}
+
+// friends and operators
+
+std::ostream& operator<<(std::ostream &s, const LLAgent &agent)
+{
+ // This is unfinished, but might never be used.
+ // We'll just leave it for now; we can always delete it.
+ s << " { "
+ << " Frame = " << agent.mFrameAgent << "\n"
+ << " }";
+ return s;
+}
+
+
+// ------------------- Beginning of legacy LLCamera hack ----------------------
+// This section is included for legacy LLCamera support until
+// it is no longer needed. Some legacy code must exist in
+// non-legacy functions, and is labeled with "// legacy" comments.
+
+//-----------------------------------------------------------------------------
+// setAvatarObject()
+//-----------------------------------------------------------------------------
+void LLAgent::setAvatarObject(LLVOAvatar *avatar)
+{
+ mAvatarObject = avatar;
+
+ if (!avatar)
+ {
+ llinfos << "Setting LLAgent::mAvatarObject to NULL" << llendl;
+ return;
+ }
+
+ 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);
+ }
+
+ sendAgentWearablesRequest();
+}
+
+// TRUE if your own avatar needs to be rendered. Usually only
+// in third person and build.
+//-----------------------------------------------------------------------------
+// needsRenderAvatar()
+//-----------------------------------------------------------------------------
+BOOL LLAgent::needsRenderAvatar()
+{
+ if (cameraMouselook() && !LLVOAvatar::sVisibleInFirstPerson)
+ {
+ return FALSE;
+ }
+
+ return mShowAvatar && mGenderChosen;
+}
+
+// TRUE if we need to render your own avatar's head.
+BOOL LLAgent::needsRenderHead()
+{
+ return (LLVOAvatar::sVisibleInFirstPerson && LLPipeline::sReflectionRender) || (mShowAvatar && !cameraMouselook());
+}
+
+//-----------------------------------------------------------------------------
+// startTyping()
+//-----------------------------------------------------------------------------
+void LLAgent::startTyping()
+{
+ if (gSavedSettings.getBOOL("FakeAway"))
+ return;
+ mTypingTimer.reset();
+
+ if (getRenderState() & AGENT_STATE_TYPING)
+ {
+ // already typing, don't trigger a different animation
+ return;
+ }
+ setRenderState(AGENT_STATE_TYPING);
+
+ if (mChatTimer.getElapsedTimeF32() < 2.f)
+ {
+ LLViewerObject* chatter = gObjectList.findObject(mLastChatterID);
+ if (chatter && chatter->isAvatar())
+ {
+ gAgent.setLookAt(LOOKAT_TARGET_RESPOND, chatter, LLVector3::zero);
+ }
+ }
+
+ if (gSavedSettings.getBOOL("PlayTypingAnim"))
+ {
+ sendAnimationRequest(ANIM_AGENT_TYPE, ANIM_REQUEST_START);
+ }
+ gChatBar->sendChatFromViewer("", CHAT_TYPE_START, FALSE);
+}
+
+//-----------------------------------------------------------------------------
+// stopTyping()
+//-----------------------------------------------------------------------------
+void LLAgent::stopTyping()
+{
+ if (mRenderState & AGENT_STATE_TYPING)
+ {
+ clearRenderState(AGENT_STATE_TYPING);
+ sendAnimationRequest(ANIM_AGENT_TYPE, ANIM_REQUEST_STOP);
+ gChatBar->sendChatFromViewer("", CHAT_TYPE_STOP, FALSE);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// setRenderState()
+//-----------------------------------------------------------------------------
+void LLAgent::setRenderState(U8 newstate)
+{
+ mRenderState |= newstate;
+}
+
+//-----------------------------------------------------------------------------
+// clearRenderState()
+//-----------------------------------------------------------------------------
+void LLAgent::clearRenderState(U8 clearstate)
+{
+ mRenderState &= ~clearstate;
+}
+
+
+//-----------------------------------------------------------------------------
+// getRenderState()
+//-----------------------------------------------------------------------------
+U8 LLAgent::getRenderState()
+{
+ if (gNoRender || gKeyboard == NULL)
+ {
+ return 0;
+ }
+
+ // *FIX: don't do stuff in a getter! This is infinite loop city!
+ if ((mTypingTimer.getElapsedTimeF32() > TYPING_TIMEOUT_SECS)
+ && (mRenderState & AGENT_STATE_TYPING))
+ {
+ stopTyping();
+ }
+
+ if ((!LLSelectMgr::getInstance()->getSelection()->isEmpty() && LLSelectMgr::getInstance()->shouldShowSelection())
+ || LLToolMgr::getInstance()->getCurrentTool()->isEditing() )
+ {
+ setRenderState(AGENT_STATE_EDITING);
+ }
+ else
+ {
+ clearRenderState(AGENT_STATE_EDITING);
+ }
+
+ return mRenderState;
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+
+static const LLFloaterView::skip_list_t& get_skip_list()
+{
+ static LLFloaterView::skip_list_t skip_list;
+ skip_list.insert(LLFloaterMap::getInstance());
+ return skip_list;
+}
+
+//-----------------------------------------------------------------------------
+// endAnimationUpdateUI()
+//-----------------------------------------------------------------------------
+void LLAgent::endAnimationUpdateUI()
+{
+ if (mCameraMode == mLastCameraMode)
+ {
+ // We're already done endAnimationUpdateUI for this transition.
+ return;
+ }
+
+ // clean up UI from mode we're leaving
+ if ( mLastCameraMode == CAMERA_MODE_MOUSELOOK )
+ {
+ // show mouse cursor
+ gViewerWindow->showCursor();
+ // show menus
+ gMenuBarView->setVisible(TRUE);
+ gStatusBar->setVisibleForMouselook(true);
+
+ LLToolMgr::getInstance()->setCurrentToolset(gBasicToolset);
+
+ // Only pop if we have pushed...
+ if (TRUE == mViewsPushed)
+ {
+ mViewsPushed = FALSE;
+ gFloaterView->popVisibleAll(get_skip_list());
+ }
+
+ gAgent.setLookAt(LOOKAT_TARGET_CLEAR);
+ if( gMorphView )
+ {
+ gMorphView->setVisible( FALSE );
+ }
+
+ // Disable mouselook-specific animations
+ if (mAvatarObject.notNull())
+ {
+ if( mAvatarObject->isAnyAnimationSignaled(AGENT_GUN_AIM_ANIMS, NUM_AGENT_GUN_AIM_ANIMS) )
+ {
+ if (mAvatarObject->mSignaledAnimations.find(ANIM_AGENT_AIM_RIFLE_R) != mAvatarObject->mSignaledAnimations.end())
+ {
+ sendAnimationRequest(ANIM_AGENT_AIM_RIFLE_R, ANIM_REQUEST_STOP);
+ sendAnimationRequest(ANIM_AGENT_HOLD_RIFLE_R, ANIM_REQUEST_START);
+ }
+ if (mAvatarObject->mSignaledAnimations.find(ANIM_AGENT_AIM_HANDGUN_R) != mAvatarObject->mSignaledAnimations.end())
+ {
+ sendAnimationRequest(ANIM_AGENT_AIM_HANDGUN_R, ANIM_REQUEST_STOP);
+ sendAnimationRequest(ANIM_AGENT_HOLD_HANDGUN_R, ANIM_REQUEST_START);
+ }
+ if (mAvatarObject->mSignaledAnimations.find(ANIM_AGENT_AIM_BAZOOKA_R) != mAvatarObject->mSignaledAnimations.end())
+ {
+ sendAnimationRequest(ANIM_AGENT_AIM_BAZOOKA_R, ANIM_REQUEST_STOP);
+ sendAnimationRequest(ANIM_AGENT_HOLD_BAZOOKA_R, ANIM_REQUEST_START);
+ }
+ if (mAvatarObject->mSignaledAnimations.find(ANIM_AGENT_AIM_BOW_L) != mAvatarObject->mSignaledAnimations.end())
+ {
+ sendAnimationRequest(ANIM_AGENT_AIM_BOW_L, ANIM_REQUEST_STOP);
+ sendAnimationRequest(ANIM_AGENT_HOLD_BOW_L, ANIM_REQUEST_START);
+ }
+ }
+ }
+ }
+ else
+ if( mLastCameraMode == CAMERA_MODE_CUSTOMIZE_AVATAR )
+ {
+ // make sure we ask to save changes
+
+ LLToolMgr::getInstance()->setCurrentToolset(gBasicToolset);
+
+ // HACK: If we're quitting, and we were in customize avatar, don't
+ // let the mini-map go visible again. JC
+ if (!LLAppViewer::instance()->quitRequested())
+ {
+ LLFloaterMap::getInstance()->popVisible();
+ }
+
+ if( gMorphView )
+ {
+ gMorphView->setVisible( FALSE );
+ }
+
+ if (mAvatarObject.notNull())
+ {
+ if(mCustomAnim)
+ {
+ sendAnimationRequest(ANIM_AGENT_CUSTOMIZE, ANIM_REQUEST_STOP);
+ sendAnimationRequest(ANIM_AGENT_CUSTOMIZE_DONE, ANIM_REQUEST_START);
+
+ mCustomAnim = FALSE ;
+ }
+
+ }
+ setLookAt(LOOKAT_TARGET_CLEAR);
+ }
+
+ //---------------------------------------------------------------------
+ // Set up UI for mode we're entering
+ //---------------------------------------------------------------------
+ if (mCameraMode == CAMERA_MODE_MOUSELOOK)
+ {
+ // hide menus
+ gMenuBarView->setVisible(FALSE);
+ gStatusBar->setVisibleForMouselook(false);
+
+ // clear out camera lag effect
+ mCameraLag.clearVec();
+
+ // JC - Added for always chat in third person option
+ gFocusMgr.setKeyboardFocus(NULL);
+
+ LLToolMgr::getInstance()->setCurrentToolset(gMouselookToolset);
+
+ mViewsPushed = TRUE;
+
+ gFloaterView->pushVisibleAll(FALSE, get_skip_list());
+
+ if( gMorphView )
+ {
+ gMorphView->setVisible(FALSE);
+ }
+
+ gConsole->setVisible( TRUE );
+
+ if (mAvatarObject.notNull())
+ {
+ // Trigger mouselook-specific animations
+ if( mAvatarObject->isAnyAnimationSignaled(AGENT_GUN_HOLD_ANIMS, NUM_AGENT_GUN_HOLD_ANIMS) )
+ {
+ if (mAvatarObject->mSignaledAnimations.find(ANIM_AGENT_HOLD_RIFLE_R) != mAvatarObject->mSignaledAnimations.end())
+ {
+ sendAnimationRequest(ANIM_AGENT_HOLD_RIFLE_R, ANIM_REQUEST_STOP);
+ sendAnimationRequest(ANIM_AGENT_AIM_RIFLE_R, ANIM_REQUEST_START);
+ }
+ if (mAvatarObject->mSignaledAnimations.find(ANIM_AGENT_HOLD_HANDGUN_R) != mAvatarObject->mSignaledAnimations.end())
+ {
+ sendAnimationRequest(ANIM_AGENT_HOLD_HANDGUN_R, ANIM_REQUEST_STOP);
+ sendAnimationRequest(ANIM_AGENT_AIM_HANDGUN_R, ANIM_REQUEST_START);
+ }
+ if (mAvatarObject->mSignaledAnimations.find(ANIM_AGENT_HOLD_BAZOOKA_R) != mAvatarObject->mSignaledAnimations.end())
+ {
+ sendAnimationRequest(ANIM_AGENT_HOLD_BAZOOKA_R, ANIM_REQUEST_STOP);
+ sendAnimationRequest(ANIM_AGENT_AIM_BAZOOKA_R, ANIM_REQUEST_START);
+ }
+ if (mAvatarObject->mSignaledAnimations.find(ANIM_AGENT_HOLD_BOW_L) != mAvatarObject->mSignaledAnimations.end())
+ {
+ sendAnimationRequest(ANIM_AGENT_HOLD_BOW_L, ANIM_REQUEST_STOP);
+ sendAnimationRequest(ANIM_AGENT_AIM_BOW_L, ANIM_REQUEST_START);
+ }
+ }
+ if (mAvatarObject->getParent())
+ {
+ LLVector3 at_axis = LLViewerCamera::getInstance()->getAtAxis();
+ LLViewerObject* root_object = (LLViewerObject*)mAvatarObject->getRoot();
+ if (root_object->flagCameraDecoupled())
+ {
+ resetAxes(at_axis);
+ }
+ else
+ {
+ resetAxes(at_axis * ~((LLViewerObject*)mAvatarObject->getParent())->getRenderRotation());
+ }
+ }
+ }
+
+ }
+ else if (mCameraMode == CAMERA_MODE_CUSTOMIZE_AVATAR)
+ {
+ LLToolMgr::getInstance()->setCurrentToolset(gFaceEditToolset);
+
+ LLFloaterMap::getInstance()->pushVisible(FALSE);
+ /*
+ LLView *view;
+ for (view = gFloaterView->getFirstChild(); view; view = gFloaterView->getNextChild())
+ {
+ view->pushVisible(FALSE);
+ }
+ */
+
+ if( gMorphView )
+ {
+ gMorphView->setVisible( TRUE );
+ }
+
+ // freeze avatar
+ if (mAvatarObject.notNull())
+ {
+ //
+ //mPauseRequest = mAvatarObject->requestPause();
+ //
+ }
+ }
+
+ if (getAvatarObject())
+ {
+ getAvatarObject()->updateAttachmentVisibility(mCameraMode);
+ }
+
+ gFloaterTools->dirty();
+
+ // Don't let this be called more than once if the camera
+ // mode hasn't changed. --JC
+ mLastCameraMode = mCameraMode;
+
+}
+
+
+//-----------------------------------------------------------------------------
+// updateCamera()
+//-----------------------------------------------------------------------------
+void LLAgent::updateCamera()
+{
+ //Ventrella - changed camera_skyward to the new global "mCameraUpVector"
+ mCameraUpVector = LLVector3::z_axis;
+ //LLVector3 camera_skyward(0.f, 0.f, 1.f);
+ //end Ventrella
+
+ U32 camera_mode = mCameraAnimating ? mLastCameraMode : mCameraMode;
+
+ validateFocusObject();
+
+ if (mAvatarObject.notNull() &&
+ mAvatarObject->mIsSitting &&
+ camera_mode == CAMERA_MODE_MOUSELOOK)
+ {
+ //Ventrella
+ //changed camera_skyward to the new global "mCameraUpVector"
+ mCameraUpVector = mCameraUpVector * mAvatarObject->getRenderRotation();
+ //end Ventrella
+ }
+
+ if (cameraThirdPerson() && mFocusOnAvatar && LLFollowCamMgr::getActiveFollowCamParams())
+ {
+ changeCameraToFollow();
+ }
+
+ //Ventrella
+ //NOTE - this needs to be integrated into a general upVector system here within llAgent.
+ if ( camera_mode == CAMERA_MODE_FOLLOW && mFocusOnAvatar )
+ {
+ mCameraUpVector = mFollowCam.getUpVector();
+ }
+ //end Ventrella
+
+ if (mSitCameraEnabled)
+ {
+ if (mSitCameraReferenceObject->isDead())
+ {
+ setSitCamera(LLUUID::null);
+ }
+ }
+
+ // Update UI with our camera inputs
+ LLFloaterCamera::getInstance()->mRotate->setToggleState(
+ mOrbitRightKey > 0.f, // left
+ mOrbitUpKey > 0.f, // top
+ mOrbitLeftKey > 0.f, // right
+ mOrbitDownKey > 0.f); // bottom
+
+ LLFloaterCamera::getInstance()->mZoom->setToggleState(
+ mOrbitInKey > 0.f, // top
+ mOrbitOutKey > 0.f); // bottom
+
+ LLFloaterCamera::getInstance()->mTrack->setToggleState(
+ mPanLeftKey > 0.f, // left
+ mPanUpKey > 0.f, // top
+ mPanRightKey > 0.f, // right
+ mPanDownKey > 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( mOrbitUpKey || mOrbitDownKey )
+ {
+ F32 input_rate = mOrbitUpKey - mOrbitDownKey;
+ cameraOrbitOver( input_rate * ORBIT_OVER_RATE / gFPSClamped );
+ }
+
+ if( mOrbitLeftKey || mOrbitRightKey)
+ {
+ F32 input_rate = mOrbitLeftKey - mOrbitRightKey;
+ cameraOrbitAround( input_rate * ORBIT_AROUND_RATE / gFPSClamped );
+ }
+
+ if( mOrbitInKey || mOrbitOutKey )
+ {
+ F32 input_rate = mOrbitInKey - mOrbitOutKey;
+
+ 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( mPanInKey || mPanOutKey )
+ {
+ F32 input_rate = mPanInKey - mPanOutKey;
+ cameraPanIn( input_rate * PAN_RATE / gFPSClamped );
+ }
+
+ if( mPanRightKey || mPanLeftKey )
+ {
+ F32 input_rate = mPanRightKey - mPanLeftKey;
+ cameraPanLeft( input_rate * -PAN_RATE / gFPSClamped );
+ }
+
+ if( mPanUpKey || mPanDownKey )
+ {
+ F32 input_rate = mPanUpKey - mPanDownKey;
+ cameraPanUp( input_rate * PAN_RATE / gFPSClamped );
+ }
+
+ // Clear camera keyboard keys.
+ mOrbitLeftKey = 0.f;
+ mOrbitRightKey = 0.f;
+ mOrbitUpKey = 0.f;
+ mOrbitDownKey = 0.f;
+ mOrbitInKey = 0.f;
+ mOrbitOutKey = 0.f;
+
+ mPanRightKey = 0.f;
+ mPanLeftKey = 0.f;
+ mPanUpKey = 0.f;
+ mPanDownKey = 0.f;
+ mPanInKey = 0.f;
+ mPanOutKey = 0.f;
+
+ // lerp camera focus offset
+ mCameraFocusOffset = lerp(mCameraFocusOffset, mCameraFocusOffsetTarget, LLCriticalDamp::getInterpolant(CAMERA_FOCUS_HALF_LIFE));
+
+ //Ventrella
+ if ( mCameraMode == CAMERA_MODE_FOLLOW )
+ {
+ if ( mAvatarObject.notNull() )
+ {
+ //--------------------------------------------------------------------------------
+ // 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 = mAvatarObject->mIsSitting ? mAvatarObject->getRenderRotation() : mFrameAgent.getQuaternion();
+
+ LLFollowCamParams* current_cam = LLFollowCamMgr::getActiveFollowCamParams();
+ if (current_cam)
+ {
+ mFollowCam.copyParams(*current_cam);
+ mFollowCam.setSubjectPositionAndRotation( mAvatarObject->getRenderPosition(), avatarRotationForFollowCam );
+ mFollowCam.update();
+ }
+ else
+ {
+ changeCameraToThirdPerson(TRUE);
+ }
+ }
+ }
+ // end Ventrella
+
+ BOOL hit_limit;
+ LLVector3d camera_pos_global;
+ LLVector3d camera_target_global = calcCameraPositionTargetGlobal(&hit_limit);
+ mCameraVirtualPositionAgent = 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);
+
+ mShowAvatar = 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 )
+ {
+ mShowAvatar = 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;
+
+ endAnimationUpdateUI();
+ mShowAvatar = TRUE;
+ }
+
+ if (getAvatarObject() && mCameraMode != CAMERA_MODE_MOUSELOOK)
+ {
+ getAvatarObject()->updateAttachmentVisibility(mCameraMode);
+ }
+ }
+ else
+ {
+ camera_pos_global = camera_target_global;
+ mFocusGlobal = focus_target_global;
+ mShowAvatar = TRUE;
+ }
+
+ // smoothing
+ if (TRUE)
+ {
+ LLVector3d agent_pos = 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
+ mCameraSmoothingStop |= (BOOL)LLToolMgr::getInstance()->inBuildMode();
+
+ 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;
+
+ F32 ui_offset = 0.f;
+ if( CAMERA_MODE_CUSTOMIZE_AVATAR == mCameraMode )
+ {
+ ui_offset = calcCustomizeAvatarUIOffset( camera_pos_global );
+ }
+
+
+ LLVector3 focus_agent = getPosAgentFromGlobal(mFocusGlobal);
+
+ mCameraPositionAgent = getPosAgentFromGlobal(camera_pos_global);
+
+ // Move the camera
+
+ //Ventrella
+ LLViewerCamera::getInstance()->updateCameraLocation(mCameraPositionAgent, mCameraUpVector, focus_agent);
+ //LLViewerCamera::getInstance()->updateCameraLocation(mCameraPositionAgent, camera_skyward, focus_agent);
+ //end Ventrella
+
+ //RN: translate UI offset after camera is oriented properly
+ LLViewerCamera::getInstance()->translate(LLViewerCamera::getInstance()->getLeftAxis() * ui_offset);
+
+ // 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 = getPositionGlobal();
+ if (! mLastPositionGlobal.isExactlyZero())
+ {
+ LLVector3d delta = global_pos - mLastPositionGlobal;
+ mDistanceTraveled += delta.magVec();
+ }
+ mLastPositionGlobal = global_pos;
+
+ if (LLVOAvatar::sVisibleInFirstPerson && mAvatarObject.notNull() && !mAvatarObject->mIsSitting && cameraMouselook())
+ {
+ LLVector3 head_pos = mAvatarObject->mHeadp->getWorldPosition() +
+ LLVector3(0.08f, 0.f, 0.05f) * mAvatarObject->mHeadp->getWorldRotation() +
+ LLVector3(0.1f, 0.f, 0.f) * mAvatarObject->mPelvisp->getWorldRotation();
+ LLVector3 diff = mCameraPositionAgent - head_pos;
+ diff = diff * ~mAvatarObject->mRoot.getWorldRotation();
+
+ LLJoint* torso_joint = mAvatarObject->mTorsop;
+ LLJoint* chest_joint = mAvatarObject->mChestp;
+ LLVector3 torso_scale = torso_joint->getScale();
+ LLVector3 chest_scale = chest_joint->getScale();
+
+ // shorten avatar skeleton to avoid foot interpenetration
+ if (!mAvatarObject->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 = mAvatarObject->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;
+ }
+
+ mAvatarObject->mPelvisp->setPosition(mAvatarObject->mPelvisp->getPosition() + diff);
+
+ mAvatarObject->mRoot.updateWorldMatrixChildren();
+
+ for (LLVOAvatar::attachment_map_t::iterator iter = mAvatarObject->mAttachmentPoints.begin();
+ iter != mAvatarObject->mAttachmentPoints.end(); )
+ {
+ LLVOAvatar::attachment_map_t::iterator curiter = iter++;
+ LLViewerJointAttachment* attachment = curiter->second;
+ LLViewerObject *attached_object = attachment->getObject();
+ 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 LLAgent::updateFocusOffset()
+{
+ validateFocusObject();
+ if (mFocusObject.notNull())
+ {
+ LLVector3d obj_pos = getPosGlobalFromAgent(mFocusObject->getRenderPosition());
+ mFocusObjectOffset.setVec(mFocusTargetGlobal - obj_pos);
+ }
+}
+
+void LLAgent::validateFocusObject()
+{
+ if (mFocusObject.notNull() &&
+ (mFocusObject->isDead()))
+ {
+ mFocusObjectOffset.clearVec();
+ clearFocusObject();
+ mCameraFOVZoomFactor = 0.f;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// calcCustomizeAvatarUIOffset()
+//-----------------------------------------------------------------------------
+F32 LLAgent::calcCustomizeAvatarUIOffset( const LLVector3d& camera_pos_global )
+{
+ F32 ui_offset = 0.f;
+
+ if( gFloaterCustomize )
+ {
+ const LLRect& rect = gFloaterCustomize->getRect();
+
+ // Move the camera so that the avatar isn't covered up by this floater.
+ F32 fraction_of_fov = 0.5f - (0.5f * (1.f - llmin(1.f, ((F32)rect.getWidth() / (F32)gViewerWindow->getWindowWidth()))));
+ F32 apparent_angle = fraction_of_fov * LLViewerCamera::getInstance()->getView() * LLViewerCamera::getInstance()->getAspect(); // radians
+ F32 offset = tan(apparent_angle);
+
+ if( rect.mLeft < (gViewerWindow->getWindowWidth() - rect.mRight) )
+ {
+ // Move the avatar to the right (camera to the left)
+ ui_offset = offset;
+ }
+ else
+ {
+ // Move the avatar to the left (camera to the right)
+ ui_offset = -offset;
+ }
+ }
+ F32 range = (F32)dist_vec(camera_pos_global, gAgent.getFocusGlobal());
+ mUIOffset = lerp(mUIOffset, ui_offset, LLCriticalDamp::getInterpolant(0.05f));
+ return mUIOffset * range;
+}
+
+//-----------------------------------------------------------------------------
+// calcFocusPositionTargetGlobal()
+//-----------------------------------------------------------------------------
+LLVector3d LLAgent::calcFocusPositionTargetGlobal()
+{
+ if (mFocusObject.notNull() && mFocusObject->isDead())
+ {
+ clearFocusObject();
+ }
+
+ // Ventrella
+ if ( mCameraMode == CAMERA_MODE_FOLLOW && mFocusOnAvatar )
+ {
+ mFocusTargetGlobal = gAgent.getPosGlobalFromAgent(mFollowCam.getSimulatedFocus());
+ return mFocusTargetGlobal;
+ }// End Ventrella
+ else if (mCameraMode == CAMERA_MODE_MOUSELOOK)
+ {
+ LLVector3d at_axis(1.0, 0.0, 0.0);
+ LLQuaternion agent_rot = mFrameAgent.getQuaternion();
+ if (mAvatarObject.notNull() && mAvatarObject->getParent())
+ {
+ LLViewerObject* root_object = (LLViewerObject*)mAvatarObject->getRoot();
+ if (!root_object->flagCameraDecoupled())
+ {
+ agent_rot *= ((LLViewerObject*)(mAvatarObject->getParent()))->getRenderRotation();
+ }
+ }
+ at_axis = at_axis * agent_rot;
+ mFocusTargetGlobal = calcCameraPositionTargetGlobal() + at_axis;
+ return mFocusTargetGlobal;
+ }
+ else if (mCameraMode == CAMERA_MODE_CUSTOMIZE_AVATAR)
+ {
+ return mFocusTargetGlobal;
+ }
+ else if (!mFocusOnAvatar)
+ {
+ if (mFocusObject.notNull() && !mFocusObject->isDead() && mFocusObject->mDrawable.notNull())
+ {
+ LLDrawable* drawablep = mFocusObject->mDrawable;
+
+ if (mTrackFocusObject &&
+ drawablep &&
+ drawablep->isActive())
+ {
+ if (!mFocusObject->isAvatar())
+ {
+ if (mFocusObject->isSelected())
+ {
+ gPipeline.updateMoveNormalAsync(drawablep);
+ }
+ else
+ {
+ if (drawablep->isState(LLDrawable::MOVE_UNDAMPED))
+ {
+ gPipeline.updateMoveNormalAsync(drawablep);
+ }
+ else
+ {
+ gPipeline.updateMoveDampedAsync(drawablep);
+ }
+ }
+ }
+ }
+ // if not tracking object, update offset based on new object position
+ else
+ {
+ updateFocusOffset();
+ }
+ LLVector3 focus_agent = mFocusObject->getRenderPosition() + mFocusObjectOffset;
+ mFocusTargetGlobal.setVec(getPosGlobalFromAgent(focus_agent));
+ }
+ return mFocusTargetGlobal;
+ }
+ else if (mSitCameraEnabled && mAvatarObject.notNull() && mAvatarObject->mIsSitting && mSitCameraReferenceObject.notNull())
+ {
+ // sit camera
+ LLVector3 object_pos = mSitCameraReferenceObject->getRenderPosition();
+ LLQuaternion object_rot = mSitCameraReferenceObject->getRenderRotation();
+
+ LLVector3 target_pos = object_pos + (mSitCameraFocus * object_rot);
+ return getPosGlobalFromAgent(target_pos);
+ }
+ else
+ {
+ return getPositionGlobal() + calcThirdPersonFocusOffset();
+ }
+}
+
+LLVector3d LLAgent::calcThirdPersonFocusOffset()
+{
+ // ...offset from avatar
+ LLVector3d focus_offset;
+ focus_offset.setVec(gSavedSettings.getVector3("FocusOffsetDefault"));
+
+ LLQuaternion agent_rot = mFrameAgent.getQuaternion();
+ if (!mAvatarObject.isNull() && mAvatarObject->getParent())
+ {
+ agent_rot *= ((LLViewerObject*)(mAvatarObject->getParent()))->getRenderRotation();
+ }
+
+ focus_offset = focus_offset * agent_rot;
+ return focus_offset;
+}
+
+void LLAgent::setupSitCamera()
+{
+ // agent frame entering this function is in world coordinates
+ if (mAvatarObject.notNull() && mAvatarObject->getParent())
+ {
+ LLQuaternion parent_rot = ((LLViewerObject*)mAvatarObject->getParent())->getRenderRotation();
+ // slam agent coordinate frame to proper parent local version
+ LLVector3 at_axis = mFrameAgent.getAtAxis();
+ at_axis.mV[VZ] = 0.f;
+ at_axis.normalize();
+ resetAxes(at_axis * ~parent_rot);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// getCameraPositionAgent()
+//-----------------------------------------------------------------------------
+const LLVector3 &LLAgent::getCameraPositionAgent() const
+{
+ return LLViewerCamera::getInstance()->getOrigin();
+}
+
+//-----------------------------------------------------------------------------
+// getCameraPositionGlobal()
+//-----------------------------------------------------------------------------
+LLVector3d LLAgent::getCameraPositionGlobal() const
+{
+ return getPosGlobalFromAgent(LLViewerCamera::getInstance()->getOrigin());
+}
+
+//-----------------------------------------------------------------------------
+// calcCameraFOVZoomFactor()
+//-----------------------------------------------------------------------------
+F32 LLAgent::calcCameraFOVZoomFactor()
+{
+ LLVector3 camera_offset_dir;
+ camera_offset_dir.setVec(mCameraFocusOffset);
+
+ if (mCameraMode == CAMERA_MODE_MOUSELOOK)
+ {
+ return 0.f;
+ }
+ else if (mFocusObject.notNull() && !mFocusObject->isAvatar())
+ {
+ // don't FOV zoom on mostly transparent objects
+ LLVector3 focus_offset = mFocusObjectOffset;
+ F32 obj_min_dist = 0.f;
+ calcCameraMinDistance(obj_min_dist);
+ F32 current_distance = llmax(0.001f, camera_offset_dir.magVec());
+
+ mFocusObjectDist = obj_min_dist - current_distance;
+
+ F32 new_fov_zoom = llclamp(mFocusObjectDist / current_distance, 0.f, 1000.f);
+ return new_fov_zoom;
+ }
+ else // focusing on land or avatar
+ {
+ // keep old field of view until user changes focus explicitly
+ return mCameraFOVZoomFactor;
+ //return 0.f;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// calcCameraPositionTargetGlobal()
+//-----------------------------------------------------------------------------
+LLVector3d LLAgent::calcCameraPositionTargetGlobal(BOOL *hit_limit)
+{
+ // Compute base camera position and look-at points.
+ F32 camera_land_height;
+ LLVector3d frame_center_global = mAvatarObject.isNull() ? getPositionGlobal()
+ : getPosGlobalFromAgent(mAvatarObject->mRoot.getWorldPosition());
+
+ LLVector3 upAxis = getUpAxis();
+ BOOL isConstrained = FALSE;
+ LLVector3d head_offset;
+ head_offset.setVec(mThirdPersonHeadOffset);
+
+ LLVector3d camera_position_global;
+
+ // Ventrella
+ if ( mCameraMode == CAMERA_MODE_FOLLOW && mFocusOnAvatar )
+ {
+ camera_position_global = gAgent.getPosGlobalFromAgent(mFollowCam.getSimulatedPosition());
+ }// End Ventrella
+ else if (mCameraMode == CAMERA_MODE_MOUSELOOK)
+ {
+ if (mAvatarObject.isNull() || mAvatarObject->mDrawable.isNull())
+ {
+ llwarns << "Null avatar drawable!" << llendl;
+ return LLVector3d::zero;
+ }
+ head_offset.clearVec();
+ if (mAvatarObject->mIsSitting && mAvatarObject->getParent())
+ {
+ mAvatarObject->updateHeadOffset();
+ head_offset.mdV[VX] = mAvatarObject->mHeadOffset.mV[VX];
+ head_offset.mdV[VY] = mAvatarObject->mHeadOffset.mV[VY];
+ head_offset.mdV[VZ] = mAvatarObject->mHeadOffset.mV[VZ] + 0.1f;
+ const LLMatrix4& mat = ((LLViewerObject*) mAvatarObject->getParent())->getRenderMatrix();
+ camera_position_global = getPosGlobalFromAgent
+ ((mAvatarObject->getPosition()+
+ LLVector3(head_offset)*mAvatarObject->getRotation()) * mat);
+ }
+ else
+ {
+ head_offset.mdV[VZ] = mAvatarObject->mHeadOffset.mV[VZ];
+ if (mAvatarObject->mIsSitting)
+ {
+ head_offset.mdV[VZ] += 0.1;
+ }
+ camera_position_global = getPosGlobalFromAgent(mAvatarObject->getRenderPosition());//frame_center_global;
+ head_offset = head_offset * mAvatarObject->getRenderRotation();
+ camera_position_global = camera_position_global + head_offset;
+ }
+ }
+ else if (mCameraMode == CAMERA_MODE_THIRD_PERSON && mFocusOnAvatar)
+ {
+ LLVector3 local_camera_offset;
+ F32 camera_distance = 0.f;
+
+ if (mSitCameraEnabled
+ && mAvatarObject.notNull()
+ && mAvatarObject->mIsSitting
+ && mSitCameraReferenceObject.notNull())
+ {
+ // sit camera
+ LLVector3 object_pos = mSitCameraReferenceObject->getRenderPosition();
+ LLQuaternion object_rot = mSitCameraReferenceObject->getRenderRotation();
+
+ LLVector3 target_pos = object_pos + (mSitCameraPos * object_rot);
+
+ camera_position_global = getPosGlobalFromAgent(target_pos);
+ }
+ else
+ {
+ local_camera_offset = mCameraZoomFraction * mCameraOffsetDefault * gSavedSettings.getF32("CameraOffsetScale");
+
+ // are we sitting down?
+ if (mAvatarObject.notNull() && mAvatarObject->getParent())
+ {
+ LLQuaternion parent_rot = ((LLViewerObject*)mAvatarObject->getParent())->getRenderRotation();
+ // slam agent coordinate frame to proper parent local version
+ LLVector3 at_axis = mFrameAgent.getAtAxis() * parent_rot;
+ at_axis.mV[VZ] = 0.f;
+ at_axis.normalize();
+ resetAxes(at_axis * ~parent_rot);
+
+ local_camera_offset = local_camera_offset * mFrameAgent.getQuaternion() * parent_rot;
+ }
+ else
+ {
+ local_camera_offset = mFrameAgent.rotateToAbsolute( local_camera_offset );
+ }
+
+ if (!mCameraCollidePlane.isExactlyZero() && (mAvatarObject.isNull() || !mAvatarObject->mIsSitting))
+ {
+ LLVector3 plane_normal;
+ plane_normal.setVec(mCameraCollidePlane.mV);
+
+ F32 offset_dot_norm = local_camera_offset * plane_normal;
+ if (llabs(offset_dot_norm) < 0.001f)
+ {
+ offset_dot_norm = 0.001f;
+ }
+
+ camera_distance = local_camera_offset.normalize();
+
+ F32 pos_dot_norm = getPosAgentFromGlobal(frame_center_global + head_offset) * plane_normal;
+
+ // if agent is outside the colliding half-plane
+ if (pos_dot_norm > mCameraCollidePlane.mV[VW])
+ {
+ // check to see if camera is on the opposite side (inside) the half-plane
+ if (offset_dot_norm + pos_dot_norm < mCameraCollidePlane.mV[VW])
+ {
+ // diminish offset by factor to push it back outside the half-plane
+ camera_distance *= (pos_dot_norm - mCameraCollidePlane.mV[VW] - CAMERA_COLLIDE_EPSILON) / -offset_dot_norm;
+ }
+ }
+ else
+ {
+ if (offset_dot_norm + pos_dot_norm > mCameraCollidePlane.mV[VW])
+ {
+ camera_distance *= (mCameraCollidePlane.mV[VW] - pos_dot_norm - CAMERA_COLLIDE_EPSILON) / offset_dot_norm;
+ }
+ }
+ }
+ else
+ {
+ camera_distance = local_camera_offset.normalize();
+ }
+
+ mTargetCameraDistance = llmax(camera_distance, MIN_CAMERA_DISTANCE);
+
+ if (mTargetCameraDistance != mCurrentCameraDistance)
+ {
+ F32 camera_lerp_amt = LLCriticalDamp::getInterpolant(CAMERA_ZOOM_HALF_LIFE);
+
+ mCurrentCameraDistance = lerp(mCurrentCameraDistance, mTargetCameraDistance, camera_lerp_amt);
+ }
+
+ // Make the camera distance current
+ local_camera_offset *= mCurrentCameraDistance;
+
+ // set the global camera position
+ LLVector3d camera_offset;
+
+ LLVector3 av_pos = mAvatarObject.isNull() ? LLVector3::zero : mAvatarObject->getRenderPosition();
+ camera_offset.setVec( local_camera_offset );
+ camera_position_global = frame_center_global + head_offset + camera_offset;
+
+ if (mAvatarObject.notNull())
+ {
+ LLVector3d camera_lag_d;
+ F32 lag_interp = LLCriticalDamp::getInterpolant(CAMERA_LAG_HALF_LIFE);
+ LLVector3 target_lag;
+ LLVector3 vel = getVelocity();
+
+ // lag by appropriate amount for flying
+ F32 time_in_air = mAvatarObject->mTimeInAir.getElapsedTimeF32();
+ if(!mCameraAnimating && mAvatarObject->mInAir && time_in_air > GROUND_TO_AIR_CAMERA_TRANSITION_START_TIME)
+ {
+ LLVector3 frame_at_axis = mFrameAgent.getAtAxis();
+ frame_at_axis -= projected_vec(frame_at_axis, getReferenceUpVector());
+ frame_at_axis.normalize();
+
+ //transition smoothly in air mode, to avoid camera pop
+ F32 u = (time_in_air - GROUND_TO_AIR_CAMERA_TRANSITION_START_TIME) / GROUND_TO_AIR_CAMERA_TRANSITION_TIME;
+ u = llclamp(u, 0.f, 1.f);
+
+ lag_interp *= u;
+
+ if (gViewerWindow->getLeftMouseDown() && gViewerWindow->getLastPick().mObjectID == mAvatarObject->getID())
+ {
+ // disable camera lag when using mouse-directed steering
+ target_lag.clearVec();
+ }
+ else
+ {
+ target_lag = vel * gSavedSettings.getF32("DynamicCameraStrength") / 30.f;
+ }
+
+ mCameraLag = lerp(mCameraLag, target_lag, lag_interp);
+
+ F32 lag_dist = mCameraLag.magVec();
+ if (lag_dist > MAX_CAMERA_LAG)
+ {
+ mCameraLag = mCameraLag * MAX_CAMERA_LAG / lag_dist;
+ }
+
+ // clamp camera lag so that avatar is always in front
+ F32 dot = (mCameraLag - (frame_at_axis * (MIN_CAMERA_LAG * u))) * frame_at_axis;
+ if (dot < -(MIN_CAMERA_LAG * u))
+ {
+ mCameraLag -= (dot + (MIN_CAMERA_LAG * u)) * frame_at_axis;
+ }
+ }
+ else
+ {
+ mCameraLag = lerp(mCameraLag, LLVector3::zero, LLCriticalDamp::getInterpolant(0.15f));
+ }
+
+ camera_lag_d.setVec(mCameraLag);
+ camera_position_global = camera_position_global - camera_lag_d;
+ }
+ }
+ }
+ else
+ {
+ LLVector3d focusPosGlobal = calcFocusPositionTargetGlobal();
+ // camera gets pushed out later wrt mCameraFOVZoomFactor...this is "raw" value
+ camera_position_global = focusPosGlobal + mCameraFocusOffset;
+ }
+
+ if (!gSavedSettings.getBOOL("DisableCameraConstraints") && !gAgent.isGodlike())
+ {
+ LLViewerRegion* regionp = LLWorld::getInstance()->getRegionFromPosGlobal(
+ camera_position_global);
+ bool constrain = true;
+ if(regionp && regionp->canManageEstate())
+ {
+ constrain = false;
+ }
+ if(constrain)
+ {
+ F32 max_dist = ( CAMERA_MODE_CUSTOMIZE_AVATAR == mCameraMode ) ?
+ APPEARANCE_MAX_ZOOM : mDrawDistance;
+
+ LLVector3d camera_offset = camera_position_global
+ - gAgent.getPositionGlobal();
+ F32 camera_distance = (F32)camera_offset.magVec();
+
+ if(camera_distance > max_dist)
+ {
+ camera_position_global = gAgent.getPositionGlobal() +
+ (max_dist / camera_distance) * camera_offset;
+ isConstrained = TRUE;
+ }
+ }
+
+// JC - Could constrain camera based on parcel stuff here.
+// LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromPosGlobal(camera_position_global);
+//
+// if (regionp && !regionp->mParcelOverlay->isBuildCameraAllowed(regionp->getPosRegionFromGlobal(camera_position_global)))
+// {
+// camera_position_global = last_position_global;
+//
+// isConstrained = TRUE;
+// }
+ }
+
+ // Don't let camera go underground
+ F32 camera_min_off_ground = getCameraMinOffGround();
+
+ camera_land_height = LLWorld::getInstance()->resolveLandHeightGlobal(camera_position_global);
+
+ if (camera_position_global.mdV[VZ] < camera_land_height + camera_min_off_ground)
+ {
+ camera_position_global.mdV[VZ] = camera_land_height + camera_min_off_ground;
+ isConstrained = TRUE;
+ }
+
+
+ if (hit_limit)
+ {
+ *hit_limit = isConstrained;
+ }
+
+ return camera_position_global;
+}
+
+
+//-----------------------------------------------------------------------------
+// handleScrollWheel()
+//-----------------------------------------------------------------------------
+void LLAgent::handleScrollWheel(S32 clicks)
+{
+ if ( mCameraMode == CAMERA_MODE_FOLLOW && gAgent.getFocusOnAvatar())
+ {
+ if ( ! mFollowCam.getPositionLocked() ) // not if the followCam position is locked in place
+ {
+ mFollowCam.zoom( clicks );
+ if ( mFollowCam.isZoomedToMinimumDistance() )
+ {
+ changeCameraToMouselook(FALSE);
+ }
+ }
+ }
+ else
+ {
+ LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection();
+ const F32 ROOT_ROOT_TWO = sqrt(F_SQRT2);
+
+ // Block if camera is animating
+ if (mCameraAnimating)
+ {
+ return;
+ }
+
+ if (selection->getObjectCount() && selection->getSelectType() == SELECT_TYPE_HUD)
+ {
+ F32 zoom_factor = (F32)pow(0.8, -clicks);
+ cameraZoomIn(zoom_factor);
+ }
+ else if (mFocusOnAvatar && mCameraMode == CAMERA_MODE_THIRD_PERSON)
+ {
+ F32 current_zoom_fraction = mTargetCameraDistance / (mCameraOffsetDefault.magVec() * gSavedSettings.getF32("CameraOffsetScale"));
+ current_zoom_fraction *= 1.f - pow(ROOT_ROOT_TWO, clicks);
+
+ cameraOrbitIn(current_zoom_fraction * mCameraOffsetDefault.magVec() * gSavedSettings.getF32("CameraOffsetScale"));
+ }
+ else
+ {
+ F32 current_zoom_fraction = (F32)mCameraFocusOffsetTarget.magVec();
+ cameraOrbitIn(current_zoom_fraction * (1.f - pow(ROOT_ROOT_TWO, clicks)));
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// getCameraMinOffGround()
+//-----------------------------------------------------------------------------
+F32 LLAgent::getCameraMinOffGround()
+{
+ if (mCameraMode == CAMERA_MODE_MOUSELOOK)
+ {
+ return 0.f;
+ }
+ else
+ {
+ if (gSavedSettings.getBOOL("DisableCameraConstraints"))
+ {
+ return -1000.f;
+ }
+ else
+ {
+ return 0.5f;
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// resetCamera()
+//-----------------------------------------------------------------------------
+void LLAgent::resetCamera()
+{
+ // Remove any pitch from the avatar
+ LLVector3 at = mFrameAgent.getAtAxis();
+ at.mV[VZ] = 0.f;
+ at.normalize();
+ gAgent.resetAxes(at);
+ // have to explicitly clear field of view zoom now
+ mCameraFOVZoomFactor = 0.f;
+
+ updateCamera();
+}
+
+//-----------------------------------------------------------------------------
+// changeCameraToMouselook()
+//-----------------------------------------------------------------------------
+void LLAgent::changeCameraToMouselook(BOOL animate)
+{
+ if (LLViewerJoystick::getInstance()->getOverrideCamera())
+ {
+ return;
+ }
+
+ // visibility changes at end of animation
+ gViewerWindow->getWindow()->resetBusyCount();
+
+ // Menus should not remain open on switching to mouselook...
+ LLMenuGL::sMenuContainer->hideMenus();
+
+ // unpause avatar animation
+ mPauseRequest = NULL;
+
+ LLToolMgr::getInstance()->setCurrentToolset(gMouselookToolset);
+
+ gSavedSettings.setBOOL("FirstPersonBtnState", FALSE);
+ gSavedSettings.setBOOL("MouselookBtnState", TRUE);
+ gSavedSettings.setBOOL("ThirdPersonBtnState", FALSE);
+ gSavedSettings.setBOOL("BuildBtnState", FALSE);
+
+ if (mAvatarObject.notNull())
+ {
+ mAvatarObject->stopMotion( ANIM_AGENT_BODY_NOISE );
+ mAvatarObject->stopMotion( ANIM_AGENT_BREATHE_ROT );
+ }
+
+ //gViewerWindow->stopGrab();
+ LLSelectMgr::getInstance()->deselectAll();
+ gViewerWindow->hideCursor();
+ gViewerWindow->moveCursorToCenter();
+
+ if( mCameraMode != CAMERA_MODE_MOUSELOOK )
+ {
+ gFocusMgr.setKeyboardFocus( NULL );
+
+ mLastCameraMode = mCameraMode;
+ mCameraMode = CAMERA_MODE_MOUSELOOK;
+ U32 old_flags = mControlFlags;
+ setControlFlags(AGENT_CONTROL_MOUSELOOK);
+ if (old_flags != mControlFlags)
+ {
+ mbFlagsDirty = TRUE;
+ }
+
+ if (animate)
+ {
+ startCameraAnimation();
+ }
+ else
+ {
+ mCameraAnimating = FALSE;
+ endAnimationUpdateUI();
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// changeCameraToDefault()
+//-----------------------------------------------------------------------------
+void LLAgent::changeCameraToDefault()
+{
+ if (LLViewerJoystick::getInstance()->getOverrideCamera())
+ {
+ return;
+ }
+
+ if (LLFollowCamMgr::getActiveFollowCamParams())
+ {
+ changeCameraToFollow();
+ }
+ else
+ {
+ changeCameraToThirdPerson();
+ }
+}
+
+
+// Ventrella
+//-----------------------------------------------------------------------------
+// changeCameraToFollow()
+//-----------------------------------------------------------------------------
+void LLAgent::changeCameraToFollow(BOOL animate)
+{
+ if (LLViewerJoystick::getInstance()->getOverrideCamera())
+ {
+ return;
+ }
+
+ if( mCameraMode != CAMERA_MODE_FOLLOW )
+ {
+ if (mCameraMode == CAMERA_MODE_MOUSELOOK)
+ {
+ animate = FALSE;
+ }
+ startCameraAnimation();
+
+ mLastCameraMode = mCameraMode;
+ mCameraMode = CAMERA_MODE_FOLLOW;
+
+ // bang-in the current focus, position, and up vector of the follow cam
+ mFollowCam.reset( mCameraPositionAgent, LLViewerCamera::getInstance()->getPointOfInterest(), LLVector3::z_axis );
+
+ if (gBasicToolset)
+ {
+ LLToolMgr::getInstance()->setCurrentToolset(gBasicToolset);
+ }
+
+ if (mAvatarObject.notNull())
+ {
+ mAvatarObject->mPelvisp->setPosition(LLVector3::zero);
+ mAvatarObject->startMotion( ANIM_AGENT_BODY_NOISE );
+ mAvatarObject->startMotion( ANIM_AGENT_BREATHE_ROT );
+ }
+
+ gSavedSettings.setBOOL("FirstPersonBtnState", FALSE);
+ gSavedSettings.setBOOL("MouselookBtnState", FALSE);
+ gSavedSettings.setBOOL("ThirdPersonBtnState", TRUE);
+ gSavedSettings.setBOOL("BuildBtnState", FALSE);
+
+ // unpause avatar animation
+ mPauseRequest = NULL;
+
+ U32 old_flags = mControlFlags;
+ clearControlFlags(AGENT_CONTROL_MOUSELOOK);
+ if (old_flags != mControlFlags)
+ {
+ mbFlagsDirty = TRUE;
+ }
+
+ if (animate)
+ {
+ startCameraAnimation();
+ }
+ else
+ {
+ mCameraAnimating = FALSE;
+ endAnimationUpdateUI();
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// changeCameraToThirdPerson()
+//-----------------------------------------------------------------------------
+void LLAgent::changeCameraToThirdPerson(BOOL animate)
+{
+ if (LLViewerJoystick::getInstance()->getOverrideCamera())
+ {
+ return;
+ }
+
+ gViewerWindow->getWindow()->resetBusyCount();
+
+ mCameraZoomFraction = INITIAL_ZOOM_FRACTION;
+
+ if (mAvatarObject.notNull())
+ {
+ if (!mAvatarObject->mIsSitting)
+ {
+ mAvatarObject->mPelvisp->setPosition(LLVector3::zero);
+ }
+ mAvatarObject->startMotion( ANIM_AGENT_BODY_NOISE );
+ mAvatarObject->startMotion( ANIM_AGENT_BREATHE_ROT );
+ }
+
+ gSavedSettings.setBOOL("FirstPersonBtnState", FALSE);
+ gSavedSettings.setBOOL("MouselookBtnState", FALSE);
+ gSavedSettings.setBOOL("ThirdPersonBtnState", TRUE);
+ gSavedSettings.setBOOL("BuildBtnState", FALSE);
+
+ LLVector3 at_axis;
+
+ // unpause avatar animation
+ mPauseRequest = NULL;
+
+ if( mCameraMode != CAMERA_MODE_THIRD_PERSON )
+ {
+ if (gBasicToolset)
+ {
+ LLToolMgr::getInstance()->setCurrentToolset(gBasicToolset);
+ }
+
+ mCameraLag.clearVec();
+ if (mCameraMode == CAMERA_MODE_MOUSELOOK)
+ {
+ mCurrentCameraDistance = MIN_CAMERA_DISTANCE;
+ mTargetCameraDistance = MIN_CAMERA_DISTANCE;
+ animate = FALSE;
+ }
+ mLastCameraMode = mCameraMode;
+ mCameraMode = CAMERA_MODE_THIRD_PERSON;
+ U32 old_flags = mControlFlags;
+ clearControlFlags(AGENT_CONTROL_MOUSELOOK);
+ if (old_flags != mControlFlags)
+ {
+ mbFlagsDirty = TRUE;
+ }
+
+ }
+
+ // Remove any pitch from the avatar
+ if (mAvatarObject.notNull() && mAvatarObject->getParent())
+ {
+ LLQuaternion obj_rot = ((LLViewerObject*)mAvatarObject->getParent())->getRenderRotation();
+ at_axis = LLViewerCamera::getInstance()->getAtAxis();
+ at_axis.mV[VZ] = 0.f;
+ at_axis.normalize();
+ resetAxes(at_axis * ~obj_rot);
+ }
+ else
+ {
+ at_axis = mFrameAgent.getAtAxis();
+ at_axis.mV[VZ] = 0.f;
+ at_axis.normalize();
+ resetAxes(at_axis);
+ }
+
+
+ if (animate)
+ {
+ startCameraAnimation();
+ }
+ else
+ {
+ mCameraAnimating = FALSE;
+ endAnimationUpdateUI();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// changeCameraToCustomizeAvatar()
+//-----------------------------------------------------------------------------
+void LLAgent::changeCameraToCustomizeAvatar(BOOL avatar_animate, BOOL camera_animate)
+{
+ if (LLViewerJoystick::getInstance()->getOverrideCamera())
+ {
+ return;
+ }
+
+ //
+ //setControlFlags(AGENT_CONTROL_STAND_UP); // force stand up
+ //
+ gViewerWindow->getWindow()->resetBusyCount();
+
+ if (gFaceEditToolset)
+ {
+ LLToolMgr::getInstance()->setCurrentToolset(gFaceEditToolset);
+ }
+
+ gSavedSettings.setBOOL("FirstPersonBtnState", FALSE);
+ gSavedSettings.setBOOL("MouselookBtnState", FALSE);
+ gSavedSettings.setBOOL("ThirdPersonBtnState", FALSE);
+ gSavedSettings.setBOOL("BuildBtnState", FALSE);
+
+ if (camera_animate)
+ {
+ //
+ if(gSavedSettings.getBOOL("AppearanceCameraMovement"))
+ //
+ startCameraAnimation();
+ }
+
+ // Remove any pitch from the avatar
+ //LLVector3 at = mFrameAgent.getAtAxis();
+ //at.mV[VZ] = 0.f;
+ //at.normalize();
+ //gAgent.resetAxes(at);
+
+ if( mCameraMode != CAMERA_MODE_CUSTOMIZE_AVATAR )
+ {
+ mLastCameraMode = mCameraMode;
+ mCameraMode = CAMERA_MODE_CUSTOMIZE_AVATAR;
+ U32 old_flags = mControlFlags;
+ clearControlFlags(AGENT_CONTROL_MOUSELOOK);
+ if (old_flags != mControlFlags)
+ {
+ mbFlagsDirty = TRUE;
+ }
+
+ gFocusMgr.setKeyboardFocus( NULL );
+ gFocusMgr.setMouseCapture( NULL );
+
+ LLVOAvatar::onCustomizeStart();
+ }
+
+ if (mAvatarObject.notNull())
+ {
+ if(avatar_animate)
+ {
+ // Remove any pitch from the avatar
+ LLVector3 at = mFrameAgent.getAtAxis();
+ at.mV[VZ] = 0.f;
+ at.normalize();
+ gAgent.resetAxes(at);
+
+ sendAnimationRequest(ANIM_AGENT_CUSTOMIZE, ANIM_REQUEST_START);
+ mCustomAnim = TRUE ;
+ mAvatarObject->startMotion(ANIM_AGENT_CUSTOMIZE);
+ LLMotion* turn_motion = mAvatarObject->findMotion(ANIM_AGENT_CUSTOMIZE);
+
+ if (turn_motion)
+ {
+ mAnimationDuration = turn_motion->getDuration() + CUSTOMIZE_AVATAR_CAMERA_ANIM_SLOP;
+
+ }
+ else
+ {
+ mAnimationDuration = gSavedSettings.getF32("ZoomTime");
+ }
+ }
+
+
+
+ gAgent.setFocusGlobal(LLVector3d::zero);
+ }
+ else
+ {
+ mCameraAnimating = FALSE;
+ endAnimationUpdateUI();
+ }
+
+ //
+ if(!gSavedSettings.getBOOL("AppearanceCameraMovement"))
+ {
+ //hmm
+ mCameraAnimating = FALSE;
+ endAnimationUpdateUI();
+ }
+
+}
+
+
+//
+// Focus point management
+//
+
+//-----------------------------------------------------------------------------
+// startCameraAnimation()
+//-----------------------------------------------------------------------------
+void LLAgent::startCameraAnimation()
+{
+ mAnimationCameraStartGlobal = getCameraPositionGlobal();
+ mAnimationFocusStartGlobal = mFocusGlobal;
+ mAnimationTimer.reset();
+ mCameraAnimating = TRUE;
+ mAnimationDuration = gSavedSettings.getF32("ZoomTime");
+}
+
+//-----------------------------------------------------------------------------
+// stopCameraAnimation()
+//-----------------------------------------------------------------------------
+void LLAgent::stopCameraAnimation()
+{
+ mCameraAnimating = FALSE;
+}
+
+void LLAgent::clearFocusObject()
+{
+ if (mFocusObject.notNull())
+ {
+ startCameraAnimation();
+
+ setFocusObject(NULL);
+ mFocusObjectOffset.clearVec();
+ }
+}
+
+void LLAgent::setFocusObject(LLViewerObject* object)
+{
+ mFocusObject = object;
+}
+
+// Focus on a point, but try to keep camera position stable.
+//-----------------------------------------------------------------------------
+// setFocusGlobal()
+//-----------------------------------------------------------------------------
+void LLAgent::setFocusGlobal(const LLPickInfo& pick)
+{
+ LLViewerObject* objectp = gObjectList.findObject(pick.mObjectID);
+
+ if (objectp)
+ {
+ // focus on object plus designated offset
+ // which may or may not be same as pick.mPosGlobal
+ setFocusGlobal(objectp->getPositionGlobal() + LLVector3d(pick.mObjectOffset), pick.mObjectID);
+ }
+ else
+ {
+ // focus directly on point where user clicked
+ setFocusGlobal(pick.mPosGlobal, pick.mObjectID);
+ }
+}
+
+
+void LLAgent::setFocusGlobal(const LLVector3d& focus, const LLUUID &object_id)
+{
+ setFocusObject(gObjectList.findObject(object_id));
+ LLVector3d old_focus = mFocusTargetGlobal;
+ LLViewerObject *focus_obj = mFocusObject;
+
+ // if focus has changed
+ if (old_focus != focus)
+ {
+ if (focus.isExactlyZero())
+ {
+ if (mAvatarObject.notNull())
+ {
+ mFocusTargetGlobal = getPosGlobalFromAgent(mAvatarObject->mHeadp->getWorldPosition());
+ }
+ else
+ {
+ mFocusTargetGlobal = getPositionGlobal();
+ }
+ mCameraFocusOffsetTarget = getCameraPositionGlobal() - mFocusTargetGlobal;
+ mCameraFocusOffset = mCameraFocusOffsetTarget;
+ setLookAt(LOOKAT_TARGET_CLEAR);
+ }
+ else
+ {
+ mFocusTargetGlobal = focus;
+ if (!focus_obj)
+ {
+ mCameraFOVZoomFactor = 0.f;
+ }
+
+ mCameraFocusOffsetTarget = gAgent.getPosGlobalFromAgent(mCameraVirtualPositionAgent) - mFocusTargetGlobal;
+
+ startCameraAnimation();
+
+ if (focus_obj)
+ {
+ if (focus_obj->isAvatar())
+ {
+ setLookAt(LOOKAT_TARGET_FOCUS, focus_obj);
+ }
+ else
+ {
+ setLookAt(LOOKAT_TARGET_FOCUS, focus_obj, (getPosAgentFromGlobal(focus) - focus_obj->getRenderPosition()) * ~focus_obj->getRenderRotation());
+ }
+ }
+ else
+ {
+ setLookAt(LOOKAT_TARGET_FOCUS, NULL, getPosAgentFromGlobal(mFocusTargetGlobal));
+ }
+ }
+ }
+ else // focus == mFocusTargetGlobal
+ {
+ if (focus.isExactlyZero())
+ {
+ if (mAvatarObject.notNull())
+ {
+ mFocusTargetGlobal = getPosGlobalFromAgent(mAvatarObject->mHeadp->getWorldPosition());
+ }
+ else
+ {
+ mFocusTargetGlobal = getPositionGlobal();
+ }
+ }
+ mCameraFocusOffsetTarget = (getCameraPositionGlobal() - mFocusTargetGlobal) / (1.f + mCameraFOVZoomFactor);;
+ mCameraFocusOffset = mCameraFocusOffsetTarget;
+ }
+
+ if (mFocusObject.notNull())
+ {
+ // for attachments, make offset relative to avatar, not the attachment
+ if (mFocusObject->isAttachment())
+ {
+ while (mFocusObject.notNull() // DEV-29123 - can crash with a messed-up attachment
+ && !mFocusObject->isAvatar())
+ {
+ mFocusObject = (LLViewerObject*) mFocusObject->getParent();
+ }
+ setFocusObject((LLViewerObject*)mFocusObject);
+ }
+ updateFocusOffset();
+ }
+}
+
+// Used for avatar customization
+//-----------------------------------------------------------------------------
+// setCameraPosAndFocusGlobal()
+//-----------------------------------------------------------------------------
+void LLAgent::setCameraPosAndFocusGlobal(const LLVector3d& camera_pos, const LLVector3d& focus, const LLUUID &object_id)
+{
+ LLVector3d old_focus = mFocusTargetGlobal;
+
+ F64 focus_delta_squared = (old_focus - focus).magVecSquared();
+ const F64 ANIM_EPSILON_SQUARED = 0.0001;
+ if( focus_delta_squared > ANIM_EPSILON_SQUARED )
+ {
+ startCameraAnimation();
+
+ if( CAMERA_MODE_CUSTOMIZE_AVATAR == mCameraMode )
+ {
+ // Compensate for the fact that the camera has already been offset to make room for LLFloaterCustomize.
+ mAnimationCameraStartGlobal -= LLVector3d(LLViewerCamera::getInstance()->getLeftAxis() * calcCustomizeAvatarUIOffset( mAnimationCameraStartGlobal ));
+ }
+ }
+
+ //LLViewerCamera::getInstance()->setOrigin( gAgent.getPosAgentFromGlobal( camera_pos ) );
+ setFocusObject(gObjectList.findObject(object_id));
+ mFocusTargetGlobal = focus;
+ mCameraFocusOffsetTarget = camera_pos - focus;
+ mCameraFocusOffset = mCameraFocusOffsetTarget;
+
+ if (mFocusObject)
+ {
+ if (mFocusObject->isAvatar())
+ {
+ setLookAt(LOOKAT_TARGET_FOCUS, mFocusObject);
+ }
+ else
+ {
+ setLookAt(LOOKAT_TARGET_FOCUS, mFocusObject, (getPosAgentFromGlobal(focus) - mFocusObject->getRenderPosition()) * ~mFocusObject->getRenderRotation());
+ }
+ }
+ else
+ {
+ setLookAt(LOOKAT_TARGET_FOCUS, NULL, getPosAgentFromGlobal(mFocusTargetGlobal));
+ }
+
+ if( mCameraAnimating )
+ {
+ const F64 ANIM_METERS_PER_SECOND = 10.0;
+ const F64 MIN_ANIM_SECONDS = 0.5;
+ F64 anim_duration = llmax( MIN_ANIM_SECONDS, sqrt(focus_delta_squared) / ANIM_METERS_PER_SECOND );
+ setAnimationDuration( (F32)anim_duration );
+ }
+
+ updateFocusOffset();
+}
+
+//-----------------------------------------------------------------------------
+// setSitCamera()
+//-----------------------------------------------------------------------------
+void LLAgent::setSitCamera(const LLUUID &object_id, const LLVector3 &camera_pos, const LLVector3 &camera_focus)
+{
+ BOOL camera_enabled = !object_id.isNull();
+
+ if (camera_enabled)
+ {
+ LLViewerObject *reference_object = gObjectList.findObject(object_id);
+ if (reference_object)
+ {
+ //convert to root object relative?
+ mSitCameraPos = camera_pos;
+ mSitCameraFocus = camera_focus;
+ mSitCameraReferenceObject = reference_object;
+ mSitCameraEnabled = TRUE;
+ }
+ }
+ else
+ {
+ mSitCameraPos.clearVec();
+ mSitCameraFocus.clearVec();
+ mSitCameraReferenceObject = NULL;
+ mSitCameraEnabled = FALSE;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// setFocusOnAvatar()
+//-----------------------------------------------------------------------------
+void LLAgent::setFocusOnAvatar(BOOL focus_on_avatar, BOOL animate)
+{
+ if (focus_on_avatar != mFocusOnAvatar)
+ {
+ if (animate)
+ {
+ startCameraAnimation();
+ }
+ else
+ {
+ stopCameraAnimation();
+ }
+ }
+
+ //RN: when focused on the avatar, we're not "looking" at it
+ // looking implies intent while focusing on avatar means
+ // you're just walking around with a camera on you...eesh.
+ if (!mFocusOnAvatar && focus_on_avatar)
+ {
+ setFocusGlobal(LLVector3d::zero);
+ mCameraFOVZoomFactor = 0.f;
+ if (mCameraMode == CAMERA_MODE_THIRD_PERSON)
+ {
+ LLVector3 at_axis;
+ if (mAvatarObject.notNull() && mAvatarObject->getParent())
+ {
+ LLQuaternion obj_rot = ((LLViewerObject*)mAvatarObject->getParent())->getRenderRotation();
+ at_axis = LLViewerCamera::getInstance()->getAtAxis();
+ at_axis.mV[VZ] = 0.f;
+ at_axis.normalize();
+ resetAxes(at_axis * ~obj_rot);
+ }
+ else
+ {
+ at_axis = LLViewerCamera::getInstance()->getAtAxis();
+ at_axis.mV[VZ] = 0.f;
+ at_axis.normalize();
+ resetAxes(at_axis);
+ }
+ }
+ }
+ // unlocking camera from avatar
+ else if (mFocusOnAvatar && !focus_on_avatar)
+ {
+ // keep camera focus point consistent, even though it is now unlocked
+ setFocusGlobal(getPositionGlobal() + calcThirdPersonFocusOffset(), gAgent.getID());
+ }
+
+ mFocusOnAvatar = focus_on_avatar;
+}
+
+//-----------------------------------------------------------------------------
+// heardChat()
+//-----------------------------------------------------------------------------
+void LLAgent::heardChat(const LLUUID& id)
+{
+ // log text and voice chat to speaker mgr
+ // for keeping track of active speakers, etc.
+ LLLocalSpeakerMgr::getInstance()->speakerChatted(id);
+
+ // don't respond to your own voice
+ if (id == getID()) return;
+
+ if (ll_rand(2) == 0)
+ {
+ LLViewerObject *chatter = gObjectList.findObject(mLastChatterID);
+ setLookAt(LOOKAT_TARGET_AUTO_LISTEN, chatter, LLVector3::zero);
+ }
+
+ mLastChatterID = id;
+ mChatTimer.reset();
+}
+
+//-----------------------------------------------------------------------------
+// lookAtLastChat()
+//-----------------------------------------------------------------------------
+void LLAgent::lookAtLastChat()
+{
+ // Block if camera is animating or not in normal third person camera mode
+ if (mCameraAnimating || !cameraThirdPerson())
+ {
+ return;
+ }
+
+ LLViewerObject *chatter = gObjectList.findObject(mLastChatterID);
+ if (chatter)
+ {
+ LLVector3 delta_pos;
+ if (chatter->isAvatar())
+ {
+ LLVOAvatar *chatter_av = (LLVOAvatar*)chatter;
+ if (mAvatarObject.notNull() && chatter_av->mHeadp)
+ {
+ delta_pos = chatter_av->mHeadp->getWorldPosition() - mAvatarObject->mHeadp->getWorldPosition();
+ }
+ else
+ {
+ delta_pos = chatter->getPositionAgent() - getPositionAgent();
+ }
+ delta_pos.normalize();
+
+ setControlFlags(AGENT_CONTROL_STOP);
+
+ changeCameraToThirdPerson();
+
+ LLVector3 new_camera_pos = mAvatarObject->mHeadp->getWorldPosition();
+ LLVector3 left = delta_pos % LLVector3::z_axis;
+ left.normalize();
+ LLVector3 up = left % delta_pos;
+ up.normalize();
+ new_camera_pos -= delta_pos * 0.4f;
+ new_camera_pos += left * 0.3f;
+ new_camera_pos += up * 0.2f;
+ if (chatter_av->mHeadp)
+ {
+ setFocusGlobal(getPosGlobalFromAgent(chatter_av->mHeadp->getWorldPosition()), mLastChatterID);
+ mCameraFocusOffsetTarget = getPosGlobalFromAgent(new_camera_pos) - gAgent.getPosGlobalFromAgent(chatter_av->mHeadp->getWorldPosition());
+ }
+ else
+ {
+ setFocusGlobal(chatter->getPositionGlobal(), mLastChatterID);
+ mCameraFocusOffsetTarget = getPosGlobalFromAgent(new_camera_pos) - chatter->getPositionGlobal();
+ }
+ setFocusOnAvatar(FALSE, TRUE);
+ }
+ else
+ {
+ delta_pos = chatter->getRenderPosition() - getPositionAgent();
+ delta_pos.normalize();
+
+ setControlFlags(AGENT_CONTROL_STOP);
+
+ changeCameraToThirdPerson();
+
+ LLVector3 new_camera_pos = mAvatarObject->mHeadp->getWorldPosition();
+ LLVector3 left = delta_pos % LLVector3::z_axis;
+ left.normalize();
+ LLVector3 up = left % delta_pos;
+ up.normalize();
+ new_camera_pos -= delta_pos * 0.4f;
+ new_camera_pos += left * 0.3f;
+ new_camera_pos += up * 0.2f;
+
+ setFocusGlobal(chatter->getPositionGlobal(), mLastChatterID);
+ mCameraFocusOffsetTarget = getPosGlobalFromAgent(new_camera_pos) - chatter->getPositionGlobal();
+ setFocusOnAvatar(FALSE, TRUE);
+ }
+ }
+}
+
+void LLAgent::lookAtObject(LLUUID object_id, ECameraPosition camera_pos)
+{
+ // Block if camera is animating or not in normal third person camera mode
+ if (mCameraAnimating || !cameraThirdPerson())
+ {
+ return;
+ }
+
+ LLViewerObject *chatter = gObjectList.findObject(object_id);
+ if (chatter)
+ {
+ LLVector3 delta_pos;
+ if (chatter->isAvatar())
+ {
+ LLVOAvatar *chatter_av = (LLVOAvatar*)chatter;
+ if (!mAvatarObject.isNull() && chatter_av->mHeadp)
+ {
+ delta_pos = chatter_av->mHeadp->getWorldPosition() - mAvatarObject->mHeadp->getWorldPosition();
+ }
+ else
+ {
+ delta_pos = chatter->getPositionAgent() - getPositionAgent();
+ }
+ delta_pos.normVec();
+
+ setControlFlags(AGENT_CONTROL_STOP);
+
+ changeCameraToThirdPerson();
+
+ LLVector3 new_camera_pos = mAvatarObject->mHeadp->getWorldPosition();
+ LLVector3 left = delta_pos % LLVector3::z_axis;
+ left.normVec();
+ LLVector3 up = left % delta_pos;
+ up.normVec();
+ new_camera_pos -= delta_pos * 0.4f;
+ new_camera_pos += left * 0.3f;
+ new_camera_pos += up * 0.2f;
+
+ F32 radius = chatter_av->getVObjRadius();
+ LLVector3d view_dist(radius, radius, 0.0f);
+
+ if (chatter_av->mHeadp)
+ {
+ setFocusGlobal(getPosGlobalFromAgent(chatter_av->mHeadp->getWorldPosition()), object_id);
+ mCameraFocusOffsetTarget = getPosGlobalFromAgent(new_camera_pos) - gAgent.getPosGlobalFromAgent(chatter_av->mHeadp->getWorldPosition());
+
+ switch(camera_pos)
+ {
+ case CAMERA_POSITION_SELF:
+ mCameraFocusOffsetTarget = getPosGlobalFromAgent(new_camera_pos) - gAgent.getPosGlobalFromAgent(chatter_av->mHeadp->getWorldPosition());
+ break;
+ case CAMERA_POSITION_OBJECT:
+ mCameraFocusOffsetTarget = view_dist;
+ break;
+ }
+ }
+ else
+ {
+ setFocusGlobal(chatter->getPositionGlobal(), object_id);
+ mCameraFocusOffsetTarget = getPosGlobalFromAgent(new_camera_pos) - chatter->getPositionGlobal();
+
+ switch(camera_pos)
+ {
+ case CAMERA_POSITION_SELF:
+ mCameraFocusOffsetTarget = getPosGlobalFromAgent(new_camera_pos) - chatter->getPositionGlobal();
+ break;
+ case CAMERA_POSITION_OBJECT:
+ mCameraFocusOffsetTarget = view_dist;
+ break;
+ }
+ }
+ setFocusOnAvatar(FALSE, TRUE);
+ }
+ else
+ {
+ delta_pos = chatter->getRenderPosition() - getPositionAgent();
+ delta_pos.normVec();
+
+ setControlFlags(AGENT_CONTROL_STOP);
+
+ changeCameraToThirdPerson();
+
+ LLVector3 new_camera_pos = mAvatarObject->mHeadp->getWorldPosition();
+ LLVector3 left = delta_pos % LLVector3::z_axis;
+ left.normVec();
+ LLVector3 up = left % delta_pos;
+ up.normVec();
+ new_camera_pos -= delta_pos * 0.4f;
+ new_camera_pos += left * 0.3f;
+ new_camera_pos += up * 0.2f;
+
+ setFocusGlobal(chatter->getPositionGlobal(), object_id);
+
+ switch(camera_pos)
+ {
+ case CAMERA_POSITION_SELF:
+ mCameraFocusOffsetTarget = getPosGlobalFromAgent(new_camera_pos) - chatter->getPositionGlobal();
+ break;
+ case CAMERA_POSITION_OBJECT:
+ F32 radius = chatter->getVObjRadius();
+ LLVector3d view_dist(radius, radius, 0.0f);
+ mCameraFocusOffsetTarget = view_dist;
+ break;
+ }
+
+ setFocusOnAvatar(FALSE, TRUE);
+ }
+ }
+}
+
+const F32 SIT_POINT_EXTENTS = 0.2f;
+
+void LLAgent::setStartPosition( U32 location_id )
+{
+ LLViewerObject *object;
+
+ if ( !(gAgentID == LLUUID::null) )
+ {
+ // we've got an ID for an agent viewerobject
+ object = gObjectList.findObject(gAgentID);
+ if (object)
+ {
+ // we've got the viewer object
+ // Sometimes the agent can be velocity interpolated off of
+ // this simulator. Clamp it to the region the agent is
+ // in, a little bit in on each side.
+ const F32 INSET = 0.5f; //meters
+ const F32 REGION_WIDTH = LLWorld::getInstance()->getRegionWidthInMeters();
+
+ LLVector3 agent_pos = getPositionAgent();
+ LLVector3 agent_look_at = mFrameAgent.getAtAxis();
+
+ if (mAvatarObject.notNull())
+ {
+ // the z height is at the agent's feet
+ agent_pos.mV[VZ] -= 0.5f * mAvatarObject->mBodySize.mV[VZ];
+ }
+
+ agent_pos.mV[VX] = llclamp( agent_pos.mV[VX], INSET, REGION_WIDTH - INSET );
+ agent_pos.mV[VY] = llclamp( agent_pos.mV[VY], INSET, REGION_WIDTH - INSET );
+
+ // Don't let them go below ground, or too high.
+ agent_pos.mV[VZ] = llclamp( agent_pos.mV[VZ],
+ mRegionp->getLandHeightRegion( agent_pos ),
+ LLWorld::getInstance()->getRegionMaxHeight() );
+ // Send the CapReq
+
+ LLSD body;
+
+ std::string url = gAgent.getRegion()->getCapability("HomeLocation");
+ std::ostringstream strBuffer;
+ if( url.empty() )
+ {
+ LLMessageSystem* msg = gMessageSystem;
+ msg->newMessageFast(_PREHASH_SetStartLocationRequest);
+ msg->nextBlockFast( _PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, getID());
+ msg->addUUIDFast(_PREHASH_SessionID, getSessionID());
+ msg->nextBlockFast( _PREHASH_StartLocationData);
+ // corrected by sim
+ msg->addStringFast(_PREHASH_SimName, "");
+ msg->addU32Fast(_PREHASH_LocationID, location_id);
+ msg->addVector3Fast(_PREHASH_LocationPos, agent_pos);
+ msg->addVector3Fast(_PREHASH_LocationLookAt,mFrameAgent.getAtAxis());
+
+ // Reliable only helps when setting home location. Last
+ // location is sent on quit, and we don't have time to ack
+ // the packets.
+ msg->sendReliable(mRegionp->getHost());
+
+ const U32 HOME_INDEX = 1;
+ if( HOME_INDEX == location_id )
+ {
+ setHomePosRegion( mRegionp->getHandle(), getPositionAgent() );
+ }
+ }
+ else
+ {
+ strBuffer << location_id;
+ body["HomeLocation"]["LocationId"] = strBuffer.str();
+
+ strBuffer.str("");
+ strBuffer << agent_pos.mV[VX];
+ body["HomeLocation"]["LocationPos"]["X"] = strBuffer.str();
+
+ strBuffer.str("");
+ strBuffer << agent_pos.mV[VY];
+ body["HomeLocation"]["LocationPos"]["Y"] = strBuffer.str();
+
+ strBuffer.str("");
+ strBuffer << agent_pos.mV[VZ];
+ body["HomeLocation"]["LocationPos"]["Z"] = strBuffer.str();
+
+ strBuffer.str("");
+ strBuffer << agent_look_at.mV[VX];
+ body["HomeLocation"]["LocationLookAt"]["X"] = strBuffer.str();
+
+ strBuffer.str("");
+ strBuffer << agent_look_at.mV[VY];
+ body["HomeLocation"]["LocationLookAt"]["Y"] = strBuffer.str();
+
+ strBuffer.str("");
+ strBuffer << agent_look_at.mV[VZ];
+ body["HomeLocation"]["LocationLookAt"]["Z"] = strBuffer.str();
+
+ LLHTTPClient::post( url, body, new LLHomeLocationResponder() );
+ }
+ }
+ else
+ {
+ llinfos << "setStartPosition - Can't find agent viewerobject id " << gAgentID << llendl;
+ }
+ }
+}
+
+void LLAgent::requestStopMotion( LLMotion* motion )
+{
+ // Notify all avatars that a motion has stopped.
+ // This is needed to clear the animation state bits
+ LLUUID anim_state = motion->getID();
+ onAnimStop(motion->getID());
+
+ // if motion is not looping, it could have stopped by running out of time
+ // so we need to tell the server this
+// llinfos << "Sending stop for motion " << motion->getName() << llendl;
+ sendAnimationRequest( anim_state, ANIM_REQUEST_STOP );
+}
+
+void LLAgent::onAnimStop(const LLUUID& id)
+{
+ // handle automatic state transitions (based on completion of animation playback)
+ if(id == ANIM_AGENT_STAND
+ //
+ // I really do not like doing this
+ || id == ANIM_AGENT_STAND_1
+ || id == ANIM_AGENT_STAND_2
+ || id == ANIM_AGENT_STAND_3
+ || id == ANIM_AGENT_STAND_4)
+ //
+ {
+ //
+ if(LLAO::isEnabled())
+ LLAO::mTimer->pause();//Timer only pauses if its not paused, check is inside function.
+ //
+ stopFidget();
+ }
+ else if (id == ANIM_AGENT_AWAY)
+ {
+ clearAFK();
+ }
+ else if (id == ANIM_AGENT_STANDUP)
+ {
+ // send stand up command
+ setControlFlags(AGENT_CONTROL_FINISH_ANIM);
+
+ // now trigger dusting self off animation
+ if (mAvatarObject.notNull() && !mAvatarObject->mBelowWater && rand() % 3 == 0)
+ sendAnimationRequest( ANIM_AGENT_BRUSH, ANIM_REQUEST_START );
+ }
+ else if (id == ANIM_AGENT_PRE_JUMP || id == ANIM_AGENT_LAND || id == ANIM_AGENT_MEDIUM_LAND)
+ {
+ setControlFlags(AGENT_CONTROL_FINISH_ANIM);
+ }
+}
+
+BOOL LLAgent::isGodlike() const
+{
+ return mAgentAccess.isGodlike();
+}
+
+U8 LLAgent::getGodLevel() const
+{
+ return mAgentAccess.getGodLevel();
+}
+
+bool LLAgent::wantsPGOnly() const
+{
+ return mAgentAccess.wantsPGOnly();
+}
+
+bool LLAgent::canAccessMature() const
+{
+ return mAgentAccess.canAccessMature();
+}
+
+bool LLAgent::canAccessAdult() const
+{
+ return mAgentAccess.canAccessAdult();
+}
+
+bool LLAgent::canAccessMaturityInRegion( U64 region_handle ) const
+{
+ LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle( region_handle );
+ if( regionp )
+ {
+ switch( regionp->getSimAccess() )
+ {
+ case SIM_ACCESS_MATURE:
+ if( !canAccessMature() )
+ return false;
+ break;
+ case SIM_ACCESS_ADULT:
+ if( !canAccessAdult() )
+ return false;
+ break;
+ default:
+ // Oh, go on and hear the silly noises.
+ break;
+ }
+ }
+
+ return true;
+}
+
+bool LLAgent::canAccessMaturityAtGlobal( LLVector3d pos_global ) const
+{
+ U64 region_handle = to_region_handle_global( pos_global.mdV[0], pos_global.mdV[1] );
+ return canAccessMaturityInRegion( region_handle );
+}
+
+bool LLAgent::prefersPG() const
+{
+ return mAgentAccess.prefersPG();
+}
+
+bool LLAgent::prefersMature() const
+{
+ return mAgentAccess.prefersMature();
+}
+
+bool LLAgent::prefersAdult() const
+{
+ return mAgentAccess.prefersAdult();
+}
+
+bool LLAgent::isTeen() const
+{
+ return mAgentAccess.isTeen();
+}
+
+bool LLAgent::isMature() const
+{
+ return mAgentAccess.isMature();
+}
+
+bool LLAgent::isAdult() const
+{
+ return mAgentAccess.isAdult();
+}
+
+void LLAgent::setTeen(bool teen)
+{
+ mAgentAccess.setTeen(teen);
+}
+
+//static
+int LLAgent::convertTextToMaturity(char text)
+{
+ return LLAgentAccess::convertTextToMaturity(text);
+}
+
+bool LLAgent::sendMaturityPreferenceToServer(int preferredMaturity)
+{
+ // Update agent access preference on the server
+ std::string url = getRegion()->getCapability("UpdateAgentInformation");
+ if (!url.empty())
+ {
+ // Set new access preference
+ LLSD access_prefs = LLSD::emptyMap();
+ if (preferredMaturity == SIM_ACCESS_PG)
+ {
+ access_prefs["max"] = "PG";
+ }
+ else if (preferredMaturity == SIM_ACCESS_MATURE)
+ {
+ access_prefs["max"] = "M";
+ }
+ if (preferredMaturity == SIM_ACCESS_ADULT)
+ {
+ access_prefs["max"] = "A";
+ }
+
+ LLSD body = LLSD::emptyMap();
+ body["access_prefs"] = access_prefs;
+ llinfos << "Sending access prefs update to " << (access_prefs["max"].asString()) << " via capability to: "
+ << url << llendl;
+ LLHTTPClient::post(url, body, new LLHTTPClient::Responder()); // Ignore response
+ return true;
+ }
+ return false;
+}
+
+BOOL LLAgent::getAdminOverride() const
+{
+ return mAgentAccess.getAdminOverride();
+}
+
+void LLAgent::setMaturity(char text)
+{
+ mAgentAccess.setMaturity(text);
+}
+
+void LLAgent::setAdminOverride(BOOL b)
+{
+ mAgentAccess.setAdminOverride(b);
+}
+
+void LLAgent::setGodLevel(U8 god_level)
+{
+ mAgentAccess.setGodLevel(god_level);
+}
+
+void LLAgent::setAOTransition()
+{
+ mAgentAccess.setTransition();
+}
+
+const LLAgentAccess& LLAgent::getAgentAccess()
+{
+ return mAgentAccess;
+}
+
+
+void LLAgent::buildFullname(std::string& name) const
+{
+ if (mAvatarObject.notNull())
+ {
+ name = mAvatarObject->getFullname();
+ }
+}
+
+void LLAgent::buildFullnameAndTitle(std::string& name) const
+{
+ if (isGroupMember())
+ {
+ name = mGroupTitle;
+ name += ' ';
+ }
+ else
+ {
+ name.erase(0, name.length());
+ }
+
+ if (mAvatarObject.notNull())
+ {
+ name += mAvatarObject->getFullname();
+ }
+}
+
+BOOL LLAgent::isInGroup(const LLUUID& group_id) const
+{
+ if (isGodlike())
+ return true;
+
+ S32 count = mGroups.count();
+ for(S32 i = 0; i < count; ++i)
+ {
+ if(mGroups.get(i).mID == group_id)
+ {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+// This implementation should mirror LLAgentInfo::hasPowerInGroup
+BOOL LLAgent::hasPowerInGroup(const LLUUID& group_id, U64 power) const
+{
+ if (isGodlike())
+ return true;
+
+ // GP_NO_POWERS can also mean no power is enough to grant an ability.
+ if (GP_NO_POWERS == power) return FALSE;
+
+ S32 count = mGroups.count();
+ for(S32 i = 0; i < count; ++i)
+ {
+ if(mGroups.get(i).mID == group_id)
+ {
+ return (BOOL)((mGroups.get(i).mPowers & power) > 0);
+ }
+ }
+ return FALSE;
+}
+
+BOOL LLAgent::hasPowerInActiveGroup(U64 power) const
+{
+ return (mGroupID.notNull() && (hasPowerInGroup(mGroupID, power)));
+}
+
+U64 LLAgent::getPowerInGroup(const LLUUID& group_id) const
+{
+ if (isGodlike())
+ return GP_ALL_POWERS;
+
+ S32 count = mGroups.count();
+ for(S32 i = 0; i < count; ++i)
+ {
+ if(mGroups.get(i).mID == group_id)
+ {
+ return (mGroups.get(i).mPowers);
+ }
+ }
+
+ return GP_NO_POWERS;
+}
+
+BOOL LLAgent::getGroupData(const LLUUID& group_id, LLGroupData& data) const
+{
+ S32 count = mGroups.count();
+ for(S32 i = 0; i < count; ++i)
+ {
+ if(mGroups.get(i).mID == group_id)
+ {
+ data = mGroups.get(i);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+S32 LLAgent::getGroupContribution(const LLUUID& group_id) const
+{
+ S32 count = mGroups.count();
+ for(S32 i = 0; i < count; ++i)
+ {
+ if(mGroups.get(i).mID == group_id)
+ {
+ S32 contribution = mGroups.get(i).mContribution;
+ return contribution;
+ }
+ }
+ return 0;
+}
+
+BOOL LLAgent::setGroupContribution(const LLUUID& group_id, S32 contribution)
+{
+ S32 count = mGroups.count();
+ for(S32 i = 0; i < count; ++i)
+ {
+ if(mGroups.get(i).mID == group_id)
+ {
+ mGroups.get(i).mContribution = contribution;
+ LLMessageSystem* msg = gMessageSystem;
+ msg->newMessage("SetGroupContribution");
+ msg->nextBlock("AgentData");
+ msg->addUUID("AgentID", gAgentID);
+ msg->addUUID("SessionID", gAgentSessionID);
+ msg->nextBlock("Data");
+ msg->addUUID("GroupID", group_id);
+ msg->addS32("Contribution", contribution);
+ sendReliableMessage();
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+BOOL LLAgent::setUserGroupFlags(const LLUUID& group_id, BOOL accept_notices, BOOL list_in_profile)
+{
+ S32 count = mGroups.count();
+ for(S32 i = 0; i < count; ++i)
+ {
+ if(mGroups.get(i).mID == group_id)
+ {
+ mGroups.get(i).mAcceptNotices = accept_notices;
+ mGroups.get(i).mListInProfile = list_in_profile;
+ LLMessageSystem* msg = gMessageSystem;
+ msg->newMessage("SetGroupAcceptNotices");
+ msg->nextBlock("AgentData");
+ msg->addUUID("AgentID", gAgentID);
+ msg->addUUID("SessionID", gAgentSessionID);
+ msg->nextBlock("Data");
+ msg->addUUID("GroupID", group_id);
+ msg->addBOOL("AcceptNotices", accept_notices);
+ msg->nextBlock("NewData");
+ msg->addBOOL("ListInProfile", list_in_profile);
+ sendReliableMessage();
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+// utility to build a location string
+void LLAgent::buildLocationString(std::string& str)
+{
+ const LLVector3& agent_pos_region = getPositionAgent();
+ S32 pos_x = S32(agent_pos_region.mV[VX]);
+ S32 pos_y = S32(agent_pos_region.mV[VY]);
+ S32 pos_z = S32(agent_pos_region.mV[VZ]);
+
+ // Round the numbers based on the velocity
+ LLVector3 agent_velocity = getVelocity();
+ F32 velocity_mag_sq = agent_velocity.magVecSquared();
+
+ const F32 FLY_CUTOFF = 6.f; // meters/sec
+ const F32 FLY_CUTOFF_SQ = FLY_CUTOFF * FLY_CUTOFF;
+ const F32 WALK_CUTOFF = 1.5f; // meters/sec
+ const F32 WALK_CUTOFF_SQ = WALK_CUTOFF * WALK_CUTOFF;
+
+ if (velocity_mag_sq > FLY_CUTOFF_SQ)
+ {
+ pos_x -= pos_x % 4;
+ pos_y -= pos_y % 4;
+ }
+ else if (velocity_mag_sq > WALK_CUTOFF_SQ)
+ {
+ pos_x -= pos_x % 2;
+ pos_y -= pos_y % 2;
+ }
+
+ // create a defult name and description for the landmark
+ std::string buffer;
+ if( LLViewerParcelMgr::getInstance()->getAgentParcelName().empty() )
+ {
+ // the parcel doesn't have a name
+ buffer = llformat("%.32s (%d, %d, %d)",
+ getRegion()->getName().c_str(),
+ pos_x, pos_y, pos_z);
+ }
+ else
+ {
+ // the parcel has a name, so include it in the landmark name
+ buffer = llformat("%.32s, %.32s (%d, %d, %d)",
+ LLViewerParcelMgr::getInstance()->getAgentParcelName().c_str(),
+ getRegion()->getName().c_str(),
+ pos_x, pos_y, pos_z);
+ }
+ str = buffer;
+}
+
+LLQuaternion LLAgent::getHeadRotation()
+{
+ if (mAvatarObject.isNull() || !mAvatarObject->mPelvisp || !mAvatarObject->mHeadp)
+ {
+ return LLQuaternion::DEFAULT;
+ }
+
+ if (!gAgent.cameraMouselook())
+ {
+ return mAvatarObject->getRotation();
+ }
+
+ // We must be in mouselook
+ LLVector3 look_dir( LLViewerCamera::getInstance()->getAtAxis() );
+ LLVector3 up = look_dir % mFrameAgent.getLeftAxis();
+ LLVector3 left = up % look_dir;
+
+ LLQuaternion rot(look_dir, left, up);
+ if (mAvatarObject->getParent())
+ {
+ rot = rot * ~mAvatarObject->getParent()->getRotation();
+ }
+
+ return rot;
+}
+
+void LLAgent::sendAnimationRequests(LLDynamicArray &anim_ids, EAnimRequest request)
+{
+ if (gAgentID.isNull())
+ {
+ return;
+ }
+
+ S32 num_valid_anims = 0;
+
+ LLMessageSystem* msg = gMessageSystem;
+ msg->newMessageFast(_PREHASH_AgentAnimation);
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, getID());
+ msg->addUUIDFast(_PREHASH_SessionID, getSessionID());
+
+ for (S32 i = 0; i < anim_ids.count(); i++)
+ {
+ if (anim_ids[i].isNull())
+ {
+ continue;
+ }
+ msg->nextBlockFast(_PREHASH_AnimationList);
+ msg->addUUIDFast(_PREHASH_AnimID, (anim_ids[i]) );
+ msg->addBOOLFast(_PREHASH_StartAnim, (request == ANIM_REQUEST_START) ? TRUE : FALSE);
+ num_valid_anims++;
+ }
+
+ msg->nextBlockFast(_PREHASH_PhysicalAvatarEventList);
+ msg->addBinaryDataFast(_PREHASH_TypeData, NULL, 0);
+ if (num_valid_anims)
+ {
+ sendReliableMessage();
+ }
+}
+
+void LLAgent::sendAnimationRequest(const LLUUID &anim_id, EAnimRequest request)
+{
+ if (gAgentID.isNull() || anim_id.isNull() || !mRegionp)
+ {
+ return;
+ }
+
+ LLMessageSystem* msg = gMessageSystem;
+ msg->newMessageFast(_PREHASH_AgentAnimation);
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, getID());
+ msg->addUUIDFast(_PREHASH_SessionID, getSessionID());
+
+ msg->nextBlockFast(_PREHASH_AnimationList);
+ msg->addUUIDFast(_PREHASH_AnimID, (anim_id) );
+ msg->addBOOLFast(_PREHASH_StartAnim, (request == ANIM_REQUEST_START) ? TRUE : FALSE);
+
+ msg->nextBlockFast(_PREHASH_PhysicalAvatarEventList);
+ msg->addBinaryDataFast(_PREHASH_TypeData, NULL, 0);
+ sendReliableMessage();
+}
+
+void LLAgent::sendWalkRun(bool running)
+{
+ LLMessageSystem* msgsys = gMessageSystem;
+ if (msgsys)
+ {
+ msgsys->newMessageFast(_PREHASH_SetAlwaysRun);
+ msgsys->nextBlockFast(_PREHASH_AgentData);
+ msgsys->addUUIDFast(_PREHASH_AgentID, getID());
+ msgsys->addUUIDFast(_PREHASH_SessionID, getSessionID());
+ msgsys->addBOOLFast(_PREHASH_AlwaysRun, BOOL(running) );
+ sendReliableMessage();
+ }
+}
+
+void LLAgent::friendsChanged()
+{
+ LLCollectProxyBuddies collector;
+ LLAvatarTracker::instance().applyFunctor(collector);
+ mProxyForAgents = collector.mProxy;
+}
+
+BOOL LLAgent::isGrantedProxy(const LLPermissions& perm)
+{
+ return (mProxyForAgents.count(perm.getOwner()) > 0);
+}
+
+BOOL LLAgent::allowOperation(PermissionBit op,
+ const LLPermissions& perm,
+ U64 group_proxy_power,
+ U8 god_minimum)
+{
+ // Check god level.
+ if (getGodLevel() >= god_minimum) return TRUE;
+
+ if (!perm.isOwned()) return FALSE;
+
+ // A group member with group_proxy_power can act as owner.
+ BOOL is_group_owned;
+ LLUUID owner_id;
+ perm.getOwnership(owner_id, is_group_owned);
+ LLUUID group_id(perm.getGroup());
+ LLUUID agent_proxy(getID());
+
+ if (is_group_owned)
+ {
+ if (hasPowerInGroup(group_id, group_proxy_power))
+ {
+ // Let the member assume the group's id for permission requests.
+ agent_proxy = owner_id;
+ }
+ }
+ else
+ {
+ // Check for granted mod permissions.
+ if ((PERM_OWNER != op) && isGrantedProxy(perm))
+ {
+ agent_proxy = owner_id;
+ }
+ }
+
+ // This is the group id to use for permission requests.
+ // Only group members may use this field.
+ LLUUID group_proxy = LLUUID::null;
+ if (group_id.notNull() && isInGroup(group_id))
+ {
+ group_proxy = group_id;
+ }
+
+ // We now have max ownership information.
+ if (PERM_OWNER == op)
+ {
+ // This this was just a check for ownership, we can now return the answer.
+ return (agent_proxy == owner_id);
+ }
+
+ return perm.allowOperationBy(op, agent_proxy, group_proxy);
+}
+
+
+void LLAgent::getName(std::string& name)
+{
+ name.clear();
+
+ if (mAvatarObject.notNull())
+ {
+ LLNameValue *first_nv = mAvatarObject->getNVPair("FirstName");
+ LLNameValue *last_nv = mAvatarObject->getNVPair("LastName");
+ if (first_nv && last_nv)
+ {
+ name = first_nv->printData() + " " + last_nv->printData();
+ }
+ else
+ {
+ llwarns << "Agent is missing FirstName and/or LastName nv pair." << llendl;
+ }
+ }
+ else
+ {
+ name = gSavedSettings.getString("FirstName") + " " + gSavedSettings.getString("LastName");
+ }
+}
+
+const LLColor4 &LLAgent::getEffectColor()
+{
+ return mEffectColor;
+}
+
+void LLAgent::setEffectColor(const LLColor4 &color)
+{
+ mEffectColor = color;
+}
+
+void LLAgent::initOriginGlobal(const LLVector3d &origin_global)
+{
+ mAgentOriginGlobal = origin_global;
+}
+
+void update_group_floaters(const LLUUID& group_id)
+{
+ LLFloaterGroupInfo::refreshGroup(group_id);
+
+ // update avatar info
+ LLFloaterAvatarInfo* fa = LLFloaterAvatarInfo::getInstance(gAgent.getID());
+ if(fa)
+ {
+ fa->resetGroupList();
+ }
+
+ if (gIMMgr)
+ {
+ // update the talk view
+ gIMMgr->refresh();
+ }
+
+ gAgent.fireEvent(new LLEvent(&gAgent, "new group"), "");
+}
+
+// static
+void LLAgent::processAgentDropGroup(LLMessageSystem *msg, void **)
+{
+ LLUUID agent_id;
+ msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id );
+
+ if (agent_id != gAgentID)
+ {
+ llwarns << "processAgentDropGroup for agent other than me" << llendl;
+ return;
+ }
+
+ LLUUID group_id;
+ msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_GroupID, group_id );
+
+ // Remove the group if it already exists remove it and add the new data to pick up changes.
+ LLGroupData gd;
+ gd.mID = group_id;
+ S32 index = gAgent.mGroups.find(gd);
+ if (index != -1)
+ {
+ gAgent.mGroups.remove(index);
+ if (gAgent.getGroupID() == group_id)
+ {
+ gAgent.mGroupID.setNull();
+ gAgent.mGroupPowers = 0;
+ gAgent.mGroupName.clear();
+ gAgent.mGroupTitle.clear();
+ }
+
+ // refresh all group information
+ gAgent.sendAgentDataUpdateRequest();
+
+ LLGroupMgr::getInstance()->clearGroupData(group_id);
+ // close the floater for this group, if any.
+ LLFloaterGroupInfo::closeGroup(group_id);
+ // refresh the group panel of the search window, if necessary.
+ LLFloaterDirectory::refreshGroup(group_id);
+ }
+ else
+ {
+ llwarns << "processAgentDropGroup, agent is not part of group " << group_id << llendl;
+ }
+}
+
+class LLAgentDropGroupViewerNode : public LLHTTPNode
+{
+ virtual void post(
+ LLHTTPNode::ResponsePtr response,
+ const LLSD& context,
+ const LLSD& input) const
+ {
+
+ if (
+ !input.isMap() ||
+ !input.has("body") )
+ {
+ //what to do with badly formed message?
+ response->status(400);
+ response->result(LLSD("Invalid message parameters"));
+ }
+
+ LLSD body = input["body"];
+ if ( body.has("body") )
+ {
+ //stupid message system doubles up the "body"s
+ body = body["body"];
+ }
+
+ if (
+ body.has("AgentData") &&
+ body["AgentData"].isArray() &&
+ body["AgentData"][0].isMap() )
+ {
+ llinfos << "VALID DROP GROUP" << llendl;
+
+ //there is only one set of data in the AgentData block
+ LLSD agent_data = body["AgentData"][0];
+ LLUUID agent_id;
+ LLUUID group_id;
+
+ agent_id = agent_data["AgentID"].asUUID();
+ group_id = agent_data["GroupID"].asUUID();
+
+ if (agent_id != gAgentID)
+ {
+ llwarns
+ << "AgentDropGroup for agent other than me" << llendl;
+
+ response->notFound();
+ return;
+ }
+
+ // Remove the group if it already exists remove it
+ // and add the new data to pick up changes.
+ LLGroupData gd;
+ gd.mID = group_id;
+ S32 index = gAgent.mGroups.find(gd);
+ if (index != -1)
+ {
+ gAgent.mGroups.remove(index);
+ if (gAgent.getGroupID() == group_id)
+ {
+ gAgent.mGroupID.setNull();
+ gAgent.mGroupPowers = 0;
+ gAgent.mGroupName.clear();
+ gAgent.mGroupTitle.clear();
+ }
+
+ // refresh all group information
+ gAgent.sendAgentDataUpdateRequest();
+
+ LLGroupMgr::getInstance()->clearGroupData(group_id);
+ // close the floater for this group, if any.
+ LLFloaterGroupInfo::closeGroup(group_id);
+ // refresh the group panel of the search window,
+ //if necessary.
+ LLFloaterDirectory::refreshGroup(group_id);
+ }
+ else
+ {
+ llwarns
+ << "AgentDropGroup, agent is not part of group "
+ << group_id << llendl;
+ }
+
+ response->result(LLSD());
+ }
+ else
+ {
+ //what to do with badly formed message?
+ response->status(400);
+ response->result(LLSD("Invalid message parameters"));
+ }
+ }
+};
+
+LLHTTPRegistration
+ gHTTPRegistrationAgentDropGroupViewerNode(
+ "/message/AgentDropGroup");
+
+// static
+void LLAgent::processAgentGroupDataUpdate(LLMessageSystem *msg, void **)
+{
+ LLUUID agent_id;
+
+ msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id );
+
+ if (agent_id != gAgentID)
+ {
+ llwarns << "processAgentGroupDataUpdate for agent other than me" << llendl;
+ return;
+ }
+
+ S32 count = msg->getNumberOfBlocksFast(_PREHASH_GroupData);
+ LLGroupData group;
+ S32 index = -1;
+ bool need_floater_update = false;
+ for(S32 i = 0; i < count; ++i)
+ {
+ msg->getUUIDFast(_PREHASH_GroupData, _PREHASH_GroupID, group.mID, i);
+ msg->getUUIDFast(_PREHASH_GroupData, _PREHASH_GroupInsigniaID, group.mInsigniaID, i);
+ msg->getU64(_PREHASH_GroupData, "GroupPowers", group.mPowers, i);
+ msg->getBOOL(_PREHASH_GroupData, "AcceptNotices", group.mAcceptNotices, i);
+ msg->getS32(_PREHASH_GroupData, "Contribution", group.mContribution, i);
+ msg->getStringFast(_PREHASH_GroupData, _PREHASH_GroupName, group.mName, i);
+
+ if(group.mID.notNull())
+ {
+ need_floater_update = true;
+ // Remove the group if it already exists remove it and add the new data to pick up changes.
+ index = gAgent.mGroups.find(group);
+ if (index != -1)
+ {
+ gAgent.mGroups.remove(index);
+ }
+ gAgent.mGroups.put(group);
+ }
+ if (need_floater_update)
+ {
+ update_group_floaters(group.mID);
+ }
+ }
+
+}
+
+class LLAgentGroupDataUpdateViewerNode : public LLHTTPNode
+{
+ virtual void post(
+ LLHTTPNode::ResponsePtr response,
+ const LLSD& context,
+ const LLSD& input) const
+ {
+ LLSD body = input["body"];
+ if(body.has("body"))
+ body = body["body"];
+ LLUUID agent_id = body["AgentData"][0]["AgentID"].asUUID();
+
+ if (agent_id != gAgentID)
+ {
+ llwarns << "processAgentGroupDataUpdate for agent other than me" << llendl;
+ return;
+ }
+
+ LLSD group_data = body["GroupData"];
+
+ LLSD::array_iterator iter_group =
+ group_data.beginArray();
+ LLSD::array_iterator end_group =
+ group_data.endArray();
+ int group_index = 0;
+ for(; iter_group != end_group; ++iter_group)
+ {
+
+ LLGroupData group;
+ S32 index = -1;
+ bool need_floater_update = false;
+
+ group.mID = (*iter_group)["GroupID"].asUUID();
+ group.mPowers = ll_U64_from_sd((*iter_group)["GroupPowers"]);
+ group.mAcceptNotices = (*iter_group)["AcceptNotices"].asBoolean();
+ group.mListInProfile = body["NewGroupData"][group_index]["ListInProfile"].asBoolean();
+ group.mInsigniaID = (*iter_group)["GroupInsigniaID"].asUUID();
+ group.mName = (*iter_group)["GroupName"].asString();
+ group.mContribution = (*iter_group)["Contribution"].asInteger();
+
+ group_index++;
+
+ if(group.mID.notNull())
+ {
+ need_floater_update = true;
+ // Remove the group if it already exists remove it and add the new data to pick up changes.
+ index = gAgent.mGroups.find(group);
+ if (index != -1)
+ {
+ gAgent.mGroups.remove(index);
+ }
+ gAgent.mGroups.put(group);
+ }
+ if (need_floater_update)
+ {
+ update_group_floaters(group.mID);
+ }
+ }
+ }
+};
+
+LLHTTPRegistration
+ gHTTPRegistrationAgentGroupDataUpdateViewerNode ("/message/AgentGroupDataUpdate");
+
+// static
+void LLAgent::processAgentDataUpdate(LLMessageSystem *msg, void **)
+{
+ LLUUID agent_id;
+
+ msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id );
+
+ if (agent_id != gAgentID)
+ {
+ llwarns << "processAgentDataUpdate for agent other than me" << llendl;
+ return;
+ }
+
+ msg->getStringFast(_PREHASH_AgentData, _PREHASH_GroupTitle, gAgent.mGroupTitle);
+ LLUUID active_id;
+ msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_ActiveGroupID, active_id);
+
+
+ if(active_id.notNull())
+ {
+ gAgent.mGroupID = active_id;
+ msg->getU64(_PREHASH_AgentData, "GroupPowers", gAgent.mGroupPowers);
+ msg->getString(_PREHASH_AgentData, _PREHASH_GroupName, gAgent.mGroupName);
+ }
+ else
+ {
+ gAgent.mGroupID.setNull();
+ gAgent.mGroupPowers = 0;
+ gAgent.mGroupName.clear();
+ }
+
+ update_group_floaters(active_id);
+}
+
+// static
+void LLAgent::processScriptControlChange(LLMessageSystem *msg, void **)
+{
+ S32 block_count = msg->getNumberOfBlocks("Data");
+ for (S32 block_index = 0; block_index < block_count; block_index++)
+ {
+ BOOL take_controls;
+ U32 controls;
+ BOOL passon;
+ U32 i;
+ msg->getBOOL("Data", "TakeControls", take_controls, block_index);
+ if (take_controls)
+ {
+ // take controls
+ msg->getU32("Data", "Controls", controls, block_index );
+ msg->getBOOL("Data", "PassToAgent", passon, block_index );
+ U32 total_count = 0;
+ for (i = 0; i < TOTAL_CONTROLS; i++)
+ {
+ if (controls & ( 1 << i))
+ {
+ if (passon)
+ {
+ gAgent.mControlsTakenPassedOnCount[i]++;
+ }
+ else
+ {
+ gAgent.mControlsTakenCount[i]++;
+ }
+ total_count++;
+ }
+ }
+
+ // Any control taken? If so, might be first time.
+ if (total_count > 0)
+ {
+ LLFirstUse::useOverrideKeys();
+ }
+ }
+ else
+ {
+ // release controls
+ msg->getU32("Data", "Controls", controls, block_index );
+ msg->getBOOL("Data", "PassToAgent", passon, block_index );
+ for (i = 0; i < TOTAL_CONTROLS; i++)
+ {
+ if (controls & ( 1 << i))
+ {
+ if (passon)
+ {
+ gAgent.mControlsTakenPassedOnCount[i]--;
+ if (gAgent.mControlsTakenPassedOnCount[i] < 0)
+ {
+ gAgent.mControlsTakenPassedOnCount[i] = 0;
+ }
+ }
+ else
+ {
+ gAgent.mControlsTakenCount[i]--;
+ if (gAgent.mControlsTakenCount[i] < 0)
+ {
+ gAgent.mControlsTakenCount[i] = 0;
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+/*
+// static
+void LLAgent::processControlTake(LLMessageSystem *msg, void **)
+{
+ U32 controls;
+ msg->getU32("Data", "Controls", controls );
+ U32 passon;
+ msg->getBOOL("Data", "PassToAgent", passon );
+
+ S32 i;
+ S32 total_count = 0;
+ for (i = 0; i < TOTAL_CONTROLS; i++)
+ {
+ if (controls & ( 1 << i))
+ {
+ if (passon)
+ {
+ gAgent.mControlsTakenPassedOnCount[i]++;
+ }
+ else
+ {
+ gAgent.mControlsTakenCount[i]++;
+ }
+ total_count++;
+ }
+ }
+
+ // Any control taken? If so, might be first time.
+ if (total_count > 0)
+ {
+ LLFirstUse::useOverrideKeys();
+ }
+}
+
+// static
+void LLAgent::processControlRelease(LLMessageSystem *msg, void **)
+{
+ U32 controls;
+ msg->getU32("Data", "Controls", controls );
+ U32 passon;
+ msg->getBOOL("Data", "PassToAgent", passon );
+
+ S32 i;
+ for (i = 0; i < TOTAL_CONTROLS; i++)
+ {
+ if (controls & ( 1 << i))
+ {
+ if (passon)
+ {
+ gAgent.mControlsTakenPassedOnCount[i]--;
+ if (gAgent.mControlsTakenPassedOnCount[i] < 0)
+ {
+ gAgent.mControlsTakenPassedOnCount[i] = 0;
+ }
+ }
+ else
+ {
+ gAgent.mControlsTakenCount[i]--;
+ if (gAgent.mControlsTakenCount[i] < 0)
+ {
+ gAgent.mControlsTakenCount[i] = 0;
+ }
+ }
+ }
+ }
+}
+*/
+
+//static
+void LLAgent::processAgentCachedTextureResponse(LLMessageSystem *mesgsys, void **user_data)
+{
+ gAgent.mNumPendingQueries--;
+
+ LLVOAvatar* avatarp = gAgent.getAvatarObject();
+ if (!avatarp || avatarp->isDead())
+ {
+ llwarns << "No avatar for user in cached texture update!" << llendl;
+ return;
+ }
+
+ if (gAgent.cameraCustomizeAvatar())
+ {
+ // ignore baked textures when in customize mode
+ return;
+ }
+
+ S32 query_id;
+ mesgsys->getS32Fast(_PREHASH_AgentData, _PREHASH_SerialNum, query_id);
+
+ S32 num_texture_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_WearableData);
+
+
+ S32 num_results = 0;
+ for (S32 texture_block = 0; texture_block < num_texture_blocks; texture_block++)
+ {
+ LLUUID texture_id;
+ U8 texture_index;
+
+ mesgsys->getUUIDFast(_PREHASH_WearableData, _PREHASH_TextureID, texture_id, texture_block);
+ mesgsys->getU8Fast(_PREHASH_WearableData, _PREHASH_TextureIndex, texture_index, texture_block);
+
+ if (texture_id.notNull()
+ && (S32)texture_index < BAKED_NUM_INDICES
+ && gAgent.mActiveCacheQueries[ texture_index ] == query_id)
+ {
+ //llinfos << "Received cached texture " << (U32)texture_index << ": " << texture_id << llendl;
+ avatarp->setCachedBakedTexture(getTextureIndex((EBakedTextureIndex)texture_index), texture_id);
+ //avatarp->setTETexture( LLVOAvatar::sBakedTextureIndices[texture_index], texture_id );
+ gAgent.mActiveCacheQueries[ texture_index ] = 0;
+ num_results++;
+ }
+ }
+
+ llinfos << "Received cached texture response for " << num_results << " textures." << llendl;
+
+ avatarp->updateMeshTextures();
+
+ if (gAgent.mNumPendingQueries == 0)
+ {
+ // RN: not sure why composites are disabled at this point
+ avatarp->setCompositeUpdatesEnabled(TRUE);
+ gAgent.sendAgentSetAppearance();
+ }
+}
+
+BOOL LLAgent::anyControlGrabbed() const
+{
+ U32 i;
+ for (i = 0; i < TOTAL_CONTROLS; i++)
+ {
+ if (gAgent.mControlsTakenCount[i] > 0)
+ return TRUE;
+ if (gAgent.mControlsTakenPassedOnCount[i] > 0)
+ return TRUE;
+ }
+ return FALSE;
+}
+
+BOOL LLAgent::isControlGrabbed(S32 control_index) const
+{
+ return mControlsTakenCount[control_index] > 0;
+}
+
+void LLAgent::forceReleaseControls()
+{
+ gMessageSystem->newMessage("ForceScriptControlRelease");
+ gMessageSystem->nextBlock("AgentData");
+ gMessageSystem->addUUID("AgentID", getID());
+ gMessageSystem->addUUID("SessionID", getSessionID());
+ sendReliableMessage();
+}
+
+void LLAgent::setHomePosRegion( const U64& region_handle, const LLVector3& pos_region)
+{
+ mHaveHomePosition = TRUE;
+ mHomeRegionHandle = region_handle;
+ mHomePosRegion = pos_region;
+}
+
+BOOL LLAgent::getHomePosGlobal( LLVector3d* pos_global )
+{
+ if(!mHaveHomePosition)
+ {
+ return FALSE;
+ }
+ F32 x = 0;
+ F32 y = 0;
+ from_region_handle( mHomeRegionHandle, &x, &y);
+ pos_global->setVec( x + mHomePosRegion.mV[VX], y + mHomePosRegion.mV[VY], mHomePosRegion.mV[VZ] );
+ return TRUE;
+}
+
+void LLAgent::clearVisualParams(void *data)
+{
+ LLVOAvatar* avatarp = gAgent.getAvatarObject();
+ if (avatarp)
+ {
+ avatarp->clearVisualParamWeights();
+ avatarp->updateVisualParams();
+ }
+}
+
+//---------------------------------------------------------------------------
+// Teleport
+//---------------------------------------------------------------------------
+
+// teleportCore() - stuff to do on any teleport
+// protected
+bool LLAgent::teleportCore(bool is_local)
+{
+ if(TELEPORT_NONE != mTeleportState)
+ {
+ llwarns << "Attempt to teleport when already teleporting." << llendl;
+ //
+ //return false;
+ teleportCancel();
+ //
+ }
+
+#if 0
+ // This should not exist. It has been added, removed, added, and now removed again.
+ // This change needs to come from the simulator. Otherwise, the agent ends up out of
+ // sync with other viewers. Discuss in DEV-14145/VWR-6744 before reenabling.
+
+ // Stop all animation before actual teleporting
+ LLVOAvatar* avatarp = gAgent.getAvatarObject();
+ if (avatarp)
+ {
+ for ( LLVOAvatar::AnimIterator anim_it= avatarp->mPlayingAnimations.begin();
+ anim_it != avatarp->mPlayingAnimations.end();
+ ++anim_it)
+ {
+ avatarp->stopMotion(anim_it->first);
+ }
+ avatarp->processAnimationStateChanges();
+ }
+#endif
+
+ // Don't call LLFirstUse::useTeleport because we don't know
+ // yet if the teleport will succeed. Look in
+ // process_teleport_location_reply
+
+ // close the map and find panels so we can see our destination
+ LLFloaterWorldMap::hide(NULL);
+ LLFloaterDirectory::hide(NULL);
+
+ // hide land floater too - it'll be out of date
+ LLFloaterLand::hideInstance();
+
+ LLViewerParcelMgr::getInstance()->deselectLand();
+ LLViewerMediaFocus::getInstance()->setFocusFace(false, NULL, 0, NULL);
+
+ // Close all pie menus, deselect land, etc.
+ // Don't change the camera until we know teleport succeeded. JC
+ //
+ if(gAgent.getFocusOnAvatar())
+ //
+ resetView(FALSE);
+
+ // local logic
+ LLViewerStats::getInstance()->incStat(LLViewerStats::ST_TELEPORT_COUNT);
+ if (is_local)
+ {
+ gAgent.setTeleportState( LLAgent::TELEPORT_LOCAL );
+ }
+ else
+ {
+ gTeleportDisplay = TRUE;
+ gAgent.setTeleportState( LLAgent::TELEPORT_START );
+
+ //release geometry from old location
+ gPipeline.resetVertexBuffers();
+
+ if (gSavedSettings.getBOOL("SpeedRez"))
+ {
+ F32 draw_distance = gSavedSettings.getF32("RenderFarClip");
+ if (gSavedDrawDistance < draw_distance)
+ {
+ gSavedDrawDistance = draw_distance;
+ }
+ gSavedSettings.setF32("SavedRenderFarClip", gSavedDrawDistance);
+ gSavedSettings.setF32("RenderFarClip", 32.0f);
+ }
+ if(gSavedSettings.getBOOL("OptionPlayTpSound"))
+ make_ui_sound("UISndTeleportOut");
+ }
+
+ // MBW -- Let the voice client know a teleport has begun so it can leave the existing channel.
+ // This was breaking the case of teleporting within a single sim. Backing it out for now.
+// gVoiceClient->leaveChannel();
+
+ return true;
+}
+
+void LLAgent::teleportRequest(
+ const U64& region_handle,
+ const LLVector3& pos_local,
+ bool look_at_from_camera)
+{
+ LLViewerRegion* regionp = getRegion();
+ bool is_local = (region_handle == to_region_handle(getPositionGlobal()));
+ if(regionp && teleportCore(is_local))
+ {
+ llinfos << "TeleportLocationRequest: '" << region_handle << "':" << pos_local
+ << llendl;
+ LLMessageSystem* msg = gMessageSystem;
+ msg->newMessage("TeleportLocationRequest");
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, getID());
+ msg->addUUIDFast(_PREHASH_SessionID, getSessionID());
+ msg->nextBlockFast(_PREHASH_Info);
+ msg->addU64("RegionHandle", region_handle);
+ msg->addVector3("Position", pos_local);
+ //
+ //LLVector3 look_at(0,1,0);
+ LLVector3 look_at = LLViewerCamera::getInstance()->getAtAxis();
+ /*if (look_at_from_camera)
+ {
+ look_at = LLViewerCamera::getInstance()->getAtAxis();
+ }*/
+ //
+ msg->addVector3("LookAt", look_at);
+ sendReliableMessage();
+ }
+}
+
+// Landmark ID = LLUUID::null means teleport home
+void LLAgent::teleportViaLandmark(const LLUUID& landmark_asset_id)
+{
+ LLViewerRegion *regionp = getRegion();
+ if(regionp && teleportCore())
+ {
+ LLMessageSystem* msg = gMessageSystem;
+ msg->newMessageFast(_PREHASH_TeleportLandmarkRequest);
+ msg->nextBlockFast(_PREHASH_Info);
+ msg->addUUIDFast(_PREHASH_AgentID, getID());
+ msg->addUUIDFast(_PREHASH_SessionID, getSessionID());
+ msg->addUUIDFast(_PREHASH_LandmarkID, landmark_asset_id);
+ sendReliableMessage();
+ }
+}
+
+void LLAgent::teleportViaLure(const LLUUID& lure_id, BOOL godlike)
+{
+ LLViewerRegion* regionp = getRegion();
+ if(regionp && teleportCore())
+ {
+ U32 teleport_flags = 0x0;
+ if (godlike)
+ {
+ teleport_flags |= TELEPORT_FLAGS_VIA_GODLIKE_LURE;
+ teleport_flags |= TELEPORT_FLAGS_DISABLE_CANCEL;
+ }
+ else
+ {
+ teleport_flags |= TELEPORT_FLAGS_VIA_LURE;
+ }
+
+ // send the message
+ LLMessageSystem* msg = gMessageSystem;
+ msg->newMessageFast(_PREHASH_TeleportLureRequest);
+ msg->nextBlockFast(_PREHASH_Info);
+ msg->addUUIDFast(_PREHASH_AgentID, getID());
+ msg->addUUIDFast(_PREHASH_SessionID, getSessionID());
+ msg->addUUIDFast(_PREHASH_LureID, lure_id);
+ // teleport_flags is a legacy field, now derived sim-side:
+ msg->addU32("TeleportFlags", teleport_flags);
+ sendReliableMessage();
+ }
+}
+
+
+// James Cook, July 28, 2005
+void LLAgent::teleportCancel()
+{
+ LLViewerRegion* regionp = getRegion();
+ if(regionp)
+ {
+ // send the message
+ LLMessageSystem* msg = gMessageSystem;
+ msg->newMessage("TeleportCancel");
+ msg->nextBlockFast(_PREHASH_Info);
+ msg->addUUIDFast(_PREHASH_AgentID, getID());
+ msg->addUUIDFast(_PREHASH_SessionID, getSessionID());
+ sendReliableMessage();
+ }
+ gTeleportDisplay = FALSE;
+ gAgent.setTeleportState( LLAgent::TELEPORT_NONE );
+}
+
+
+void LLAgent::teleportViaLocation(const LLVector3d& pos_global)
+{
+ LLViewerRegion* regionp = getRegion();
+ U64 handle = to_region_handle(pos_global);
+ LLSimInfo* info = LLWorldMap::getInstance()->simInfoFromHandle(handle);
+ if(regionp && info)
+ {
+ LLVector3d region_origin = info->getGlobalOrigin();
+ LLVector3 pos_local(
+ (F32)(pos_global.mdV[VX] - region_origin.mdV[VX]),
+ (F32)(pos_global.mdV[VY] - region_origin.mdV[VY]),
+ (F32)(pos_global.mdV[VZ]));
+ teleportRequest(handle, pos_local);
+ }
+ else if(regionp &&
+ teleportCore(regionp->getHandle() == to_region_handle_global((F32)pos_global.mdV[VX], (F32)pos_global.mdV[VY])))
+ {
+ llwarns << "Using deprecated teleportlocationrequest." << llendl;
+ // send the message
+ LLMessageSystem* msg = gMessageSystem;
+ msg->newMessageFast(_PREHASH_TeleportLocationRequest);
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, getID());
+ msg->addUUIDFast(_PREHASH_SessionID, getSessionID());
+
+ msg->nextBlockFast(_PREHASH_Info);
+ F32 width = regionp->getWidth();
+ LLVector3 pos(fmod((F32)pos_global.mdV[VX], width),
+ fmod((F32)pos_global.mdV[VY], width),
+ (F32)pos_global.mdV[VZ]);
+ F32 region_x = (F32)(pos_global.mdV[VX]);
+ F32 region_y = (F32)(pos_global.mdV[VY]);
+ U64 region_handle = to_region_handle_global(region_x, region_y);
+ msg->addU64Fast(_PREHASH_RegionHandle, region_handle);
+ msg->addVector3Fast(_PREHASH_Position, pos);
+ pos.mV[VX] += 1;
+ //
+ LLVector3 lookat = LLViewerCamera::getInstance()->getAtAxis();
+ //msg->addVector3Fast(_PREHASH_LookAt, pos);
+ msg->addVector3Fast(_PREHASH_LookAt, lookat);
+ //
+ sendReliableMessage();
+ }
+}
+
+// Teleport to global position, but keep facing in the same direction
+void LLAgent::teleportViaLocationLookAt(const LLVector3d& pos_global)
+{
+ mbTeleportKeepsLookAt = true;
+ setFocusOnAvatar(FALSE, ANIMATE); // detach camera form avatar, so it keeps direction
+ U64 region_handle = to_region_handle(pos_global);
+ LLVector3 pos_local = (LLVector3)(pos_global - from_region_handle(region_handle));
+ teleportRequest(region_handle, pos_local, getTeleportKeepsLookAt());
+}
+
+void LLAgent::setTeleportState(ETeleportState state)
+{
+ mTeleportState = state;
+ if (mTeleportState > TELEPORT_NONE && gSavedSettings.getBOOL("FreezeTime"))
+ {
+ LLFloaterSnapshot::hide(0);
+ }
+ if (mTeleportState == TELEPORT_NONE)
+ {
+ mbTeleportKeepsLookAt = false;
+ }
+ // OGPX : Only compute a 'slurl' in non-OGP mode. In OGP, set it to regionuri in floaterteleport.
+ if ((mTeleportState == TELEPORT_MOVING)&& (!gSavedSettings.getBOOL("OpenGridProtocol")))
+ {
+ // We're outa here. Save "back" slurl.
+ mTeleportSourceSLURL = getSLURL();
+ }
+}
+
+void LLAgent::stopCurrentAnimations()
+{
+ // This function stops all current overriding animations on this
+ // avatar, propagating this change back to the server.
+
+ LLVOAvatar* avatarp = gAgent.getAvatarObject();
+ if (avatarp)
+ {
+ for ( LLVOAvatar::AnimIterator anim_it =
+ avatarp->mPlayingAnimations.begin();
+ anim_it != avatarp->mPlayingAnimations.end();
+ anim_it++)
+ {
+ if (anim_it->first ==
+ ANIM_AGENT_SIT_GROUND_CONSTRAINED)
+ {
+ // don't cancel a ground-sit anim, as viewers
+ // use this animation's status in
+ // determining whether we're sitting. ick.
+ }
+ else
+ {
+ // stop this animation locally
+ avatarp->stopMotion(anim_it->first, TRUE);
+ // ...and tell the server to tell everyone.
+ sendAnimationRequest(anim_it->first, ANIM_REQUEST_STOP);
+ }
+ }
+
+ // re-assert at least the default standing animation, because
+ // viewers get confused by avs with no associated anims.
+ sendAnimationRequest(ANIM_AGENT_STAND,
+ ANIM_REQUEST_START);
+ }
+}
+
+void LLAgent::fidget()
+{
+ if (!getAFK())
+ {
+ F32 curTime = mFidgetTimer.getElapsedTimeF32();
+ if (curTime > mNextFidgetTime)
+ {
+ // pick a random fidget anim here
+ S32 oldFidget = mCurrentFidget;
+
+ mCurrentFidget = ll_rand(NUM_AGENT_STAND_ANIMS);
+
+ if (mCurrentFidget != oldFidget)
+ {
+ //LLAgent::stopFidget();
+ //
+ // for the sack of smaller packets, make this cancel the last one only
+ if(oldFidget != 0)
+ sendAnimationRequest(AGENT_STAND_ANIMS[oldFidget],ANIM_REQUEST_STOP);
+ //
+
+ switch(mCurrentFidget)
+ {
+ case 0:
+ mCurrentFidget = 0;
+ break;
+ case 1:
+ sendAnimationRequest(ANIM_AGENT_STAND_1, ANIM_REQUEST_START);
+ mCurrentFidget = 1;
+ break;
+ case 2:
+ sendAnimationRequest(ANIM_AGENT_STAND_2, ANIM_REQUEST_START);
+ mCurrentFidget = 2;
+ break;
+ case 3:
+ sendAnimationRequest(ANIM_AGENT_STAND_3, ANIM_REQUEST_START);
+ mCurrentFidget = 3;
+ break;
+ case 4:
+ sendAnimationRequest(ANIM_AGENT_STAND_4, ANIM_REQUEST_START);
+ mCurrentFidget = 4;
+ break;
+ }
+ }
+
+ // calculate next fidget time
+ mNextFidgetTime = curTime + ll_frand(MAX_FIDGET_TIME - MIN_FIDGET_TIME) + MIN_FIDGET_TIME;
+ }
+ }
+}
+
+void LLAgent::stopFidget()
+{
+ LLDynamicArray anims;
+ anims.put(ANIM_AGENT_STAND_1);
+ anims.put(ANIM_AGENT_STAND_2);
+ anims.put(ANIM_AGENT_STAND_3);
+ anims.put(ANIM_AGENT_STAND_4);
+
+ gAgent.sendAnimationRequests(anims, ANIM_REQUEST_STOP);
+}
+
+
+void LLAgent::requestEnterGodMode()
+{
+ LLMessageSystem* msg = gMessageSystem;
+ msg->newMessageFast(_PREHASH_RequestGodlikePowers);
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+ msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ msg->nextBlockFast(_PREHASH_RequestBlock);
+ msg->addBOOLFast(_PREHASH_Godlike, TRUE);
+ msg->addUUIDFast(_PREHASH_Token, LLUUID::null);
+
+ // simulators need to know about your request
+ sendReliableMessage();
+}
+
+void LLAgent::requestLeaveGodMode()
+{
+ LLMessageSystem* msg = gMessageSystem;
+ msg->newMessageFast(_PREHASH_RequestGodlikePowers);
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+ msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ msg->nextBlockFast(_PREHASH_RequestBlock);
+ msg->addBOOLFast(_PREHASH_Godlike, FALSE);
+ msg->addUUIDFast(_PREHASH_Token, LLUUID::null);
+
+ // simulator needs to know about your request
+ sendReliableMessage();
+}
+
+// wearables
+LLAgent::createStandardWearablesAllDoneCallback::~createStandardWearablesAllDoneCallback()
+{
+ gAgent.createStandardWearablesAllDone();
+}
+
+LLAgent::sendAgentWearablesUpdateCallback::~sendAgentWearablesUpdateCallback()
+{
+ gAgent.sendAgentWearablesUpdate();
+}
+
+LLAgent::addWearableToAgentInventoryCallback::addWearableToAgentInventoryCallback(
+ LLPointer cb, S32 index, LLWearable* wearable, U32 todo) :
+ mIndex(index),
+ mWearable(wearable),
+ mTodo(todo),
+ mCB(cb)
+{
+}
+
+void LLAgent::addWearableToAgentInventoryCallback::fire(const LLUUID& inv_item)
+{
+ if (inv_item.isNull())
+ return;
+
+ gAgent.addWearabletoAgentInventoryDone(mIndex, inv_item, mWearable);
+
+ if (mTodo & CALL_UPDATE)
+ {
+ gAgent.sendAgentWearablesUpdate();
+ }
+ if (mTodo & CALL_RECOVERDONE)
+ {
+ gAgent.recoverMissingWearableDone();
+ }
+ /*
+ * Do this for every one in the loop
+ */
+ if (mTodo & CALL_CREATESTANDARDDONE)
+ {
+ gAgent.createStandardWearablesDone(mIndex);
+ }
+ if (mTodo & CALL_MAKENEWOUTFITDONE)
+ {
+ gAgent.makeNewOutfitDone(mIndex);
+ }
+}
+
+void LLAgent::addWearabletoAgentInventoryDone(
+ S32 index,
+ const LLUUID& item_id,
+ LLWearable* wearable)
+{
+ if (item_id.isNull())
+ return;
+
+ LLUUID old_item_id = mWearableEntry[index].mItemID;
+ mWearableEntry[index].mItemID = item_id;
+ mWearableEntry[index].mWearable = wearable;
+ if (old_item_id.notNull())
+ gInventory.addChangedMask(LLInventoryObserver::LABEL, old_item_id);
+ gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id);
+ LLViewerInventoryItem* item = gInventory.getItem(item_id);
+ if(item && wearable)
+ {
+ // We're changing the asset id, so we both need to set it
+ // locally via setAssetUUID() and via setTransactionID() which
+ // will be decoded on the server. JC
+ item->setAssetUUID(wearable->getID());
+ item->setTransactionID(wearable->getTransactionID());
+ gInventory.addChangedMask(LLInventoryObserver::INTERNAL, item_id);
+ item->updateServer(FALSE);
+ }
+ gInventory.notifyObservers();
+}
+
+void LLAgent::sendAgentWearablesUpdate()
+{
+ // First make sure that we have inventory items for each wearable
+ S32 i;
+ for(i=0; i < WT_COUNT; ++i)
+ {
+ LLWearable* wearable = mWearableEntry[ i ].mWearable;
+ if (wearable)
+ {
+ if( mWearableEntry[ i ].mItemID.isNull() )
+ {
+ LLPointer cb =
+ new addWearableToAgentInventoryCallback(
+ LLPointer(NULL),
+ i,
+ wearable,
+ addWearableToAgentInventoryCallback::CALL_NONE);
+ addWearableToAgentInventory(cb, wearable);
+ }
+ else
+ {
+ gInventory.addChangedMask( LLInventoryObserver::LABEL,
+ mWearableEntry[i].mItemID );
+ }
+ }
+ }
+
+ // Then make sure the inventory is in sync with the avatar.
+ gInventory.notifyObservers();
+
+ // Send the AgentIsNowWearing
+ gMessageSystem->newMessageFast(_PREHASH_AgentIsNowWearing);
+
+ gMessageSystem->nextBlockFast(_PREHASH_AgentData);
+ gMessageSystem->addUUIDFast(_PREHASH_AgentID, getID());
+ gMessageSystem->addUUIDFast(_PREHASH_SessionID, getSessionID());
+
+ LL_DEBUGS("Wearables") << "sendAgentWearablesUpdate()" << LL_ENDL;
+ for(i=0; i < WT_COUNT; ++i)
+ {
+ gMessageSystem->nextBlockFast(_PREHASH_WearableData);
+
+ U8 type_u8 = (U8)i;
+ gMessageSystem->addU8Fast(_PREHASH_WearableType, type_u8 );
+
+ LLWearable* wearable = mWearableEntry[ i ].mWearable;
+ if( wearable )
+ {
+ LL_DEBUGS("Wearables") << "Sending wearable " << wearable->getName() << " mItemID = " << mWearableEntry[ i ].mItemID << LL_ENDL;
+ gMessageSystem->addUUIDFast(_PREHASH_ItemID, mWearableEntry[ i ].mItemID );
+ }
+ else
+ {
+ LL_DEBUGS("Wearables") << "Not wearing wearable type " << LLWearable::typeToTypeName((EWearableType)i) << LL_ENDL;
+ gMessageSystem->addUUIDFast(_PREHASH_ItemID, LLUUID::null );
+ }
+
+ LL_DEBUGS("Wearables") << " " << LLWearable::typeToTypeLabel((EWearableType)i) << " : " << (wearable ? wearable->getID() : LLUUID::null) << LL_ENDL;
+ }
+ gAgent.sendReliableMessage();
+}
+
+void LLAgent::saveWearable( EWearableType type, BOOL send_update )
+{
+ LLWearable* old_wearable = mWearableEntry[(S32)type].mWearable;
+ if( old_wearable && (old_wearable->isDirty() || old_wearable->isOldVersion()) )
+ {
+ LLWearable* new_wearable = gWearableList.createCopyFromAvatar( old_wearable );
+ mWearableEntry[(S32)type].mWearable = new_wearable;
+
+ LLInventoryItem* item = gInventory.getItem(mWearableEntry[(S32)type].mItemID);
+ if( item )
+ {
+ // Update existing inventory item
+ LLPointer template_item =
+ new LLViewerInventoryItem(item->getUUID(),
+ item->getParentUUID(),
+ item->getPermissions(),
+ new_wearable->getID(),
+ new_wearable->getAssetType(),
+ item->getInventoryType(),
+ item->getName(),
+ item->getDescription(),
+ item->getSaleInfo(),
+ item->getFlags(),
+ item->getCreationDate());
+ template_item->setTransactionID(new_wearable->getTransactionID());
+ template_item->updateServer(FALSE);
+ gInventory.updateItem(template_item);
+ }
+ else
+ {
+ // Add a new inventory item (shouldn't ever happen here)
+ U32 todo = addWearableToAgentInventoryCallback::CALL_NONE;
+ if (send_update)
+ {
+ todo |= addWearableToAgentInventoryCallback::CALL_UPDATE;
+ }
+ LLPointer cb =
+ new addWearableToAgentInventoryCallback(
+ LLPointer(NULL),
+ (S32)type,
+ new_wearable,
+ todo);
+ addWearableToAgentInventory(cb, new_wearable);
+ return;
+ }
+
+ getAvatarObject()->wearableUpdated( type );
+
+ if( send_update )
+ {
+ sendAgentWearablesUpdate();
+ }
+ }
+}
+
+void LLAgent::saveWearableAs(
+ EWearableType type,
+ const std::string& new_name,
+ BOOL save_in_lost_and_found)
+{
+ if(!isWearableCopyable(type))
+ {
+ llwarns << "LLAgent::saveWearableAs() not copyable." << llendl;
+ return;
+ }
+ LLWearable* old_wearable = getWearable(type);
+ if(!old_wearable)
+ {
+ llwarns << "LLAgent::saveWearableAs() no old wearable." << llendl;
+ return;
+ }
+ LLInventoryItem* item = gInventory.getItem(mWearableEntry[type].mItemID);
+ if(!item)
+ {
+ llwarns << "LLAgent::saveWearableAs() no inventory item." << llendl;
+ return;
+ }
+ std::string trunc_name(new_name);
+ LLStringUtil::truncate(trunc_name, DB_INV_ITEM_NAME_STR_LEN);
+ LLWearable* new_wearable = gWearableList.createCopyFromAvatar(
+ old_wearable,
+ trunc_name);
+ LLPointer cb =
+ new addWearableToAgentInventoryCallback(
+ LLPointer(NULL),
+ type,
+ new_wearable,
+ addWearableToAgentInventoryCallback::CALL_UPDATE);
+ LLUUID category_id;
+ if (save_in_lost_and_found)
+ {
+ category_id = gInventory.findCategoryUUIDForType(
+ LLAssetType::AT_LOST_AND_FOUND);
+ }
+ else
+ {
+ // put in same folder as original
+ category_id = item->getParentUUID();
+ }
+
+ copy_inventory_item(
+ gAgent.getID(),
+ item->getPermissions().getOwner(),
+ item->getUUID(),
+ category_id,
+ new_name,
+ cb);
+
+/*
+ LLWearable* old_wearable = getWearable( type );
+ if( old_wearable )
+ {
+ std::string old_name = old_wearable->getName();
+ old_wearable->setName( new_name );
+ LLWearable* new_wearable = gWearableList.createCopyFromAvatar( old_wearable );
+ old_wearable->setName( old_name );
+
+ LLUUID category_id;
+ LLInventoryItem* item = gInventory.getItem( mWearableEntry[ type ].mItemID );
+ if( item )
+ {
+ new_wearable->setPermissions(item->getPermissions());
+ if (save_in_lost_and_found)
+ {
+ category_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_LOST_AND_FOUND);
+ }
+ else
+ {
+ // put in same folder as original
+ category_id = item->getParentUUID();
+ }
+ LLInventoryView* view = LLInventoryView::getActiveInventory();
+ if(view)
+ {
+ view->getPanel()->setSelection(item->getUUID(), TAKE_FOCUS_NO);
+ }
+ }
+
+ mWearableEntry[ type ].mWearable = new_wearable;
+ LLPointer cb =
+ new addWearableToAgentInventoryCallback(
+ LLPointer(NULL),
+ type,
+ addWearableToAgentInventoryCallback::CALL_UPDATE);
+ addWearableToAgentInventory(cb, new_wearable, category_id);
+ }
+*/
+}
+
+void LLAgent::revertWearable( EWearableType type )
+{
+ LLWearable* wearable = mWearableEntry[(S32)type].mWearable;
+ if( wearable )
+ {
+ wearable->writeToAvatar( TRUE );
+ }
+ sendAgentSetAppearance();
+}
+
+void LLAgent::revertAllWearables()
+{
+ for( S32 i=0; i < WT_COUNT; i++ )
+ {
+ revertWearable( (EWearableType)i );
+ }
+}
+
+void LLAgent::saveAllWearables()
+{
+ //if(!gInventory.isLoaded())
+ //{
+ // return;
+ //}
+
+ for( S32 i=0; i < WT_COUNT; i++ )
+ {
+ saveWearable( (EWearableType)i, FALSE );
+ }
+ sendAgentWearablesUpdate();
+}
+
+// Called when the user changes the name of a wearable inventory item that is currenlty being worn.
+void LLAgent::setWearableName( const LLUUID& item_id, const std::string& new_name )
+{
+ for( S32 i=0; i < WT_COUNT; i++ )
+ {
+ if( mWearableEntry[i].mItemID == item_id )
+ {
+ LLWearable* old_wearable = mWearableEntry[i].mWearable;
+ llassert( old_wearable );
+
+ std::string old_name = old_wearable->getName();
+ old_wearable->setName( new_name );
+ LLWearable* new_wearable = gWearableList.createCopy( old_wearable );
+ LLInventoryItem* item = gInventory.getItem(item_id);
+ if(item)
+ {
+ new_wearable->setPermissions(item->getPermissions());
+ }
+ old_wearable->setName( old_name );
+
+ mWearableEntry[i].mWearable = new_wearable;
+ sendAgentWearablesUpdate();
+ break;
+ }
+ }
+}
+
+
+BOOL LLAgent::isWearableModifiable(EWearableType type)
+{
+ LLUUID item_id = getWearableItem(type);
+ if(!item_id.isNull())
+ {
+ LLInventoryItem* item = gInventory.getItem(item_id);
+ if(item && item->getPermissions().allowModifyBy(gAgent.getID(),
+ gAgent.getGroupID()))
+ {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+BOOL LLAgent::isWearableCopyable(EWearableType type)
+{
+ LLUUID item_id = getWearableItem(type);
+ if(!item_id.isNull())
+ {
+ LLInventoryItem* item = gInventory.getItem(item_id);
+ if(item && item->getPermissions().allowCopyBy(gAgent.getID(),
+ gAgent.getGroupID()))
+ {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+U32 LLAgent::getWearablePermMask(EWearableType type)
+{
+ LLUUID item_id = getWearableItem(type);
+ if(!item_id.isNull())
+ {
+ LLInventoryItem* item = gInventory.getItem(item_id);
+ if(item)
+ {
+ return item->getPermissions().getMaskOwner();
+ }
+ }
+ return PERM_NONE;
+}
+
+LLInventoryItem* LLAgent::getWearableInventoryItem(EWearableType type)
+{
+ LLUUID item_id = getWearableItem(type);
+ LLInventoryItem* item = NULL;
+ if(item_id.notNull())
+ {
+ item = gInventory.getItem(item_id);
+ }
+ return item;
+}
+
+LLWearable* LLAgent::getWearableFromWearableItem( const LLUUID& item_id )
+{
+ for( S32 i=0; i < WT_COUNT; i++ )
+ {
+ if( mWearableEntry[i].mItemID == item_id )
+ {
+ return mWearableEntry[i].mWearable;
+ }
+ }
+ return NULL;
+}
+
+
+void LLAgent::sendAgentWearablesRequest()
+{
+ gMessageSystem->newMessageFast(_PREHASH_AgentWearablesRequest);
+ gMessageSystem->nextBlockFast(_PREHASH_AgentData);
+ gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
+ gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID() );
+ sendReliableMessage();
+}
+
+// Used to enable/disable menu items.
+// static
+BOOL LLAgent::selfHasWearable( void* userdata )
+{
+ EWearableType type = (EWearableType)(intptr_t)userdata;
+ return gAgent.getWearable( type ) != NULL;
+}
+
+BOOL LLAgent::isWearingItem( const LLUUID& item_id )
+{
+ return (getWearableFromWearableItem( item_id ) != NULL);
+}
+
+// static
+void LLAgent::processAgentInitialWearablesUpdate( LLMessageSystem* mesgsys, void** user_data )
+{
+ // We should only receive this message a single time. Ignore subsequent AgentWearablesUpdates
+ // that may result from AgentWearablesRequest having been sent more than once.
+ static bool first = true;
+ if (!first) return;
+ first = false;
+
+ LLUUID agent_id;
+ gMessageSystem->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id );
+
+ LLVOAvatar* avatar = gAgent.getAvatarObject();
+ if( avatar && (agent_id == avatar->getID()) )
+ {
+ gMessageSystem->getU32Fast(_PREHASH_AgentData, _PREHASH_SerialNum, gAgent.mAgentWearablesUpdateSerialNum );
+
+ S32 num_wearables = gMessageSystem->getNumberOfBlocksFast(_PREHASH_WearableData);
+ if( num_wearables < 4 )
+ {
+ // Transitional state. Avatars should always have at least their body parts (hair, eyes, shape and skin).
+ // The fact that they don't have any here (only a dummy is sent) implies that this account existed
+ // before we had wearables, or that the database has gotten messed up.
+ return;
+ }
+ //else
+ //{
+ // // OGPX HACK: OGP authentication does not pass back login-flags,
+ // // thus doesn't check for "gendered" flag
+ // // so this isn't an ideal place for this because the check in idle_startup in STATE_WEARABLES_WAIT
+ // // is happening *before* this call. That causes the welcomechoosesex dialog to be displayed
+ // // but I'm torn on removing this commented out code because I'm unsure how the initial wearables
+ // // code will work out.
+ // gAgent.setGenderChosen(TRUE);
+ //}
+
+ //lldebugs << "processAgentInitialWearablesUpdate()" << llendl;
+ // Add wearables
+ LLUUID asset_id_array[ WT_COUNT ];
+ S32 i;
+ for( i=0; i < num_wearables; i++ )
+ {
+ U8 type_u8 = 0;
+ gMessageSystem->getU8Fast(_PREHASH_WearableData, _PREHASH_WearableType, type_u8, i );
+ if( type_u8 >= WT_COUNT )
+ {
+ continue;
+ }
+ EWearableType type = (EWearableType) type_u8;
+
+ LLUUID item_id;
+ gMessageSystem->getUUIDFast(_PREHASH_WearableData, _PREHASH_ItemID, item_id, i );
+
+ LLUUID asset_id;
+ gMessageSystem->getUUIDFast(_PREHASH_WearableData, _PREHASH_AssetID, asset_id, i );
+ if( asset_id.isNull() )
+ {
+ LLWearable::removeFromAvatar( type, FALSE );
+ }
+ else
+ {
+ LLAssetType::EType asset_type = LLWearable::typeToAssetType( type );
+ if( asset_type == LLAssetType::AT_NONE )
+ {
+ continue;
+ }
+
+ gAgent.mWearableEntry[type].mItemID = item_id;
+ asset_id_array[type] = asset_id;
+ }
+
+ LL_DEBUGS("Wearables") << " " << LLWearable::typeToTypeLabel(type) << " " << asset_id << " item id " << gAgent.mWearableEntry[type].mItemID.asString() << LL_ENDL;
+ }
+
+ // now that we have the asset ids...request the wearable assets
+ for( i = 0; i < WT_COUNT; i++ )
+ {
+ LL_DEBUGS("Wearables") << " fetching " << asset_id_array[i] << LL_ENDL;
+ if( !gAgent.mWearableEntry[i].mItemID.isNull() )
+ {
+ gWearableList.getAsset(
+ asset_id_array[i],
+ LLStringUtil::null,
+ LLWearable::typeToAssetType( (EWearableType) i ),
+ LLAgent::onInitialWearableAssetArrived, (void*)(intptr_t)i );
+ }
+ }
+ }
+}
+
+// A single wearable that the avatar was wearing on start-up has arrived from the database.
+// static
+void LLAgent::onInitialWearableAssetArrived( LLWearable* wearable, void* userdata )
+{
+ EWearableType type = (EWearableType)(intptr_t)userdata;
+
+ LLVOAvatar* avatar = gAgent.getAvatarObject();
+ if( !avatar )
+ {
+ return;
+ }
+
+ if( wearable )
+ {
+ llassert( type == wearable->getType() );
+ gAgent.mWearableEntry[ type ].mWearable = wearable;
+
+ // disable composites if initial textures are baked
+ avatar->setupComposites();
+ gAgent.queryWearableCache();
+
+ wearable->writeToAvatar( FALSE );
+ avatar->setCompositeUpdatesEnabled(TRUE);
+ gInventory.addChangedMask( LLInventoryObserver::LABEL, gAgent.mWearableEntry[type].mItemID );
+ }
+ else
+ {
+ // Somehow the asset doesn't exist in the database.
+ gAgent.recoverMissingWearable( type );
+ }
+
+ gInventory.notifyObservers();
+
+ // Have all the wearables that the avatar was wearing at log-in arrived?
+ if( !gAgent.mWearablesLoaded )
+ {
+ gAgent.mWearablesLoaded = TRUE;
+ for( S32 i = 0; i < WT_COUNT; i++ )
+ {
+ if( !gAgent.mWearableEntry[i].mItemID.isNull() && !gAgent.mWearableEntry[i].mWearable )
+ {
+ gAgent.mWearablesLoaded = FALSE;
+ break;
+ }
+ }
+ }
+
+ if( gAgent.mWearablesLoaded )
+ {
+ // Make sure that the server's idea of the avatar's wearables actually match the wearables.
+ gAgent.sendAgentSetAppearance();
+
+ // Check to see if there are any baked textures that we hadn't uploaded before we logged off last time.
+ // If there are any, schedule them to be uploaded as soon as the layer textures they depend on arrive.
+ if( !gAgent.cameraCustomizeAvatar() )
+ {
+ avatar->requestLayerSetUploads();
+ }
+ }
+}
+
+// Normally, all wearables referred to "AgentWearablesUpdate" will correspond to actual assets in the
+// database. If for some reason, we can't load one of those assets, we can try to reconstruct it so that
+// the user isn't left without a shape, for example. (We can do that only after the inventory has loaded.)
+void LLAgent::recoverMissingWearable( EWearableType type )
+{
+ // Try to recover by replacing missing wearable with a new one.
+ LLNotifications::instance().add("ReplacedMissingWearable");
+ lldebugs << "Wearable " << LLWearable::typeToTypeLabel( type ) << " could not be downloaded. Replaced inventory item with default wearable." << llendl;
+ LLWearable* new_wearable = gWearableList.createNewWearable(type);
+
+ S32 type_s32 = (S32) type;
+ mWearableEntry[type_s32].mWearable = new_wearable;
+ new_wearable->writeToAvatar( TRUE );
+
+ // Add a new one in the lost and found folder.
+ // (We used to overwrite the "not found" one, but that could potentially
+ // destory content.) JC
+ LLUUID lost_and_found_id =
+ gInventory.findCategoryUUIDForType(LLAssetType::AT_LOST_AND_FOUND);
+ LLPointer cb =
+ new addWearableToAgentInventoryCallback(
+ LLPointer(NULL),
+ type_s32,
+ new_wearable,
+ addWearableToAgentInventoryCallback::CALL_RECOVERDONE);
+ addWearableToAgentInventory( cb, new_wearable, lost_and_found_id, TRUE);
+}
+
+void LLAgent::recoverMissingWearableDone()
+{
+ // Have all the wearables that the avatar was wearing at log-in arrived or been fabricated?
+ mWearablesLoaded = TRUE;
+ for( S32 i = 0; i < WT_COUNT; i++ )
+ {
+ if( !mWearableEntry[i].mItemID.isNull() && !mWearableEntry[i].mWearable )
+ {
+ mWearablesLoaded = FALSE;
+ break;
+ }
+ }
+
+ if( mWearablesLoaded )
+ {
+ // Make sure that the server's idea of the avatar's wearables actually match the wearables.
+ sendAgentSetAppearance();
+ }
+ else
+ {
+ gInventory.addChangedMask( LLInventoryObserver::LABEL, LLUUID::null );
+ gInventory.notifyObservers();
+ }
+}
+
+void LLAgent::createStandardWearables(BOOL female)
+{
+ llwarns << "Creating Standard " << (female ? "female" : "male" )
+ << " Wearables" << llendl;
+
+ if (mAvatarObject.isNull())
+ {
+ return;
+ }
+
+ if(female) mAvatarObject->setSex(SEX_FEMALE);
+ else mAvatarObject->setSex(SEX_MALE);
+
+ BOOL create[WT_COUNT] =
+ {
+ TRUE, //WT_SHAPE
+ TRUE, //WT_SKIN
+ TRUE, //WT_HAIR
+ TRUE, //WT_EYES
+ TRUE, //WT_SHIRT
+ TRUE, //WT_PANTS
+ TRUE, //WT_SHOES
+ TRUE, //WT_SOCKS
+ FALSE, //WT_JACKET
+ FALSE, //WT_GLOVES
+ TRUE, //WT_UNDERSHIRT
+ TRUE, //WT_UNDERPANTS
+ FALSE, //WT_SKIRT
+ FALSE, //WT_ALPHA
+ FALSE //WT_TATTOO
+ };
+
+ for( S32 i=0; i < WT_COUNT; i++ )
+ {
+ bool once = false;
+ LLPointer donecb = NULL;
+ if( create[i] )
+ {
+ if (!once)
+ {
+ once = true;
+ donecb = new createStandardWearablesAllDoneCallback;
+ }
+ llassert( mWearableEntry[i].mWearable == NULL );
+ LLWearable* wearable = gWearableList.createNewWearable((EWearableType)i);
+ mWearableEntry[i].mWearable = wearable;
+ // no need to update here...
+ LLPointer cb =
+ new addWearableToAgentInventoryCallback(
+ donecb,
+ i,
+ wearable,
+ addWearableToAgentInventoryCallback::CALL_CREATESTANDARDDONE);
+ addWearableToAgentInventory(cb, wearable, LLUUID::null, FALSE);
+ }
+ }
+}
+void LLAgent::createStandardWearablesDone(S32 index)
+{
+ LLWearable* wearable = mWearableEntry[index].mWearable;
+
+ if (wearable)
+ {
+ wearable->writeToAvatar(TRUE);
+ }
+}
+
+void LLAgent::createStandardWearablesAllDone()
+{
+ // ... because sendAgentWearablesUpdate will notify inventory
+ // observers.
+ mWearablesLoaded = TRUE;
+ sendAgentWearablesUpdate();
+ sendAgentSetAppearance();
+
+ // Treat this as the first texture entry message, if none received yet
+ mAvatarObject->onFirstTEMessageReceived();
+}
+
+void LLAgent::makeNewOutfit(
+ const std::string& new_folder_name,
+ const LLDynamicArray& wearables_to_include,
+ const LLDynamicArray& attachments_to_include,
+ BOOL rename_clothing)
+{
+ if (mAvatarObject.isNull())
+ {
+ return;
+ }
+
+ // First, make a folder in the Clothes directory.
+ LLUUID folder_id = gInventory.createNewCategory(
+ gInventory.findCategoryUUIDForType(LLAssetType::AT_CLOTHING),
+ LLAssetType::AT_NONE,
+ new_folder_name);
+
+ bool found_first_item = false;
+
+ ///////////////////
+ // Wearables
+
+ if( wearables_to_include.count() )
+ {
+ // Then, iterate though each of the wearables and save copies of them in the folder.
+ S32 i;
+ S32 count = wearables_to_include.count();
+ LLDynamicArray delete_items;
+ LLPointer cbdone = NULL;
+ for( i = 0; i < count; ++i )
+ {
+ S32 index = wearables_to_include[i];
+ LLWearable* old_wearable = mWearableEntry[ index ].mWearable;
+ if( old_wearable )
+ {
+ std::string new_name;
+ LLWearable* new_wearable;
+ new_wearable = gWearableList.createCopy(old_wearable);
+ if (rename_clothing)
+ {
+ new_name = new_folder_name;
+ new_name.append(" ");
+ new_name.append(old_wearable->getTypeLabel());
+ LLStringUtil::truncate(new_name, DB_INV_ITEM_NAME_STR_LEN);
+ new_wearable->setName(new_name);
+ }
+
+ LLViewerInventoryItem* item = gInventory.getItem(mWearableEntry[index].mItemID);
+ S32 todo = addWearableToAgentInventoryCallback::CALL_NONE;
+ if (!found_first_item)
+ {
+ found_first_item = true;
+ /* set the focus to the first item */
+ todo |= addWearableToAgentInventoryCallback::CALL_MAKENEWOUTFITDONE;
+ /* send the agent wearables update when done */
+ cbdone = new sendAgentWearablesUpdateCallback;
+ }
+ LLPointer cb =
+ new addWearableToAgentInventoryCallback(
+ cbdone,
+ index,
+ new_wearable,
+ todo);
+ if (isWearableCopyable((EWearableType)index))
+ {
+ copy_inventory_item(
+ gAgent.getID(),
+ item->getPermissions().getOwner(),
+ item->getUUID(),
+ folder_id,
+ new_name,
+ cb);
+ }
+ else
+ {
+ move_inventory_item(
+ gAgent.getID(),
+ gAgent.getSessionID(),
+ item->getUUID(),
+ folder_id,
+ new_name,
+ cb);
+ }
+ }
+ }
+ gInventory.notifyObservers();
+ }
+
+
+ ///////////////////
+ // Attachments
+
+ if( attachments_to_include.count() )
+ {
+ BOOL msg_started = FALSE;
+ LLMessageSystem* msg = gMessageSystem;
+ for( S32 i = 0; i < attachments_to_include.count(); i++ )
+ {
+ S32 attachment_pt = attachments_to_include[i];
+ LLViewerJointAttachment* attachment = get_if_there(mAvatarObject->mAttachmentPoints, attachment_pt, (LLViewerJointAttachment*)NULL );
+ if(!attachment) continue;
+ LLViewerObject* attached_object = attachment->getObject();
+ if(!attached_object) continue;
+ const LLUUID& item_id = attachment->getItemID();
+ if(item_id.isNull()) continue;
+ LLInventoryItem* item = gInventory.getItem(item_id);
+ if(!item) continue;
+ if(!msg_started)
+ {
+ msg_started = TRUE;
+ msg->newMessage("CreateNewOutfitAttachments");
+ msg->nextBlock("AgentData");
+ msg->addUUID("AgentID", getID());
+ msg->addUUID("SessionID", getSessionID());
+ msg->nextBlock("HeaderData");
+ msg->addUUID("NewFolderID", folder_id);
+ }
+ msg->nextBlock("ObjectData");
+ msg->addUUID("OldItemID", item_id);
+ msg->addUUID("OldFolderID", item->getParentUUID());
+ }
+
+ if( msg_started )
+ {
+ sendReliableMessage();
+ }
+
+ }
+}
+
+void LLAgent::makeNewOutfitDone(S32 index)
+{
+ LLUUID first_item_id = mWearableEntry[index].mItemID;
+ // Open the inventory and select the first item we added.
+ if( first_item_id.notNull() )
+ {
+ LLInventoryView* view = LLInventoryView::getActiveInventory();
+ if(view)
+ {
+ view->getPanel()->setSelection(first_item_id, TAKE_FOCUS_NO);
+ }
+ }
+}
+
+
+void LLAgent::addWearableToAgentInventory(
+ LLPointer cb,
+ LLWearable* wearable,
+ const LLUUID& category_id,
+ BOOL notify)
+{
+ create_inventory_item(
+ gAgent.getID(),
+ gAgent.getSessionID(),
+ category_id,
+ wearable->getTransactionID(),
+ wearable->getName(),
+ wearable->getDescription(),
+ wearable->getAssetType(),
+ LLInventoryType::IT_WEARABLE,
+ wearable->getType(),
+ wearable->getPermissions().getMaskNextOwner(),
+ cb);
+}
+
+//-----------------------------------------------------------------------------
+// sendAgentSetAppearance()
+//-----------------------------------------------------------------------------
+void LLAgent::sendAgentSetAppearance()
+{
+ if (mAvatarObject.isNull()) return;
+
+ if (mNumPendingQueries > 0 && !gAgent.cameraCustomizeAvatar())
+ {
+ return;
+ }
+
+
+ llinfos << "TAT: Sent AgentSetAppearance: " << mAvatarObject->getBakedStatusForPrintout() << llendl;
+ //dumpAvatarTEs( "sendAgentSetAppearance()" );
+
+ LLMessageSystem* msg = gMessageSystem;
+ msg->newMessageFast(_PREHASH_AgentSetAppearance);
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, getID());
+ msg->addUUIDFast(_PREHASH_SessionID, getSessionID());
+
+ // correct for the collision tolerance (to make it look like the
+ // agent is actually walking on the ground/object)
+ // NOTE -- when we start correcting all of the other Havok geometry
+ // to compensate for the COLLISION_TOLERANCE ugliness we will have
+ // to tweak this number again
+ const LLVector3 body_size = mAvatarObject->mBodySize;
+ msg->addVector3Fast(_PREHASH_Size, body_size);
+
+ // To guard against out of order packets
+ // Note: always start by sending 1. This resets the server's count. 0 on the server means "uninitialized"
+ mAppearanceSerialNum++;
+ msg->addU32Fast(_PREHASH_SerialNum, mAppearanceSerialNum );
+
+ // is texture data current relative to wearables?
+ // KLW - TAT this will probably need to check the local queue.
+ BOOL textures_current = !mAvatarObject->hasPendingBakedUploads() && mWearablesLoaded;
+
+ for(U8 baked_index = 0; baked_index < BAKED_NUM_INDICES; baked_index++ )
+ {
+ const ETextureIndex texture_index = getTextureIndex((EBakedTextureIndex)baked_index);
+
+ // if we're not wearing a skirt, we don't need the texture to be baked
+ if (texture_index == TEX_SKIRT_BAKED && !mAvatarObject->isWearingWearableType(WT_SKIRT))
+ {
+ continue;
+ }
+
+ // IMG_DEFAULT_AVATAR means not baked
+ if (!mAvatarObject->isTextureDefined(texture_index))
+ {
+ textures_current = FALSE;
+ break;
+ }
+ }
+
+ // only update cache entries if we have all our baked textures
+ if (textures_current)
+ {
+ llinfos << "TAT: Sending cached texture data" << llendl;
+ for (U8 baked_index = 0; baked_index < BAKED_NUM_INDICES; baked_index++)
+ {
+ const LLVOAvatarDictionary::WearableDictionaryEntry *wearable_dict = LLVOAvatarDictionary::getInstance()->getWearable((EBakedTextureIndex)baked_index);
+ LLUUID hash;
+ for (U8 i=0; i < wearable_dict->mWearablesVec.size(); i++)
+ {
+ // EWearableType wearable_type = gBakedWearableMap[baked_index][wearable_num];
+ const EWearableType wearable_type = wearable_dict->mWearablesVec[i];
+ const LLWearable* wearable = getWearable(wearable_type);
+ if (wearable)
+ {
+ hash ^= wearable->getID();
+ }
+ }
+ if (hash.notNull())
+ {
+ hash ^= wearable_dict->mHashID;
+ }
+
+ const ETextureIndex texture_index = getTextureIndex((EBakedTextureIndex)baked_index);
+
+ msg->nextBlockFast(_PREHASH_WearableData);
+ msg->addUUIDFast(_PREHASH_CacheID, hash);
+ msg->addU8Fast(_PREHASH_TextureIndex, (U8)texture_index);
+ }
+ msg->nextBlockFast(_PREHASH_ObjectData);
+
+ // Tag changing support
+ if (!gSavedSettings.controlExists("AscentSpoofClientUUID"))
+ {
+ gSavedSettings.declareString("AscentSpoofClientUUID", "8873757c-092a-98fb-1afd-ecd347566fcd", "FAKIN' BAKE-IN");
+ gSavedSettings.setString("AscentSpoofClientUUID", "8873757c-092a-98fb-1afd-ecd347566fcd");
+ }
+
+ mAvatarObject->packTEMessage( gMessageSystem, 1, gSavedSettings.getString("AscentSpoofClientUUID") );
+ }
+ else
+ {
+ // If the textures aren't baked, send NULL for texture IDs
+ // This means the baked texture IDs on the server will be untouched.
+ // Once all textures are baked, another AvatarAppearance message will be sent to update the TEs
+ msg->nextBlockFast(_PREHASH_ObjectData);
+ gMessageSystem->addBinaryDataFast(_PREHASH_TextureEntry, NULL, 0);
+ }
+
+
+ S32 transmitted_params = 0;
+ for (LLViewerVisualParam* param = (LLViewerVisualParam*)mAvatarObject->getFirstVisualParam();
+ param;
+ param = (LLViewerVisualParam*)mAvatarObject->getNextVisualParam())
+ {
+ if (param->getGroup() == VISUAL_PARAM_GROUP_TWEAKABLE)
+ {
+ msg->nextBlockFast(_PREHASH_VisualParam );
+
+ // We don't send the param ids. Instead, we assume that the receiver has the same params in the same sequence.
+ const F32 param_value = param->getWeight();
+ const U8 new_weight = F32_to_U8(param_value, param->getMinWeight(), param->getMaxWeight());
+ msg->addU8Fast(_PREHASH_ParamValue, new_weight );
+ transmitted_params++;
+ }
+ }
+
+// llinfos << "Avatar XML num VisualParams transmitted = " << transmitted_params << llendl;
+ sendReliableMessage();
+}
+
+void LLAgent::sendAgentDataUpdateRequest()
+{
+ gMessageSystem->newMessageFast(_PREHASH_AgentDataUpdateRequest);
+ gMessageSystem->nextBlockFast(_PREHASH_AgentData);
+ gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+ gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ sendReliableMessage();
+}
+
+void LLAgent::removeWearable( EWearableType type )
+{
+ LLWearable* old_wearable = mWearableEntry[ type ].mWearable;
+
+ if ( (gAgent.isTeen())
+ && (type == WT_UNDERSHIRT || type == WT_UNDERPANTS))
+ {
+ // Can't take off underclothing in simple UI mode or on PG accounts
+ return;
+ }
+
+ if( old_wearable )
+ {
+ if( old_wearable->isDirty() )
+ {
+ LLSD payload;
+ payload["wearable_type"] = (S32)type;
+ // Bring up view-modal dialog: Save changes? Yes, No, Cancel
+ LLNotifications::instance().add("WearableSave", LLSD(), payload, &LLAgent::onRemoveWearableDialog);
+ return;
+ }
+ else
+ {
+ removeWearableFinal( type );
+ }
+ }
+}
+
+// static
+bool LLAgent::onRemoveWearableDialog(const LLSD& notification, const LLSD& response )
+{
+ S32 option = LLNotification::getSelectedOption(notification, response);
+ EWearableType type = (EWearableType)notification["payload"]["wearable_type"].asInteger();
+ switch( option )
+ {
+ case 0: // "Save"
+ gAgent.saveWearable( type );
+ gAgent.removeWearableFinal( type );
+ break;
+
+ case 1: // "Don't Save"
+ gAgent.removeWearableFinal( type );
+ break;
+
+ case 2: // "Cancel"
+ break;
+
+ default:
+ llassert(0);
+ break;
+ }
+ return false;
+}
+
+// Called by removeWearable() and onRemoveWearableDialog() to actually do the removal.
+void LLAgent::removeWearableFinal( EWearableType type )
+{
+ LLWearable* old_wearable = mWearableEntry[ type ].mWearable;
+
+ gInventory.addChangedMask( LLInventoryObserver::LABEL, mWearableEntry[type].mItemID );
+
+ mWearableEntry[ type ].mWearable = NULL;
+ mWearableEntry[ type ].mItemID.setNull();
+
+ queryWearableCache();
+
+ if( old_wearable )
+ {
+ old_wearable->removeFromAvatar( TRUE );
+ }
+
+ // Update the server
+ sendAgentWearablesUpdate();
+ sendAgentSetAppearance();
+ gInventory.notifyObservers();
+}
+
+void LLAgent::copyWearableToInventory( EWearableType type )
+{
+ LLWearable* wearable = mWearableEntry[ type ].mWearable;
+ if( wearable )
+ {
+ // Save the old wearable if it has changed.
+ if( wearable->isDirty() )
+ {
+ wearable = gWearableList.createCopyFromAvatar( wearable );
+ mWearableEntry[ type ].mWearable = wearable;
+ }
+
+ // Make a new entry in the inventory. (Put it in the same folder as the original item if possible.)
+ LLUUID category_id;
+ LLInventoryItem* item = gInventory.getItem( mWearableEntry[ type ].mItemID );
+ if( item )
+ {
+ category_id = item->getParentUUID();
+ wearable->setPermissions(item->getPermissions());
+ }
+ LLPointer cb =
+ new addWearableToAgentInventoryCallback(
+ LLPointer(NULL),
+ type,
+ wearable);
+ addWearableToAgentInventory(cb, wearable, category_id);
+ }
+}
+
+
+// A little struct to let setWearable() communicate more than one value with onSetWearableDialog().
+struct LLSetWearableData
+{
+ LLSetWearableData( const LLUUID& new_item_id, LLWearable* new_wearable ) :
+ mNewItemID( new_item_id ), mNewWearable( new_wearable ) {}
+ LLUUID mNewItemID;
+ LLWearable* mNewWearable;
+};
+
+BOOL LLAgent::needsReplacement(EWearableType wearableType, S32 remove)
+{
+ return TRUE;
+ /*if (remove) return TRUE;
+
+ return getWearable(wearableType) ? TRUE : FALSE;*/
+}
+
+// Assumes existing wearables are not dirty.
+void LLAgent::setWearableOutfit(
+ const LLInventoryItem::item_array_t& items,
+ const LLDynamicArray< LLWearable* >& wearables,
+ BOOL remove )
+{
+ lldebugs << "setWearableOutfit() start" << llendl;
+
+ BOOL wearables_to_remove[WT_COUNT];
+ wearables_to_remove[WT_SHAPE] = FALSE;
+ wearables_to_remove[WT_SKIN] = FALSE;
+ wearables_to_remove[WT_HAIR] = FALSE;
+ wearables_to_remove[WT_EYES] = FALSE;
+ wearables_to_remove[WT_SHIRT] = remove;
+ wearables_to_remove[WT_PANTS] = remove;
+ wearables_to_remove[WT_SHOES] = remove;
+ wearables_to_remove[WT_SOCKS] = remove;
+ wearables_to_remove[WT_JACKET] = remove;
+ wearables_to_remove[WT_GLOVES] = remove;
+ wearables_to_remove[WT_UNDERSHIRT] = (!gAgent.isTeen()) & remove;
+ wearables_to_remove[WT_UNDERPANTS] = (!gAgent.isTeen()) & remove;
+ wearables_to_remove[WT_SKIRT] = remove;
+ wearables_to_remove[WT_ALPHA] = remove;
+ wearables_to_remove[WT_TATTOO] = remove;
+
+ S32 count = wearables.count();
+ llassert( items.count() == count );
+
+ S32 i;
+ for( i = 0; i < count; i++ )
+ {
+ LLWearable* new_wearable = wearables[i];
+ LLPointer new_item = items[i];
+
+ EWearableType type = new_wearable->getType();
+ wearables_to_remove[type] = FALSE;
+
+ LLWearable* old_wearable = mWearableEntry[ type ].mWearable;
+ if( old_wearable )
+ {
+ const LLUUID& old_item_id = mWearableEntry[ type ].mItemID;
+ if( (old_wearable->getID() == new_wearable->getID()) &&
+ (old_item_id == new_item->getUUID()) )
+ {
+ lldebugs << "No change to wearable asset and item: " << LLWearable::typeToTypeName( type ) << llendl;
+ continue;
+ }
+
+ gInventory.addChangedMask(LLInventoryObserver::LABEL, old_item_id);
+
+ // Assumes existing wearables are not dirty.
+ if( old_wearable->isDirty() )
+ {
+ llassert(0);
+ continue;
+ }
+ }
+
+ mWearableEntry[ type ].mItemID = new_item->getUUID();
+ mWearableEntry[ type ].mWearable = new_wearable;
+ }
+
+ std::vector wearables_being_removed;
+
+ for( i = 0; i < WT_COUNT; i++ )
+ {
+ if( wearables_to_remove[i] )
+ {
+ wearables_being_removed.push_back(mWearableEntry[ i ].mWearable);
+ mWearableEntry[ i ].mWearable = NULL;
+
+ gInventory.addChangedMask(LLInventoryObserver::LABEL, mWearableEntry[ i ].mItemID);
+ mWearableEntry[ i ].mItemID.setNull();
+ }
+ }
+
+ gInventory.notifyObservers();
+
+ queryWearableCache();
+
+ std::vector::iterator wearable_iter;
+
+ for( wearable_iter = wearables_being_removed.begin();
+ wearable_iter != wearables_being_removed.end();
+ ++wearable_iter)
+ {
+ LLWearable* wearablep = *wearable_iter;
+ if (wearablep)
+ {
+ wearablep->removeFromAvatar( TRUE );
+ }
+ }
+
+ for( i = 0; i < count; i++ )
+ {
+ wearables[i]->writeToAvatar( TRUE );
+ }
+
+ // Start rendering & update the server
+ mWearablesLoaded = TRUE;
+ sendAgentWearablesUpdate();
+ sendAgentSetAppearance();
+
+ lldebugs << "setWearableOutfit() end" << llendl;
+}
+
+
+// User has picked "wear on avatar" from a menu.
+void LLAgent::setWearable( LLInventoryItem* new_item, LLWearable* new_wearable )
+{
+ EWearableType type = new_wearable->getType();
+
+ LLWearable* old_wearable = mWearableEntry[ type ].mWearable;
+ if( old_wearable )
+ {
+ const LLUUID& old_item_id = mWearableEntry[ type ].mItemID;
+ if( (old_wearable->getID() == new_wearable->getID()) &&
+ (old_item_id == new_item->getUUID()) )
+ {
+ lldebugs << "No change to wearable asset and item: " << LLWearable::typeToTypeName( type ) << llendl;
+ return;
+ }
+
+ if( old_wearable->isDirty() )
+ {
+ // Bring up modal dialog: Save changes? Yes, No, Cancel
+ LLSD payload;
+ payload["item_id"] = new_item->getUUID();
+ LLNotifications::instance().add( "WearableSave", LLSD(), payload, boost::bind(LLAgent::onSetWearableDialog, _1, _2, new_wearable));
+ return;
+ }
+ }
+
+ setWearableFinal( new_item, new_wearable );
+}
+
+// static
+bool LLAgent::onSetWearableDialog( const LLSD& notification, const LLSD& response, LLWearable* wearable )
+{
+ S32 option = LLNotification::getSelectedOption(notification, response);
+ LLInventoryItem* new_item = gInventory.getItem( notification["payload"]["item_id"].asUUID());
+ if( !new_item )
+ {
+ delete wearable;
+ return false;
+ }
+
+ switch( option )
+ {
+ case 0: // "Save"
+ gAgent.saveWearable( wearable->getType() );
+ gAgent.setWearableFinal( new_item, wearable );
+ break;
+
+ case 1: // "Don't Save"
+ gAgent.setWearableFinal( new_item, wearable );
+ break;
+
+ case 2: // "Cancel"
+ break;
+
+ default:
+ llassert(0);
+ break;
+ }
+
+ delete wearable;
+ return false;
+}
+
+// Called from setWearable() and onSetWearableDialog() to actually set the wearable.
+void LLAgent::setWearableFinal( LLInventoryItem* new_item, LLWearable* new_wearable )
+{
+ EWearableType type = new_wearable->getType();
+
+ // Replace the old wearable with a new one.
+ llassert( new_item->getAssetUUID() == new_wearable->getID() );
+ LLUUID old_item_id = mWearableEntry[ type ].mItemID;
+ mWearableEntry[ type ].mItemID = new_item->getUUID();
+ mWearableEntry[ type ].mWearable = new_wearable;
+
+ if (old_item_id.notNull())
+ {
+ gInventory.addChangedMask( LLInventoryObserver::LABEL, old_item_id );
+ gInventory.notifyObservers();
+ }
+
+ //llinfos << "LLVOAvatar::setWearable()" << llendl;
+ queryWearableCache();
+ new_wearable->writeToAvatar( TRUE );
+
+ // Update the server
+ sendAgentWearablesUpdate();
+ sendAgentSetAppearance();
+}
+
+void LLAgent::queryWearableCache()
+{
+ if (!mWearablesLoaded)
+ {
+ return;
+ }
+
+ // Look up affected baked textures.
+ // If they exist:
+ // disallow updates for affected layersets (until dataserver responds with cache request.)
+ // If cache miss, turn updates back on and invalidate composite.
+ // If cache hit, modify baked texture entries.
+ //
+ // Cache requests contain list of hashes for each baked texture entry.
+ // Response is list of valid baked texture assets. (same message)
+
+ gMessageSystem->newMessageFast(_PREHASH_AgentCachedTexture);
+ gMessageSystem->nextBlockFast(_PREHASH_AgentData);
+ gMessageSystem->addUUIDFast(_PREHASH_AgentID, getID());
+ gMessageSystem->addUUIDFast(_PREHASH_SessionID, getSessionID());
+ gMessageSystem->addS32Fast(_PREHASH_SerialNum, mTextureCacheQueryID);
+
+ S32 num_queries = 0;
+ for (U8 baked_index = 0; baked_index < BAKED_NUM_INDICES; baked_index++ )
+ {
+ const LLVOAvatarDictionary::WearableDictionaryEntry *wearable_dict = LLVOAvatarDictionary::getInstance()->getWearable((EBakedTextureIndex)baked_index);
+ LLUUID hash;
+ for (U8 i=0; i < wearable_dict->mWearablesVec.size(); i++)
+ {
+ // EWearableType wearable_type = gBakedWearableMap[baked_index][wearable_num];
+ const EWearableType wearable_type = wearable_dict->mWearablesVec[i];
+ const LLWearable* wearable = getWearable(wearable_type);
+ if (wearable)
+ {
+ hash ^= wearable->getID();
+ }
+ }
+ if (hash.notNull())
+ {
+ hash ^= wearable_dict->mHashID;
+ num_queries++;
+ // *NOTE: make sure at least one request gets packed
+
+ //llinfos << "Requesting texture for hash " << hash << " in baked texture slot " << baked_index << llendl;
+ gMessageSystem->nextBlockFast(_PREHASH_WearableData);
+ gMessageSystem->addUUIDFast(_PREHASH_ID, hash);
+ gMessageSystem->addU8Fast(_PREHASH_TextureIndex, (U8)baked_index);
+ }
+
+ mActiveCacheQueries[ baked_index ] = mTextureCacheQueryID;
+ }
+
+ llinfos << "Requesting texture cache entry for " << num_queries << " baked textures" << llendl;
+ gMessageSystem->sendReliable(getRegion()->getHost());
+ mNumPendingQueries++;
+ mTextureCacheQueryID++;
+}
+
+// User has picked "remove from avatar" from a menu.
+// static
+void LLAgent::userRemoveWearable( void* userdata )
+{
+ EWearableType type = (EWearableType)(intptr_t)userdata;
+
+ if( !(type==WT_SHAPE || type==WT_SKIN || type==WT_HAIR || type==WT_EYES) ) //&&
+ //!((!gAgent.isTeen()) && ( type==WT_UNDERPANTS || type==WT_UNDERSHIRT )) )
+ {
+ gAgent.removeWearable( type );
+ }
+}
+
+void LLAgent::userRemoveAllClothes( void* userdata )
+{
+ // We have to do this up front to avoid having to deal with the case of multiple wearables being dirty.
+ if( gFloaterCustomize )
+ {
+ gFloaterCustomize->askToSaveIfDirty( LLAgent::userRemoveAllClothesStep2, NULL );
+ }
+ else
+ {
+ LLAgent::userRemoveAllClothesStep2( TRUE, NULL );
+ }
+}
+
+void LLAgent::userRemoveAllClothesStep2( BOOL proceed, void* userdata )
+{
+ if( proceed )
+ {
+ gAgent.removeWearable( WT_SHIRT );
+ gAgent.removeWearable( WT_PANTS );
+ gAgent.removeWearable( WT_SHOES );
+ gAgent.removeWearable( WT_SOCKS );
+ gAgent.removeWearable( WT_JACKET );
+ gAgent.removeWearable( WT_GLOVES );
+ gAgent.removeWearable( WT_UNDERSHIRT );
+ gAgent.removeWearable( WT_UNDERPANTS );
+ gAgent.removeWearable( WT_SKIRT );
+ gAgent.removeWearable( WT_ALPHA );
+ gAgent.removeWearable( WT_TATTOO );
+ }
+}
+
+void LLAgent::userRemoveAllAttachments( void* userdata )
+{
+ LLVOAvatar* avatarp = gAgent.getAvatarObject();
+ if(!avatarp)
+ {
+ llwarns << "No avatar found." << llendl;
+ return;
+ }
+
+ gMessageSystem->newMessage("ObjectDetach");
+ gMessageSystem->nextBlockFast(_PREHASH_AgentData);
+ gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
+ gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+
+ for (LLVOAvatar::attachment_map_t::iterator iter = avatarp->mAttachmentPoints.begin();
+ iter != avatarp->mAttachmentPoints.end(); )
+ {
+ LLVOAvatar::attachment_map_t::iterator curiter = iter++;
+ LLViewerJointAttachment* attachment = curiter->second;
+ LLViewerObject* objectp = attachment->getObject();
+ if (objectp)
+ {
+ gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
+ gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, objectp->getLocalID());
+ }
+ }
+ gMessageSystem->sendReliable( gAgent.getRegionHost() );
+}
+
+void LLAgent::observeFriends()
+{
+ if(!mFriendObserver)
+ {
+ mFriendObserver = new LLAgentFriendObserver;
+ LLAvatarTracker::instance().addObserver(mFriendObserver);
+ friendsChanged();
+ }
+}
+
+void LLAgent::parseTeleportMessages(const std::string& xml_filename)
+{
+ LLXMLNodePtr root;
+ BOOL success = LLUICtrlFactory::getLayeredXMLNode(xml_filename, root);
+
+ if (!success || !root || !root->hasName( "teleport_messages" ))
+ {
+ llerrs << "Problem reading teleport string XML file: "
+ << xml_filename << llendl;
+ return;
+ }
+
+ for (LLXMLNode* message_set = root->getFirstChild();
+ message_set != NULL;
+ message_set = message_set->getNextSibling())
+ {
+ if ( !message_set->hasName("message_set") ) continue;
+
+ std::map *teleport_msg_map = NULL;
+ std::string message_set_name;
+
+ if ( message_set->getAttributeString("name", message_set_name) )
+ {
+ //now we loop over all the string in the set and add them
+ //to the appropriate set
+ if ( message_set_name == "errors" )
+ {
+ teleport_msg_map = &sTeleportErrorMessages;
+ }
+ else if ( message_set_name == "progress" )
+ {
+ teleport_msg_map = &sTeleportProgressMessages;
+ }
+ }
+
+ if ( !teleport_msg_map ) continue;
+
+ std::string message_name;
+ for (LLXMLNode* message_node = message_set->getFirstChild();
+ message_node != NULL;
+ message_node = message_node->getNextSibling())
+ {
+ if ( message_node->hasName("message") &&
+ message_node->getAttributeString("name", message_name) )
+ {
+ (*teleport_msg_map)[message_name] =
+ message_node->getTextContents();
+ } //end if ( message exists and has a name)
+ } //end for (all message in set)
+ }//end for (all message sets in xml file)
+}
+
+// OGPX - This code will change when capabilities get refactored.
+// Right now this is used for capabilities that we get from OGP agent domain
+void LLAgent::setCapability(const std::string& name, const std::string& url)
+{
+#if 0 // OGPX : I think (hope?) we don't need this
+ // but I'm leaving it here commented out because I'm not quite
+ // sure why the region capabilities code had it wedged in setCap call
+ // Maybe the agent domain capabilities will need something like this as well
+
+ if (name == "EventQueueGet")
+ {
+ delete mEventPoll;
+ mEventPoll = NULL;
+ mEventPoll = new LLEventPoll(url, getHost());
+ }
+ else if (name == "UntrustedSimulatorMessage")
+ {
+ LLHTTPSender::setSender(mHost, new LLCapHTTPSender(url));
+ }
+ else
+#endif
+ {
+ mCapabilities[name] = url;
+ }
+}
+
+//OGPX : Agent Domain capabilities... this needs to be refactored
+std::string LLAgent::getCapability(const std::string& name) const
+{
+ CapabilityMap::const_iterator iter = mCapabilities.find(name);
+ if (iter == mCapabilities.end())
+ {
+ return "";
+ }
+ return iter->second;
+}
+//
+
+void LLAgent::showLureDestination(const std::string fromname, const int global_x, const int global_y, const int x, const int y, const int z, const std::string maturity)
+{
+ const LLVector3d posglobal = LLVector3d(F64(global_x), F64(global_y), F64(0));
+ LLSimInfo* siminfo;
+ siminfo = LLWorldMap::getInstance()->simInfoFromPosGlobal(posglobal);
+ if(siminfo)
+ {
+ llinfos << fromname << "'s teleport lure is to " << siminfo->getName() << " (" << maturity << ")" << llendl;
+ std::string url = LLURLDispatcher::buildSLURL(siminfo->getName(), S32(x), S32(y), S32(z));
+ std::string msg;
+ msg = llformat("%s's teleport lure is to %s", fromname.c_str(), url.c_str());
+ if(maturity != "")
+ msg.append(llformat(" (%s)", maturity.c_str()));
+ LLChat chat(msg);
+ LLFloaterChat::addChat(chat);
+ }
+ else
+ {
+ LLAgent::lure_show = TRUE;
+ LLAgent::lure_name = fromname;
+ LLAgent::lure_posglobal = posglobal;
+ LLAgent::lure_global_x = U16(global_x / 256);
+ LLAgent::lure_global_y = U16(global_y / 256);
+ LLAgent::lure_x = x;
+ LLAgent::lure_y = y;
+ LLAgent::lure_z = z;
+ LLAgent::lure_maturity = maturity;
+ LLWorldMapMessage::getInstance()->sendMapBlockRequest(lure_global_x, lure_global_y, lure_global_x, lure_global_y, true);
+ }
+}
+
+void LLAgent::onFoundLureDestination()
+{
+ LLAgent::lure_show = FALSE;
+ LLSimInfo* siminfo;
+ siminfo = LLWorldMap::getInstance()->simInfoFromPosGlobal(LLAgent::lure_posglobal);
+ if(siminfo)
+ {
+ llinfos << LLAgent::lure_name << "'s teleport lure is to " << siminfo->getName() << " (" << LLAgent::lure_maturity << ")" << llendl;
+ std::string url = LLURLDispatcher::buildSLURL(siminfo->getName(), S32(LLAgent::lure_x), S32(LLAgent::lure_y), S32(LLAgent::lure_z));
+ std::string msg;
+ msg = llformat("%s's teleport lure is to %s", LLAgent::lure_name.c_str(), url.c_str());
+ if(LLAgent::lure_maturity != "")
+ msg.append(llformat(" (%s)", LLAgent::lure_maturity.c_str()));
+ LLChat chat(msg);
+ LLFloaterChat::addChat(chat);
+ }
+ else
+ llwarns << "Grand scheme failed" << llendl;
+}
+
+//
+
+// EOF
+
diff --git a/indra/newview/llfloaterdickdongs.cpp b/indra/newview/llfloaterdickdongs.cpp
index d49a849c7..f9dbc64e1 100644
--- a/indra/newview/llfloaterdickdongs.cpp
+++ b/indra/newview/llfloaterdickdongs.cpp
@@ -44,7 +44,7 @@
//this is really the only thing that needs to be here atm
LLFloaterDickDongs::LLFloaterDickDongs(const LLSD& seed)
{
- LLUICtrlFactory::getInstance()->buildFloater(this, "floater_dickdongs.xml");
+ //LLUICtrlFactory::getInstance()->buildFloater(this, "floater_dickdongs.xml");
}
//Not needed yet
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index 820ba699b..ad98288b3 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -2646,10 +2646,10 @@ bool idle_startup()
LLFloaterActiveSpeakers::showInstance();
}
- if (gSavedSettings.getBOOL("BeaconAlwaysOn"))
+ /*if (gSavedSettings.getBOOL("BeaconAlwaysOn"))
{
- LLFloaterBeacons::showInstance();
- }
+ LLFloaterBeacons::showInstance(); DIE
+ }*/
if (!gSavedSettings.getBOOL("CloudsEnabled") && !gNoRender)
{
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index 2375d7255..4df22fea6 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -112,7 +112,8 @@
#include "llfloaterchat.h"
#include "llfloatercustomize.h"
#include "llfloaterdaycycle.h"
-#include "llfloaterdickdongs.h"
+//#include "llfloaterdickdongs.h" No need for the custom floater right now, I think. -HgB
+#include "ascentuploadbrowser.h" //New customer floater attempts
#include "llfloaterdirectory.h"
#include "llfloatereditui.h"
#include "llfloaterchatterbox.h"
@@ -6110,17 +6111,17 @@ class LLShowFloater : public view_listener_t
{
LLFloaterActiveSpeakers::toggleInstance(LLSD());
}
- else if (floater_name == "beacons")
+ /*else if (floater_name == "beacons")
{
- LLFloaterBeacons::toggleInstance(LLSD());
- }
+ LLFloaterBeacons::toggleInstance(LLSD()); NO
+ }*/
else if (floater_name == "perm prefs")
{
LLFloaterPerms::toggleInstance(LLSD());
}
- else if (floater_name == "dickdongs")
+ else if (floater_name == "ascentuploadbrowser")
{
- LLFloaterDickDongs::toggleInstance(LLSD());
+ ASFloaterUploadBrowser::show(NULL);
}
return true;
}
@@ -6177,14 +6178,14 @@ class LLFloaterVisible : public view_listener_t
{
new_value = LLFloaterActiveSpeakers::instanceVisible(LLSD());
}
- else if (floater_name == "beacons")
+ /*else if (floater_name == "beacons")
{
- new_value = LLFloaterBeacons::instanceVisible(LLSD());
+ new_value = LLFloaterBeacons::instanceVisible(LLSD()); Oh man fuck this floater so much.
}
else if (floater_name == "dickdongs")
{
- new_value = LLFloaterDickDongs::instanceVisible(LLSD());
- }
+ new_value = LLFloaterDickDongs::instanceVisible(LLSD()); Not needed any more.
+ }*/
else if (floater_name == "inventory")
{
LLInventoryView* iv = LLInventoryView::getActiveInventory();
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index aabb514ac..5311eb0ea 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -86,8 +86,7 @@
#include "llvoiceclient.h"
#include "llvoicevisualizer.h" // Ventrella
-
-#include "llsdserialize.h"
+#include "llsdserialize.h" //For the client definitions
//
#include "llfloaterexploreanimations.h"
#include "llao.h"
@@ -710,6 +709,9 @@ BOOL LLVOAvatar::sJointDebug = FALSE;
EmeraldGlobalBoobConfig LLVOAvatar::sBoobConfig;
+F32 LLVOAvatar::sAvMorphTime = 0.65f;
+
+
F32 LLVOAvatar::sUnbakedTime = 0.f;
F32 LLVOAvatar::sUnbakedUpdateTime = 0.f;
F32 LLVOAvatar::sGreyTime = 0.f;
@@ -1020,7 +1022,7 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,
//VTPause(); // VTune
mVoiceVisualizer->setVoiceEnabled( gVoiceClient->getVoiceEnabled( mID ) );
- mCurrentGesticulationLevel = 0;
+ mCurrentGesticulationLevel = 0;
}
@@ -1186,45 +1188,45 @@ void LLVOAvatar::dumpScratchTextureByteCount()
llinfos << "Scratch Texture GL: " << (sScratchTexBytes/1024) << "KB" << llendl;
}
+// static
+void LLVOAvatar::getMeshInfo (mesh_info_t* mesh_info)
+{
+ if (!mesh_info) return;
+ LLVOAvatarXmlInfo::mesh_info_list_t::iterator iter = sAvatarXmlInfo->mMeshInfoList.begin();
+ LLVOAvatarXmlInfo::mesh_info_list_t::iterator end = sAvatarXmlInfo->mMeshInfoList.end();
+ for (; iter != end; ++iter)
+ {
+ LLVOAvatarXmlInfo::LLVOAvatarMeshInfo* avatar_info = (*iter);
+ std::string type = avatar_info->mType;
+ S32 lod = avatar_info->mLOD;
+ std::string file = avatar_info->mMeshFileName;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ mesh_info_t::iterator iter_info = mesh_info->find(type);
+ if(iter_info == mesh_info->end())
+ {
+ lod_mesh_map_t lod_mesh;
+ lod_mesh.insert(std::pair(lod, file));
+ mesh_info->insert(std::pair(type, lod_mesh));
+ }
+ else
+ {
+ lod_mesh_map_t& lod_mesh = iter_info->second;
+ lod_mesh_map_t::iterator iter_lod = lod_mesh.find(lod);
+ if (iter_lod == lod_mesh.end())
+ {
+ lod_mesh.insert(std::pair(lod, file));
+ }
+ else
+ {
+ // Should never happen
+ llwarns << "Duplicate mesh LOD " << type << " " << lod << " " << file << llendl;
+ }
+ }
+ }
+ return;
+}
// static
@@ -1399,9 +1401,9 @@ if(gAuditTexture)
}
LLTexLayerSet::sHasCaches = FALSE;
}
-
- for( LLGLuint* namep = sScratchTexNames.getFirstData();
- namep;
+
+ for( LLGLuint* namep = sScratchTexNames.getFirstData();
+ namep;
namep = sScratchTexNames.getNextData() )
{
LLImageGL::deleteTextures(1, (U32 *)namep );
@@ -1427,7 +1429,7 @@ if(gAuditTexture)
// LLVOAvatar::initClass()
//------------------------------------------------------------------------
void LLVOAvatar::initClass()
-{
+{
std::string xmlFile;
xmlFile = gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,AVATAR_DEFAULT_CHAR) + "_lad.xml";
@@ -1439,7 +1441,7 @@ void LLVOAvatar::initClass()
// now sanity check xml file
LLXmlTreeNode* root = sXMLTree.getRoot();
- if (!root)
+ if (!root)
{
llerrs << "No root node found in avatar configuration file: " << xmlFile << llendl;
return;
@@ -1601,7 +1603,7 @@ void LLVOAvatar::getSpatialExtents(LLVector3& newMin, LLVector3& newMax)
LLPolyMesh* mesh = i->second;
for (S32 joint_num = 0; joint_num < mesh->mJointRenderData.count(); joint_num++)
{
- update_min_max(newMin, newMax,
+ update_min_max(newMin, newMax,
mesh->mJointRenderData[joint_num]->mWorldMatrix->getTranslation());
}
}
@@ -1609,7 +1611,7 @@ void LLVOAvatar::getSpatialExtents(LLVector3& newMin, LLVector3& newMax)
mPixelArea = LLPipeline::calcPixelArea((newMin+newMax)*0.5f, (newMax-newMin)*0.5f, *LLViewerCamera::getInstance());
//stretch bounding box by attachments
- for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
+ for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
iter != mAttachmentPoints.end();
++iter)
{
@@ -1633,9 +1635,9 @@ void LLVOAvatar::getSpatialExtents(LLVector3& newMin, LLVector3& newMax)
LLVector3 distance = (ext[1] - ext[0]);
// Only add the prim to spatial extents calculations if it isn't a megaprim.
- // max_attachment_span calculated at the start of the function
- // (currently 5 times our max prim size)
- if (distance.mV[0] < max_attachment_span
+ // max_attachment_span calculated at the start of the function
+ // (currently 5 times our max prim size)
+ if (distance.mV[0] < max_attachment_span
&& distance.mV[1] < max_attachment_span
&& distance.mV[2] < max_attachment_span)
{
@@ -1764,7 +1766,7 @@ BOOL LLVOAvatar::parseSkeletonFile(const std::string& filename)
// now sanity check xml file
LLXmlTreeNode* root = sSkeletonXMLTree.getRoot();
- if (!root)
+ if (!root)
{
llerrs << "No root node found in avatar skeleton file: " << filename << llendl;
}
@@ -2023,7 +2025,7 @@ void LLVOAvatar::buildCharacter()
//-------------------------------------------------------------------------
// Make sure "well known" pointers exist
//-------------------------------------------------------------------------
- if (!(mPelvisp &&
+ if (!(mPelvisp &&
mTorsop &&
mChestp &&
mNeckp &&
@@ -2119,7 +2121,7 @@ void LLVOAvatar::buildCharacter()
else
{
BOOL attachment_found = FALSE;
- for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
+ for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
iter != mAttachmentPoints.end(); )
{
attachment_map_t::iterator curiter = iter++;
@@ -2127,6 +2129,8 @@ void LLVOAvatar::buildCharacter()
if (attachment->getGroup() == i)
{
LLMenuItemCallGL* item;
+
+
item = new LLMenuItemCallGL(attachment->getName(),
NULL,
object_selected_and_point_valid);
@@ -2159,14 +2163,14 @@ void LLVOAvatar::buildCharacter()
else
{
BOOL attachment_found = FALSE;
- for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
+ for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
iter != mAttachmentPoints.end(); )
{
attachment_map_t::iterator curiter = iter++;
LLViewerJointAttachment* attachment = curiter->second;
if (attachment->getGroup() == i)
{
- gDetachPieMenu->append(new LLMenuItemCallGL(attachment->getName(),
+ gDetachPieMenu->append(new LLMenuItemCallGL(attachment->getName(),
&handle_detach_from_avatar, object_attached, attachment));
attachment_found = TRUE;
@@ -2182,7 +2186,7 @@ void LLVOAvatar::buildCharacter()
}
// add screen attachments
- for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
+ for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
iter != mAttachmentPoints.end(); )
{
attachment_map_t::iterator curiter = iter++;
@@ -2190,12 +2194,14 @@ void LLVOAvatar::buildCharacter()
if (attachment->getGroup() == 8)
{
LLMenuItemCallGL* item;
- item = new LLMenuItemCallGL(attachment->getName(),
- NULL,
+
+
+ item = new LLMenuItemCallGL(attachment->getName(),
+ NULL,
object_selected_and_point_valid);
item->addListener(gMenuHolder->getListenerByName("Object.AttachToAvatar"), "on_click", curiter->first);
gAttachScreenPieMenu->append(item);
- gDetachScreenPieMenu->append(new LLMenuItemCallGL(attachment->getName(),
+ gDetachScreenPieMenu->append(new LLMenuItemCallGL(attachment->getName(),
&handle_detach_from_avatar, object_attached, attachment));
}
}
@@ -2208,7 +2214,7 @@ void LLVOAvatar::buildCharacter()
for (S32 pass = 0; pass < 2; pass++)
{
- for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
+ for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
iter != mAttachmentPoints.end(); )
{
attachment_map_t::iterator curiter = iter++;
@@ -2218,13 +2224,13 @@ void LLVOAvatar::buildCharacter()
continue;
}
- LLMenuItemCallGL* item = new LLMenuItemCallGL(attachment->getName(),
+ LLMenuItemCallGL* item = new LLMenuItemCallGL(attachment->getName(),
NULL, &object_selected_and_point_valid,
&attach_label, attachment);
item->addListener(gMenuHolder->getListenerByName("Object.AttachToAvatar"), "on_click", curiter->first);
gAttachSubMenu->append(item);
- gDetachSubMenu->append(new LLMenuItemCallGL(attachment->getName(),
+ gDetachSubMenu->append(new LLMenuItemCallGL(attachment->getName(),
&handle_detach_from_avatar, object_attached, &detach_label, attachment));
}
@@ -2247,7 +2253,7 @@ void LLVOAvatar::buildCharacter()
std::multimap attachment_pie_menu_map;
// gather up all attachment points assigned to this group, and throw into map sorted by pie slice number
- for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
+ for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
iter != mAttachmentPoints.end(); )
{
attachment_map_t::iterator curiter = iter++;
@@ -2279,14 +2285,14 @@ void LLVOAvatar::buildCharacter()
{
- LLMenuItemCallGL* item = new LLMenuItemCallGL(attachment->getName(),
+ LLMenuItemCallGL* item = new LLMenuItemCallGL(attachment->getName(),
NULL, object_selected_and_point_valid);
gAttachBodyPartPieMenus[group]->append(item);
item->addListener(gMenuHolder->getListenerByName("Object.AttachToAvatar"), "on_click", attach_index);
- gDetachBodyPartPieMenus[group]->append(new LLMenuItemCallGL(attachment->getName(),
+ gDetachBodyPartPieMenus[group]->append(new LLMenuItemCallGL(attachment->getName(),
&handle_detach_from_avatar,
object_attached, attachment));
cur_pie_slice++;
@@ -2332,8 +2338,8 @@ void LLVOAvatar::releaseMeshData()
facep->setSize(0, 0);
}
}
-
- for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
+
+ for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
iter != mAttachmentPoints.end(); )
{
attachment_map_t::iterator curiter = iter++;
@@ -2363,7 +2369,7 @@ void LLVOAvatar::restoreMeshData()
}
else
{
- for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
+ for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
iter != mAttachmentPoints.end(); )
{
attachment_map_t::iterator curiter = iter++;
@@ -2415,12 +2421,12 @@ void LLVOAvatar::updateMeshData()
if(last_v_num > 0)//put the last inserted part into next vertex buffer.
{
num_vertices = last_v_num ;
- num_indices = last_i_num ;
+ num_indices = last_i_num ;
part_index-- ;
}
LLFace* facep ;
- if(f_num < mDrawable->getNumFaces())
+ if(f_num < mDrawable->getNumFaces())
{
facep = mDrawable->getFace(f_num);
}
@@ -2477,7 +2483,7 @@ void LLVOAvatar::updateMeshData()
//------------------------------------------------------------------------
// The viewer can only suggest a good size for the agent,
// the simulator will keep it inside a reasonable range.
-void LLVOAvatar::computeBodySize()
+void LLVOAvatar::computeBodySize()
{
LLVector3 pelvis_scale = mPelvisp->getScale();
@@ -2517,11 +2523,11 @@ void LLVOAvatar::computeBodySize()
mBodySize.mV[VZ] = mPelvisToFoot +
// the sqrt(2) correction below is an approximate
// correction to get to the top of the head
- F_SQRT2 * (skull.mV[VZ] * head_scale.mV[VZ]) +
- head.mV[VZ] * neck_scale.mV[VZ] +
- neck.mV[VZ] * chest_scale.mV[VZ] +
- chest.mV[VZ] * torso_scale.mV[VZ] +
- torso.mV[VZ] * pelvis_scale.mV[VZ];
+ F_SQRT2 * (skull.mV[VZ] * head_scale.mV[VZ]) +
+ head.mV[VZ] * neck_scale.mV[VZ] +
+ neck.mV[VZ] * chest_scale.mV[VZ] +
+ chest.mV[VZ] * torso_scale.mV[VZ] +
+ torso.mV[VZ] * pelvis_scale.mV[VZ];
// TODO -- measure the real depth and width
mBodySize.mV[VX] = DEFAULT_AGENT_DEPTH;
@@ -2644,7 +2650,7 @@ BOOL LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
// force asynchronous drawable update
if(mDrawable.notNull() && !gNoRender)
- {
+ {
LLFastTimer t(LLFastTimer::FTM_JOINT_UPDATE);
if (mIsSitting && getParent())
@@ -2664,7 +2670,7 @@ BOOL LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
}
}
}
- else
+ else
{
gPipeline.updateMoveDampedAsync(mDrawable);
}
@@ -2739,7 +2745,7 @@ void LLVOAvatar::idleUpdateVoiceVisualizer(bool voice_enabled)
// disable voice visualizer when in mouselook
mVoiceVisualizer->setVoiceEnabled( voice_enabled && !(mIsSelf && gAgent.cameraMouselook()) );
if ( voice_enabled )
- {
+ {
//----------------------------------------------------------------
// Only do gesture triggering for your own avatar, and only when you're in a proximal channel.
//----------------------------------------------------------------
@@ -2779,7 +2785,7 @@ void LLVOAvatar::idleUpdateVoiceVisualizer(bool voice_enabled)
// "away", so that the avatar doesn't lapse into away-mode (and slump over) while the user is still talking.
//-----------------------------------------------------------------------------------------------------------------
if ( gVoiceClient->getIsSpeaking( mID ) )
- {
+ {
if ( ! mVoiceVisualizer->getCurrentlySpeaking() )
{
mVoiceVisualizer->setStartSpeaking();
@@ -2821,7 +2827,7 @@ void LLVOAvatar::idleUpdateVoiceVisualizer(bool voice_enabled)
mVoiceVisualizer->setVoiceSourceWorldPosition( mRoot.getWorldPosition() + headOffset );
}//if ( voiceEnabled )
-}
+}
void LLVOAvatar::idleUpdateMisc(bool detailed_update)
{
@@ -2845,14 +2851,14 @@ void LLVOAvatar::idleUpdateMisc(bool detailed_update)
if (detailed_update || !sUseImpostors)
{
LLFastTimer t(LLFastTimer::FTM_ATTACHMENT_UPDATE);
- for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
+ for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
iter != mAttachmentPoints.end(); )
{
attachment_map_t::iterator curiter = iter++;
LLViewerJointAttachment* attachment = curiter->second;
LLViewerObject *attached_object = attachment->getObject();
- BOOL visibleAttachment = visible || (attached_object &&
+ BOOL visibleAttachment = visible || (attached_object &&
!(attached_object->mDrawable->getSpatialBridge() &&
attached_object->mDrawable->getSpatialBridge()->getRadius() < 2.0));
@@ -2873,7 +2879,7 @@ void LLVOAvatar::idleUpdateMisc(bool detailed_update)
{
gPipeline.updateMoveNormalAsync(bridge);
}
- attached_object->updateText();
+ attached_object->updateText();
}
}
}
@@ -2937,10 +2943,10 @@ void LLVOAvatar::idleUpdateAppearanceAnimation()
{
ESex avatar_sex = getSex();
F32 appearance_anim_time = mAppearanceMorphTimer.getElapsedTimeF32();
- if (appearance_anim_time >= APPEARANCE_MORPH_TIME)
+ if (appearance_anim_time >= sAvMorphTime)
{
mAppearanceAnimating = FALSE;
- for (LLVisualParam *param = getFirstVisualParam();
+ for (LLVisualParam *param = getFirstVisualParam();
param;
param = getNextVisualParam())
{
@@ -2958,15 +2964,15 @@ void LLVOAvatar::idleUpdateAppearanceAnimation()
}
else
{
- F32 blend_frac = calc_bouncy_animation(appearance_anim_time / APPEARANCE_MORPH_TIME);
- F32 last_blend_frac = calc_bouncy_animation(mLastAppearanceBlendTime / APPEARANCE_MORPH_TIME);
+ F32 blend_frac = calc_bouncy_animation(appearance_anim_time / sAvMorphTime);
+ F32 last_blend_frac = calc_bouncy_animation(mLastAppearanceBlendTime / sAvMorphTime);
F32 morph_amt;
-
-
-
-
-
-
+ // if it's over 5 seconds, just forget the bouncy anim
+ if(sAvMorphTime > 5.f)
+ {
+ blend_frac = appearance_anim_time / sAvMorphTime;
+ last_blend_frac = mLastAppearanceBlendTime / sAvMorphTime;
+ }
if (last_blend_frac == 1.f)
{
morph_amt = 1.f;
@@ -3027,7 +3033,6 @@ void LLVOAvatar::idleUpdateBoobEffect()
EmeraldBoobState newBoobState = EmeraldBoobUtils::idleUpdate(sBoobConfig, mLocalBoobConfig, mBoobState, boobInputs);
-
if(mBoobState.boobGrav != newBoobState.boobGrav)
{
LLVisualParam *param;
@@ -3179,7 +3184,7 @@ void LLVOAvatar::idleUpdateLoadingEffect()
setParticleSource(particle_parameters, getID());
}
}
-}
+}
void LLVOAvatar::idleUpdateWindEffect()
@@ -3225,7 +3230,7 @@ void LLVOAvatar::idleUpdateWindEffect()
mWindVec = lerp(mWindVec, wind, interp);
F32 wind_freq = hover_strength + llclamp(8.f + (speed * 0.7f) + (noise1(mRipplePhase) * 4.f), 8.f, 25.f);
- mWindFreq = lerp(mWindFreq, wind_freq, interp);
+ mWindFreq = lerp(mWindFreq, wind_freq, interp);
if (mBelowWater)
{
@@ -3440,7 +3445,8 @@ void LLVOAvatar::getClientInfo(std::string& client, LLColor4& color, BOOL useCom
color = LLColor4(0.5f, 0.0f, 0.0f);
client = "Unknown";
}
- else if (LLVOAvatar::sClientResolutionList.has("isComplete") && LLVOAvatar::sClientResolutionList.has(uuid_str)) {
+ else if (LLVOAvatar::sClientResolutionList.has("isComplete") && LLVOAvatar::sClientResolutionList.has(uuid_str))
+ {
LLSD cllsd = LLVOAvatar::sClientResolutionList[uuid_str];
client = cllsd["name"].asString();
LLColor4 colour;
@@ -3499,6 +3505,43 @@ void LLVOAvatar::getClientInfo(std::string& client, LLColor4& color, BOOL useCom
}
}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
LLColor4 LLVOAvatar::getTagColorByUUID(std::string uuid_str)
{
if (uuid_str == "0bcd5f5d-a4ce-9ea4-f9e8-15132653b3d8")
@@ -5631,7 +5674,7 @@ void LLVOAvatar::processAnimationStateChanges()
stop_glerror();
}
-//Here's that undeform function I was talking about. -HGB
+//Here's that undeform function I was talking about. -HgB
/* Bug-fixed Linden Labs style. Comment out 4ever.
std::string undeformers[] =
{
@@ -6196,7 +6239,7 @@ BOOL LLVOAvatar::allocateCollisionVolumes( U32 num )
//-----------------------------------------------------------------------------
LLJoint *LLVOAvatar::getCharacterJoint( U32 num )
{
- if ((S32)num >= mNumJoints
+ if ((S32)num >= mNumJoints
|| (S32)num < 0)
{
return NULL;
@@ -6412,7 +6455,7 @@ BOOL LLVOAvatar::loadSkeletonNode ()
else
{
addVisualParam(param);
- }
+ }
}
}
@@ -6500,7 +6543,7 @@ BOOL LLVOAvatar::loadSkeletonNode ()
BOOL LLVOAvatar::loadMeshNodes()
{
for (LLVOAvatarXmlInfo::mesh_info_list_t::const_iterator meshinfo_iter = sAvatarXmlInfo->mMeshInfoList.begin();
- meshinfo_iter != sAvatarXmlInfo->mMeshInfoList.end();
+ meshinfo_iter != sAvatarXmlInfo->mMeshInfoList.end();
meshinfo_iter++)
{
const LLVOAvatarXmlInfo::LLVOAvatarMeshInfo *info = *meshinfo_iter;
@@ -6541,7 +6584,7 @@ BOOL LLVOAvatar::loadMeshNodes()
return FALSE;
}
}
- else
+ else
{
llwarns << "Ignoring unrecognized mesh type: " << type << llendl;
return FALSE;
@@ -6588,7 +6631,7 @@ BOOL LLVOAvatar::loadMeshNodes()
mesh->setLOD( info->mMinPixelArea );
for (LLVOAvatarXmlInfo::LLVOAvatarMeshInfo::morph_info_list_t::const_iterator xmlinfo_iter = info->mPolyMorphTargetInfoList.begin();
- xmlinfo_iter != info->mPolyMorphTargetInfoList.end();
+ xmlinfo_iter != info->mPolyMorphTargetInfoList.end();
xmlinfo_iter++)
{
const LLVOAvatarXmlInfo::LLVOAvatarMeshInfo::morph_info_pair_t *info_pair = &(*xmlinfo_iter);
@@ -6608,7 +6651,7 @@ BOOL LLVOAvatar::loadMeshNodes()
{
addVisualParam(param);
}
- }
+ }
}
}
@@ -6825,7 +6868,7 @@ void LLVOAvatar::updateShadowFaces()
LLVector3 joint_world_pos = mFootLeftp->getWorldPosition();
// this only does a ray straight down from the foot, as our client-side ray-tracing is very limited now
// but we make an explicit ray trace call in expectation of future improvements
- resolveRayCollisionAgent(gAgent.getPosGlobalFromAgent(joint_world_pos),
+ resolveRayCollisionAgent(gAgent.getPosGlobalFromAgent(joint_world_pos),
gAgent.getPosGlobalFromAgent(gSky.getSunDirection() + joint_world_pos), shadow_pos, normal);
shadow_pos_agent = gAgent.getPosAgentFromGlobal(shadow_pos);
foot_height = joint_world_pos.mV[VZ] - shadow_pos_agent.mV[VZ];
@@ -6858,7 +6901,7 @@ void LLVOAvatar::updateShadowFaces()
LLVector3 joint_world_pos = mFootRightp->getWorldPosition();
// this only does a ray straight down from the foot, as our client-side ray-tracing is very limited now
// but we make an explicit ray trace call in expectation of future improvements
- resolveRayCollisionAgent(gAgent.getPosGlobalFromAgent(joint_world_pos),
+ resolveRayCollisionAgent(gAgent.getPosGlobalFromAgent(joint_world_pos),
gAgent.getPosGlobalFromAgent(gSky.getSunDirection() + joint_world_pos), shadow_pos, normal);
shadow_pos_agent = gAgent.getPosAgentFromGlobal(shadow_pos);
foot_height = joint_world_pos.mV[VZ] - shadow_pos_agent.mV[VZ];
@@ -6915,22 +6958,6 @@ void LLVOAvatar::hideSkirt()
mMeshLOD[MESH_ID_SKIRT]->setVisible(FALSE, TRUE);
}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
//-----------------------------------------------------------------------------
// requestLayerSetUpdate()
//-----------------------------------------------------------------------------
@@ -7090,7 +7117,7 @@ void LLVOAvatar::lazyAttach()
void LLVOAvatar::resetHUDAttachments()
{
- for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
+ for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
iter != mAttachmentPoints.end(); )
{
attachment_map_t::iterator curiter = iter++;
@@ -7111,7 +7138,7 @@ void LLVOAvatar::resetHUDAttachments()
//-----------------------------------------------------------------------------
BOOL LLVOAvatar::detachObject(LLViewerObject *viewer_object)
{
- for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
+ for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
iter != mAttachmentPoints.end(); )
{
attachment_map_t::iterator curiter = iter++;
@@ -7284,7 +7311,7 @@ void LLVOAvatar::getOffObject()
LLViewerObject* sit_object = (LLViewerObject*)getParent();
- if (sit_object)
+ if (sit_object)
{
stopMotionFromSource(sit_object->getID());
LLFollowCamMgr::setCameraActive(sit_object->getID(), FALSE);
@@ -7306,7 +7333,7 @@ void LLVOAvatar::getOffObject()
// set *local* position based on last *world* position, since we're unparenting the avatar
mDrawable->mXform.setPosition(cur_position_world);
- mDrawable->mXform.setRotation(cur_rotation_world);
+ mDrawable->mXform.setRotation(cur_rotation_world);
gPipeline.markMoved(mDrawable, TRUE);
@@ -7386,7 +7413,7 @@ LLVOAvatar* LLVOAvatar::findAvatarFromAttachment( LLViewerObject* obj )
//-----------------------------------------------------------------------------
BOOL LLVOAvatar::isWearingAttachment( const LLUUID& inv_item_id )
{
- for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
+ for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
iter != mAttachmentPoints.end(); )
{
attachment_map_t::iterator curiter = iter++;
@@ -7417,7 +7444,7 @@ BOOL LLVOAvatar::isWearingUnsupportedAttachment( const LLUUID& inv_item_id )
//-----------------------------------------------------------------------------
LLViewerObject* LLVOAvatar::getWornAttachment( const LLUUID& inv_item_id )
{
- for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
+ for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
iter != mAttachmentPoints.end(); )
{
attachment_map_t::iterator curiter = iter++;
@@ -7432,7 +7459,7 @@ LLViewerObject* LLVOAvatar::getWornAttachment( const LLUUID& inv_item_id )
const std::string LLVOAvatar::getAttachedPointName(const LLUUID& inv_item_id)
{
- for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
+ for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
iter != mAttachmentPoints.end(); )
{
attachment_map_t::iterator curiter = iter++;
@@ -7528,7 +7555,7 @@ void LLVOAvatar::updateComposites()
{
for (U32 i = 0; i < mBakedTextureData.size(); i++)
{
- if ( mBakedTextureData[i].mTexLayerSet
+ if ( mBakedTextureData[i].mTexLayerSet
&& ((i != BAKED_SKIRT) || isWearingWearableType( WT_SKIRT )) )
{
mBakedTextureData[i].mTexLayerSet->updateComposite();
@@ -8017,7 +8044,7 @@ LLGLuint LLVOAvatar::getScratchTexName( LLGLenum format, U32* texture_bytes )
stop_glerror();
LLImageGL::setManualImage(
- GL_TEXTURE_2D, 0, internal_format,
+ GL_TEXTURE_2D, 0, internal_format,
SCRATCH_TEX_WIDTH, SCRATCH_TEX_HEIGHT,
format, GL_UNSIGNED_BYTE, NULL );
stop_glerror();
@@ -8137,9 +8164,9 @@ void LLVOAvatar::updateMeshTextures()
// When an avatar is changing clothes and not in Appearance mode,
// use the last-known good baked texture until it finish the first
// render of the new layerset.
- use_lkg_baked_layer[i] = (!is_layer_baked[i]
- && (mBakedTextureData[i].mLastTextureIndex != IMG_DEFAULT_AVATAR)
- && mBakedTextureData[i].mTexLayerSet
+ use_lkg_baked_layer[i] = (!is_layer_baked[i]
+ && (mBakedTextureData[i].mLastTextureIndex != IMG_DEFAULT_AVATAR)
+ && mBakedTextureData[i].mTexLayerSet
&& !mBakedTextureData[i].mTexLayerSet->getComposite()->isInitialized());
if (use_lkg_baked_layer[i])
{
@@ -8148,7 +8175,7 @@ void LLVOAvatar::updateMeshTextures()
}
else
{
- use_lkg_baked_layer[i] = (!is_layer_baked[i]
+ use_lkg_baked_layer[i] = (!is_layer_baked[i]
&& mBakedTextureData[i].mLastTextureIndex != IMG_DEFAULT_AVATAR);
if (mBakedTextureData[i].mTexLayerSet)
{
@@ -8192,7 +8219,7 @@ void LLVOAvatar::updateMeshTextures()
mBakedTextureData[i].mIsLoaded = FALSE;
if ((baked_img->getID() != IMG_INVISIBLE) && (i == BAKED_HEAD || i == BAKED_UPPER || i == BAKED_LOWER))
{
- baked_img->setLoadedCallback(onBakedTextureMasksLoaded, MORPH_MASK_REQUESTED_DISCARD, TRUE, TRUE, new LLTextureMaskData( mID ));
+ baked_img->setLoadedCallback(onBakedTextureMasksLoaded, MORPH_MASK_REQUESTED_DISCARD, TRUE, TRUE, new LLTextureMaskData( mID ));
}
baked_img->setLoadedCallback(onBakedTextureLoaded, SWITCH_TO_BAKED_DISCARD, FALSE, FALSE, new LLUUID( mID ) );
}
@@ -8203,7 +8230,7 @@ void LLVOAvatar::updateMeshTextures()
{
mBakedTextureData[i].mTexLayerSet->createComposite();
mBakedTextureData[i].mTexLayerSet->setUpdatesEnabled( TRUE );
- mBakedTextureData[i].mIsUsed = FALSE;
+ mBakedTextureData[i].mIsUsed = FALSE;
for (U32 k=0; k < mBakedTextureData[i].mMeshes.size(); k++)
{
mBakedTextureData[i].mMeshes[k]->setLayerSet( mBakedTextureData[i].mTexLayerSet );
@@ -8224,8 +8251,8 @@ void LLVOAvatar::updateMeshTextures()
mBakedTextureData[BAKED_HAIR].mMeshes[i]->setTexture( hair_img );
}
mHasBakedHair = FALSE;
- }
- else
+ }
+ else
{
mHasBakedHair = TRUE;
}
@@ -8460,7 +8487,7 @@ ETextureIndex LLVOAvatar::getBakedTE( LLTexLayerSet* layerset )
void LLVOAvatar::setNewBakedTexture( ETextureIndex te, const LLUUID& uuid )
{
// Baked textures live on other sims.
- LLHost target_host = getObjectHost();
+ LLHost target_host = getObjectHost();
setTEImage( te, gImageList.getImageFromHost( uuid, target_host ) );
if (uuid != IMG_INVISIBLE)
{
@@ -8574,8 +8601,8 @@ void LLVOAvatar::releaseUnnecessaryTextures()
//-----------------------------------------------------------------------------
void LLVOAvatar::onCustomizeStart()
{
- // We're no longer doing any baking or invalidating on entering
- // appearance editing mode. Leaving function in place in case
+ // We're no longer doing any baking or invalidating on entering
+ // appearance editing mode. Leaving function in place in case
// further changes require us to do something at this point - Nyx
}
@@ -8706,7 +8733,7 @@ LLColor4 LLVOAvatar::getClothesColor( ETextureIndex te )
void LLVOAvatar::dumpAvatarTEs( const std::string& context )
-{
+{
/* const char* te_name[] = {
"TEX_HEAD_BODYPAINT ",
"TEX_UPPER_SHIRT ", */
@@ -8749,7 +8776,7 @@ void LLVOAvatar::dumpAvatarTEs( const std::string& context )
//-----------------------------------------------------------------------------
void LLVOAvatar::updateAttachmentVisibility(U32 camera_mode)
{
- for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
+ for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
iter != mAttachmentPoints.end(); )
{
attachment_map_t::iterator curiter = iter++;
@@ -8930,7 +8957,7 @@ void LLVOAvatar::wearableUpdated(EWearableType type, BOOL upload_result)
invalidateComposite(mBakedTextureData[index].mTexLayerSet, upload_result);
updateMeshTextures();
}
- break;
+ break;
}
}
}
@@ -8947,7 +8974,7 @@ void LLVOAvatar::clampAttachmentPositions()
{
return;
}
- for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
+ for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
iter != mAttachmentPoints.end(); )
{
attachment_map_t::iterator curiter = iter++;
@@ -8961,7 +8988,7 @@ void LLVOAvatar::clampAttachmentPositions()
BOOL LLVOAvatar::hasHUDAttachment() const
{
- for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin();
+ for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin();
iter != mAttachmentPoints.end(); )
{
attachment_map_t::const_iterator curiter = iter++;
@@ -8977,7 +9004,7 @@ BOOL LLVOAvatar::hasHUDAttachment() const
LLBBox LLVOAvatar::getHUDBBox() const
{
LLBBox bbox;
- for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin();
+ for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin();
iter != mAttachmentPoints.end(); )
{
attachment_map_t::const_iterator curiter = iter++;
@@ -9082,7 +9109,7 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )
// prevent the overwriting of valid baked textures with invalid baked textures
for (U8 baked_index = 0; baked_index < mBakedTextureData.size(); baked_index++)
{
- if (!isTextureDefined(mBakedTextureData[baked_index].mTextureIndex)
+ if (!isTextureDefined(mBakedTextureData[baked_index].mTextureIndex)
&& mBakedTextureData[baked_index].mLastTextureIndex != IMG_DEFAULT
&& baked_index != BAKED_SKIRT)
{
@@ -9148,22 +9175,22 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )
mesgsys->getU8Fast(_PREHASH_VisualParam, _PREHASH_ParamValue, value, i);
F32 newWeight = U8_to_F32(value, param->getMinWeight(), param->getMaxWeight());
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ if(param->getID() == 507 && newWeight != getActualBoobGrav())
+ {
+ llwarns << "Boob Grav SET to " << newWeight << " for " << getFullname() << llendl;
+ setActualBoobGrav(newWeight);
+ }
+ /*if(param->getID() == 795 && newWeight != getActualButtGrav())
+ {
+ llwarns << "Butt Grav SET to " << newWeight << " for " << getFullname() << llendl;
+ setActualButtGrav(newWeight);
+ }
+ if(param->getID() == 157 && newWeight != getActualFatGrav())
+ {
+ llwarns << "Fat Grav SET to " << newWeight << " for " << getFullname() << llendl;
+ setActualFatGrav(newWeight);
+ }
+ */
if (is_first_appearance_message || (param->getWeight() != newWeight))
@@ -9206,7 +9233,7 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )
if( old_sex != new_sex )
{
updateSexDependentLayerSets( FALSE );
- }
+ }
}
}
else
@@ -9282,7 +9309,7 @@ void LLVOAvatar::onBakedTextureMasksLoaded( BOOL success, LLViewerImage *src_vi,
stop_glerror();
LLImageGL::setManualImage(
- GL_TEXTURE_2D, 0, GL_ALPHA8,
+ GL_TEXTURE_2D, 0, GL_ALPHA8,
aux_src->getWidth(), aux_src->getHeight(),
GL_ALPHA, GL_UNSIGNED_BYTE, aux_src->getData());
stop_glerror();
@@ -9462,7 +9489,7 @@ void LLVOAvatar::dumpArchetypeXML( void* )
for( LLVisualParam* param = avatar->getFirstVisualParam(); param; param = avatar->getNextVisualParam() )
{
LLViewerVisualParam* viewer_param = (LLViewerVisualParam*)param;
- if( (viewer_param->getWearableType() == type) &&
+ if( (viewer_param->getWearableType() == type) &&
(viewer_param->getGroup() == VISUAL_PARAM_GROUP_TWEAKABLE) )
{
apr_file_printf( file, "\t\t\n",
@@ -9551,7 +9578,7 @@ void LLVOAvatar::cullAvatarsByPixelArea()
{
culled = FALSE;
}
- else
+ else
{
culled = TRUE;
}
@@ -9717,7 +9744,7 @@ void LLVOAvatar::dumpLocalTextures()
llinfos << "LocTex " << name << ": "
<< "Discard " << image->getDiscardLevel() << ", "
- << "(" << image->getWidth() << ", " << image->getHeight() << ") "
+ << "(" << image->getWidth() << ", " << image->getHeight() << ") "
#if !LL_RELEASE_FOR_DOWNLOAD
// End users don't get to trivially see avatar texture IDs,
// makes textures easier to steal
@@ -9747,7 +9774,7 @@ void LLVOAvatar::startAppearanceAnimation(BOOL set_by_user, BOOL play_sound)
void LLVOAvatar::removeMissingBakedTextures()
-{
+{
if (!mIsSelf) return;
BOOL removed = FALSE;
@@ -9785,13 +9812,13 @@ LLVOAvatarXmlInfo::LLVOAvatarXmlInfo()
LLVOAvatarXmlInfo::~LLVOAvatarXmlInfo()
{
std::for_each(mMeshInfoList.begin(), mMeshInfoList.end(), DeletePointer());
- std::for_each(mSkeletalDistortionInfoList.begin(), mSkeletalDistortionInfoList.end(), DeletePointer());
+ std::for_each(mSkeletalDistortionInfoList.begin(), mSkeletalDistortionInfoList.end(), DeletePointer());
std::for_each(mAttachmentInfoList.begin(), mAttachmentInfoList.end(), DeletePointer());
delete mTexSkinColorInfo;
delete mTexHairColorInfo;
delete mTexEyeColorInfo;
- std::for_each(mLayerInfoList.begin(), mLayerInfoList.end(), DeletePointer());
- std::for_each(mDriverInfoList.begin(), mDriverInfoList.end(), DeletePointer());
+ std::for_each(mLayerInfoList.begin(), mLayerInfoList.end(), DeletePointer());
+ std::for_each(mDriverInfoList.begin(), mDriverInfoList.end(), DeletePointer());
}
//-----------------------------------------------------------------------------
@@ -10249,8 +10276,8 @@ std::string LLVOAvatar::getFullname() const
{
std::string name;
- LLNameValue* first = getNVPair("FirstName");
- LLNameValue* last = getNVPair("LastName");
+ LLNameValue* first = getNVPair("FirstName");
+ LLNameValue* last = getNVPair("LastName");
if (first && last)
{
name += first->getString();
@@ -10338,7 +10365,7 @@ U32 LLVOAvatar::getPartitionType() const
}
//static
-void LLVOAvatar::updateImpostors()
+void LLVOAvatar::updateImpostors()
{
for (std::vector::iterator iter = LLCharacter::sInstances.begin();
iter != LLCharacter::sInstances.end(); ++iter)
@@ -10409,7 +10436,7 @@ void LLVOAvatar::idleUpdateRenderCost()
std::set textures;
attachment_map_t::const_iterator iter;
- for (iter = mAttachmentPoints.begin();
+ for (iter = mAttachmentPoints.begin();
iter != mAttachmentPoints.end();
++iter)
{
diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h
index a01ccd855..fcf3418ed 100644
--- a/indra/newview/llvoavatar.h
+++ b/indra/newview/llvoavatar.h
@@ -374,10 +374,10 @@ public:
void setLocTexTE( U8 te, LLViewerImage* image, BOOL set_by_user );
void setupComposites();
+ typedef std::map lod_mesh_map_t;
+ typedef std::map mesh_info_t;
-
-
-
+ static void getMeshInfo (mesh_info_t* mesh_info);
//--------------------------------------------------------------------
// Handling partially loaded avatars (Ruth)
@@ -608,7 +608,7 @@ public:
static F32 sLODFactor; // user-settable LOD factor
static BOOL sJointDebug; // output total number of joints being touched for each avatar
static BOOL sDebugAvatarRotation;
-
+ static F32 sAvMorphTime;
static S32 sNumVisibleAvatars; // Number of instances of this class
diff --git a/indra/newview/llwearable.cpp b/indra/newview/llwearable.cpp
index 99979981d..d95d4086e 100644
--- a/indra/newview/llwearable.cpp
+++ b/indra/newview/llwearable.cpp
@@ -556,9 +556,54 @@ BOOL LLWearable::isDirty()
weight = llclamp( weight, param->getMinWeight(), param->getMaxWeight() );
U8 a = F32_to_U8( param->getWeight(), param->getMinWeight(), param->getMaxWeight() );
- U8 b = F32_to_U8( weight, param->getMinWeight(), param->getMaxWeight() );
+
+ if(avatar->getAppearanceFlag() == true)
+ {
+ //boob
+ if(param->getID() == 507)
+ {
+ weight = get_if_there(mVisualParamMap, param->getID(), avatar->getActualBoobGrav());
+ weight = llclamp( weight, param->getMinWeight(), param->getMaxWeight() );
+ }
+ /*//butt
+ if(param->getID() == 795)
+ {
+ weight = get_if_there(mVisualParamMap, param->getID(), avatar->getActualButtGrav());
+ weight = llclamp( weight, param->getMinWeight(), param->getMaxWeight() );
+ }
+ //fat
+ if(param->getID() == 157)
+ {
+ weight = get_if_there(mVisualParamMap, param->getID(), avatar->getActualFatGrav());
+ weight = llclamp( weight, param->getMinWeight(), param->getMaxWeight() );
+ }
+ */
+ }
+ else
+ {
+ //boob
+ if(param->getID() == 507)
+ {
+ a = F32_to_U8( avatar->getActualBoobGrav(), param->getMinWeight(), param->getMaxWeight() );
+ }
+ /*//butt
+ if(param->getID() == 795)
+ {
+ a = F32_to_U8( avatar->getActualButtGrav(), param->getMinWeight(), param->getMaxWeight() );
+ }
+ //fat
+ if(param->getID() == 157)
+ {
+ a = F32_to_U8( avatar->getActualFatGrav(), param->getMinWeight(), param->getMaxWeight() );
+ }
+ */
+ }
+
+
+ U8 b = F32_to_U8( weight, param->getMinWeight(), param->getMaxWeight() );
if( a != b )
{
+ llwarns << "param ID " << param->getID() << " was changed." << llendl;
return TRUE;
}
}
@@ -644,6 +689,16 @@ void LLWearable::writeToAvatar( BOOL set_by_user )
{
S32 param_id = param->getID();
F32 weight = get_if_there(mVisualParamMap, param_id, param->getDefaultWeight());
+
+ //ZOMG: When switching shapes from inventory
+ if(param_id == 507)
+ avatar->setActualBoobGrav(weight);
+ /*if(param_id == 795)
+ avatar->setActualButtGrav(weight);
+ if(param_id == 157)
+ avatar->setActualFatGrav(weight);
+ */
+
// only animate with user-originated changes
if (set_by_user)
{
@@ -781,6 +836,22 @@ void LLWearable::readFromAvatar()
{
if( (((LLViewerVisualParam*)param)->getWearableType() == mType) && (param->getGroup() == VISUAL_PARAM_GROUP_TWEAKABLE ) )
{
+
+ //pretty sure is right
+ if(param->getID() == 507)
+ avatar->setActualBoobGrav(param->getWeight());
+ /*if(param->getID() == 151)
+ avatar->setActualButtGrav(param->getWeight());
+ if(param->getID() == 157)
+ avatar->setActualFatGrav(param->getWeight());
+ */
+ //if(param->getID() == 507)
+ //{
+ // llwarns << "current = " << avatar->getActualBoobGrav() << llendl;
+ // llwarns << "param weight = " << param->getWeight() << llendl;
+ //}
+
+
mVisualParamMap[param->getID()] = param->getWeight();
}
}
@@ -832,6 +903,27 @@ void LLWearable::copyDataFrom( LLWearable* src )
{
S32 id = param->getID();
F32 weight = get_if_there(src->mVisualParamMap, id, param->getDefaultWeight() );
+ //llwarns << "------------------------------" << llendl;
+ //llwarns << "copydatafrom" << llendl;
+ //llwarns << "------------------------------" << llendl;
+
+ //if(id == 507)
+ //{
+ // llwarns << "weight = " << weight << llendl;
+ // llwarns << "actual = " << avatar->getActualBoobGrav() << llendl;
+ // llwarns << "mVisualParamMap[id] = " << mVisualParamMap[id] << llendl;
+ //}
+
+ //pretty sure right
+ if(id == 507)
+ avatar->setActualBoobGrav(weight);
+ /*if(id == 795)
+ avatar->setActualButtGrav(weight);
+ if(id == 157)
+ avatar->setActualFatGrav(weight);
+ */
+
+
mVisualParamMap[id] = weight;
}
}
diff --git a/indra/newview/skins/default/xui/en-us/floater_about_land.xml b/indra/newview/skins/default/xui/en-us/floater_about_land.xml
index 84a9e2ab2..6db25321b 100644
--- a/indra/newview/skins/default/xui/en-us/floater_about_land.xml
+++ b/indra/newview/skins/default/xui/en-us/floater_about_land.xml
@@ -537,7 +537,7 @@ Go to World menu > About Land or select another parcel to show its details.
column_padding="0" draw_border="true" draw_heading="true"
draw_stripes="true" enabled="true"
follows="left|top|right|bottom" height="117" left="4" mouse_opaque="true"
- multi_select="false" name="owner list" name_column_index="2" width="450">
+ multi_select="true" name="owner list" name_column_index="2" width="450">
diff --git a/indra/newview/skins/default/xui/en-us/menu_viewer.xml b/indra/newview/skins/default/xui/en-us/menu_viewer.xml
index d8876ccb1..e22641df7 100644
--- a/indra/newview/skins/default/xui/en-us/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en-us/menu_viewer.xml
@@ -73,6 +73,11 @@
mouse_opaque="true" name="Quit" shortcut="control|Q" width="243">
+
+
+
+
@@ -265,8 +278,8 @@
tool_tip="" name="AscentCmdLineMapTo" control_name="AscentCmdLineMapTo" width="200"/>
+ name="AscentMapToKeepPos" radio_style="false" width="270"
+ control_name="AscentMapToKeepPos"/>
Teleport to avatar (usage: cmd name)
@@ -294,6 +307,12 @@
tool_tip="Turns off broadcasting headturns and lookat beacons for yourself."
mouse_opaque="true" name="private_look_at_check" radio_style="false"
width="400" />
+
-
-
+
-
-
-
-
-
-
-
+
@@ -153,5 +130,31 @@
mouse_opaque="true" name="effect_color_swatch"
tool_tip="Click to open Color Picker" width="32" />
+
+
+
+
+
+
+
+