llagent.cpp

Go to the documentation of this file.
00001 
00032 #include "llviewerprecompiledheaders.h"
00033 
00034 #include "stdtypes.h"
00035 #include "stdenums.h"
00036 
00037 #include "llagent.h" 
00038 
00039 #include "llcoordframe.h"
00040 #include "indra_constants.h"
00041 #include "llmath.h"
00042 #include "llcriticaldamp.h"
00043 #include "llfocusmgr.h"
00044 #include "llglheaders.h"
00045 #include "llparcel.h"
00046 #include "llpermissions.h"
00047 #include "llregionhandle.h"
00048 #include "m3math.h"
00049 #include "m4math.h"
00050 #include "message.h"
00051 #include "llquaternion.h"
00052 #include "v3math.h"
00053 #include "v4math.h"
00054 #include "llsdutil.h"
00055 //#include "vmath.h"
00056 
00057 #include "imageids.h"
00058 #include "llbox.h"
00059 #include "llbutton.h"
00060 #include "llcameraview.h"
00061 #include "llcallingcard.h"
00062 #include "llchatbar.h"
00063 #include "llconsole.h"
00064 #include "lldrawable.h"
00065 #include "llface.h"
00066 #include "llfirstuse.h"
00067 #include "llfloater.h"
00068 #include "llfloateractivespeakers.h"
00069 #include "llfloateravatarinfo.h"
00070 #include "llfloateravatarlist.h"
00071 #include "llfloaterbuildoptions.h"
00072 #include "llfloaterchat.h"
00073 #include "llfloatercustomize.h"
00074 #include "llfloaterdirectory.h"
00075 #include "llfloatergroupinfo.h"
00076 #include "llfloatergroups.h"
00077 #include "llfloatermap.h"
00078 #include "llfloatermute.h"
00079 #include "llfloatersnapshot.h"
00080 #include "llfloatertools.h"
00081 #include "llfloaterworldmap.h"
00082 #include "llgroupmgr.h"
00083 #include "llhudeffectlookat.h"
00084 #include "llhudmanager.h"
00085 #include "llinventorymodel.h"
00086 #include "llinventoryview.h"
00087 #include "lljoystickbutton.h"
00088 #include "llmenugl.h"
00089 #include "llmorphview.h"
00090 #include "llmoveview.h"
00091 #include "llnotify.h"
00092 #include "llquantize.h"
00093 #include "llselectmgr.h"
00094 #include "llsky.h"
00095 #include "llsphere.h"
00096 #include "llstatusbar.h"
00097 #include "llimview.h"
00098 #include "lltool.h"
00099 #include "lltoolcomp.h"         // for gToolGun
00100 #include "lltoolfocus.h"
00101 #include "lltoolgrab.h"
00102 #include "lltoolmgr.h"
00103 #include "lltoolpie.h"
00104 #include "lltoolview.h"
00105 #include "llui.h"                       // for make_ui_sound
00106 #include "llviewercamera.h"
00107 #include "llviewerinventory.h"
00108 #include "llviewermenu.h"
00109 #include "llviewernetwork.h"
00110 #include "llviewerobjectlist.h"
00111 #include "llviewerparcelmgr.h"
00112 #include "llviewerparceloverlay.h"
00113 #include "llviewerregion.h"
00114 #include "llviewerstats.h"
00115 #include "llviewerwindow.h"
00116 #include "llvoavatar.h"
00117 #include "llvoground.h"
00118 #include "llvosky.h"
00119 #include "llwearable.h"
00120 #include "llwearablelist.h"
00121 #include "llworld.h"
00122 #include "llworldmap.h"
00123 #include "pipeline.h"
00124 #include "roles_constants.h"
00125 #include "viewer.h"
00126 #include "llvoiceclient.h"
00127 
00128 // Ventrella
00129 #include "llfollowcam.h"
00130 // end Ventrella
00131 
00132 extern LLMenuBarGL* gMenuBarView;
00133 extern U8 gLastPickAlpha;
00134 extern F32 gFrameDTClamped;
00135 
00136 //drone wandering constants
00137 const F32 MAX_WANDER_TIME = 20.f;                                               // seconds
00138 const F32 MAX_HEADING_HALF_ERROR = 0.2f;                                // radians
00139 const F32 WANDER_MAX_SLEW_RATE = 2.f * DEG_TO_RAD;              // radians / frame
00140 const F32 WANDER_TARGET_MIN_DISTANCE = 10.f;                    // meters
00141 
00142 // Autopilot constants
00143 const F32 AUTOPILOT_HEADING_HALF_ERROR = 10.f * DEG_TO_RAD;     // radians
00144 const F32 AUTOPILOT_MAX_SLEW_RATE = 1.f * DEG_TO_RAD;           // radians / frame
00145 const F32 AUTOPILOT_STOP_DISTANCE = 2.f;                                        // meters
00146 const F32 AUTOPILOT_HEIGHT_ADJUST_DISTANCE = 8.f;                       // meters
00147 const F32 AUTOPILOT_MIN_TARGET_HEIGHT_OFF_GROUND = 1.f; // meters
00148 const F32 AUTOPILOT_MAX_TIME_NO_PROGRESS = 1.5f;                // seconds
00149 
00150 // face editing constants
00151 const LLVector3d FACE_EDIT_CAMERA_OFFSET(0.4f, -0.05f, 0.07f);
00152 const LLVector3d FACE_EDIT_TARGET_OFFSET(0.f, 0.f, 0.05f);
00153 
00154 // Mousewheel camera zoom
00155 const F32 MIN_ZOOM_FRACTION = 0.25f;
00156 const F32 INITIAL_ZOOM_FRACTION = 1.f;
00157 const F32 MAX_ZOOM_FRACTION = 8.f;
00158 const F32 METERS_PER_WHEEL_CLICK = 1.f;
00159 
00160 const F32 MAX_TIME_DELTA = 1.f;
00161 
00162 const F32 CAMERA_ZOOM_HALF_LIFE = 0.07f;        // seconds
00163 const F32 FOV_ZOOM_HALF_LIFE = 0.07f;   // seconds
00164 
00165 const F32 CAMERA_FOCUS_HALF_LIFE = 0.f;//0.02f;
00166 const F32 CAMERA_LAG_HALF_LIFE = 0.25f;
00167 const F32 MIN_CAMERA_LAG = 0.5f;
00168 const F32 MAX_CAMERA_LAG = 5.f;
00169 
00170 const F32 CAMERA_COLLIDE_EPSILON = 0.1f;
00171 const F32 MIN_CAMERA_DISTANCE = 0.1f;
00172 const F32 AVATAR_ZOOM_MIN_X_FACTOR = 0.55f;
00173 const F32 AVATAR_ZOOM_MIN_Y_FACTOR = 0.7f;
00174 const F32 AVATAR_ZOOM_MIN_Z_FACTOR = 1.15f;
00175 
00176 const F32 MAX_CAMERA_DISTANCE_FROM_AGENT = 50.f;
00177 
00178 const F32 HEAD_BUFFER_SIZE = 0.3f;
00179 const F32 CUSTOMIZE_AVATAR_CAMERA_ANIM_SLOP = 0.2f;
00180 
00181 const F32 LAND_MIN_ZOOM = 0.15f;
00182 const F32 AVATAR_MIN_ZOOM = 0.5f;
00183 const F32 OBJECT_MIN_ZOOM = 0.02f;
00184 
00185 const F32 APPEARANCE_MIN_ZOOM = 0.39f;
00186 const F32 APPEARANCE_MAX_ZOOM = 8.f;
00187 
00188 // fidget constants
00189 const F32 MIN_FIDGET_TIME = 8.f; // seconds
00190 const F32 MAX_FIDGET_TIME = 20.f; // seconds
00191 
00192 const S32 MAX_NUM_CHAT_POSITIONS = 10;
00193 const F32 GROUND_TO_AIR_CAMERA_TRANSITION_TIME = 0.5f;
00194 const F32 GROUND_TO_AIR_CAMERA_TRANSITION_START_TIME = 0.5f;
00195 
00196 const F32 MAX_VELOCITY_AUTO_LAND_SQUARED = 4.f * 4.f;
00197 
00198 const F32 MAX_FOCUS_OFFSET = 20.f;
00199 
00200 const F32 OBJECT_EXTENTS_PADDING = 0.5f;
00201 
00202 const F32 MIN_RADIUS_ALPHA_SIZZLE = 0.5f;
00203 
00204 const F64 CHAT_AGE_FAST_RATE = 3.0;
00205 
00206 const S32 MAX_WEARABLES_PER_LAYERSET = 7;
00207 
00208 const EWearableType WEARABLE_BAKE_TEXTURE_MAP[BAKED_TEXTURE_COUNT][MAX_WEARABLES_PER_LAYERSET] = 
00209 {
00210         { WT_SHAPE,     WT_SKIN,        WT_HAIR,        WT_INVALID,     WT_INVALID,     WT_INVALID,             WT_INVALID    },        // TEX_HEAD_BAKED
00211         { WT_SHAPE, WT_SKIN,    WT_SHIRT,       WT_JACKET,      WT_GLOVES,      WT_UNDERSHIRT,  WT_INVALID        },    // TEX_UPPER_BAKED
00212         { WT_SHAPE, WT_SKIN,    WT_PANTS,       WT_SHOES,       WT_SOCKS,       WT_JACKET,              WT_UNDERPANTS },        // TEX_LOWER_BAKED
00213         { WT_EYES,      WT_INVALID,     WT_INVALID,     WT_INVALID,     WT_INVALID,     WT_INVALID,             WT_INVALID    },        // TEX_EYES_BAKED
00214         { WT_SKIRT,     WT_INVALID,     WT_INVALID,     WT_INVALID,     WT_INVALID,     WT_INVALID,             WT_INVALID    }         // TEX_SKIRT_BAKED
00215 };
00216 
00217 const LLUUID BAKED_TEXTURE_HASH[BAKED_TEXTURE_COUNT] = 
00218 {
00219         LLUUID("18ded8d6-bcfc-e415-8539-944c0f5ea7a6"),
00220         LLUUID("338c29e3-3024-4dbb-998d-7c04cf4fa88f"),
00221         LLUUID("91b4a2c7-1b1a-ba16-9a16-1f8f8dcc1c3f"),
00222         LLUUID("b2cf28af-b840-1071-3c6a-78085d8128b5"),
00223         LLUUID("ea800387-ea1a-14e0-56cb-24f2022f969a")
00224 };
00225 
00226 //
00227 // Statics
00228 //
00229 BOOL LLAgent::sDebugDisplayTarget = FALSE;
00230 
00231 const F32 LLAgent::TYPING_TIMEOUT_SECS = 5.f;
00232 
00233 std::map<LLString, LLString> LLAgent::sTeleportErrorMessages;
00234 std::map<LLString, LLString> LLAgent::sTeleportProgressMessages;
00235 
00236 class LLAgentFriendObserver : public LLFriendObserver
00237 {
00238 public:
00239         LLAgentFriendObserver() {}
00240         virtual ~LLAgentFriendObserver() {}
00241         virtual void changed(U32 mask);
00242 };
00243 
00244 void LLAgentFriendObserver::changed(U32 mask)
00245 {
00246         // if there's a change we're interested in.
00247         if((mask & (LLFriendObserver::POWERS)) != 0)
00248         {
00249                 gAgent.friendsChanged();
00250         }
00251 }
00252 
00253 // ************************************************************
00254 // Enabled this definition to compile a 'hacked' viewer that
00255 // locally believes the end user has godlike powers.
00256 // #define HACKED_GODLIKE_VIEWER
00257 // For a toggled version, see viewer.h for the
00258 // TOGGLE_HACKED_GODLIKE_VIEWER define, instead.
00259 // ************************************************************
00260 
00261 // Constructors and Destructors
00262 
00263 // JC - Please try to make this order match the order in the header
00264 // file.  Otherwise it's hard to find variables that aren't initialized.
00265 //-----------------------------------------------------------------------------
00266 // LLAgent()
00267 //-----------------------------------------------------------------------------
00268 LLAgent::LLAgent()
00269 :       mViewerPort(NET_USE_OS_ASSIGNED_PORT),
00270         mDrawDistance( DEFAULT_FAR_PLANE ),
00271         mAccess(SIM_ACCESS_PG),
00272         mGroupPowers(0),
00273         mGroupID(),
00274         //mGroupInsigniaID(),
00275         mMapOriginX(0),
00276         mMapOriginY(0),
00277         mMapWidth(0),
00278         mMapHeight(0),
00279         mLookAt(NULL),
00280         mPointAt(NULL),
00281         mInitialized(FALSE),
00282         mNumPendingQueries(0),
00283         mForceMouselook(FALSE),
00284         mTeleportState( TELEPORT_NONE ),
00285         mRegionp(NULL),
00286 
00287         mAgentOriginGlobal(),
00288         mPositionGlobal(),
00289 
00290         mDistanceTraveled(0),
00291         mLastPositionGlobal(LLVector3d::zero),
00292 
00293         mAvatarObject(NULL),
00294 
00295         mRenderState(0),
00296         mTypingTimer(),
00297 
00298         mCameraMode( CAMERA_MODE_THIRD_PERSON ),
00299         mLastCameraMode( CAMERA_MODE_THIRD_PERSON ),
00300         mViewsPushed(FALSE),
00301 
00302         mbAlwaysRun(FALSE),
00303         mShowAvatar(TRUE),
00304 
00305         mCameraAnimating( FALSE ),
00306         mAnimationCameraStartGlobal(),
00307         mAnimationFocusStartGlobal(),
00308         mAnimationTimer(),
00309         mAnimationDuration(0.33f),
00310         mCameraFOVZoomFactor(0.f),
00311         mCameraCurrentFOVZoomFactor(0.f),
00312         mCameraFocusOffset(),
00313         mCameraOffsetDefault(),
00314 //      mCameraOffsetNorm(),
00315         mCameraCollidePlane(),
00316         mCurrentCameraDistance(2.f),            // meters, set in init()
00317         mTargetCameraDistance(2.f),
00318         mCameraZoomFraction(1.f),                       // deprecated
00319         mThirdPersonHeadOffset(0.f, 0.f, 1.f),
00320         mSitCameraEnabled(FALSE),
00321         mFocusOnAvatar(TRUE),
00322         mFocusGlobal(),
00323         mFocusTargetGlobal(),
00324         mFocusObject(NULL),
00325         mFocusObjectOffset(),
00326         mFocusDotRadius( 0.1f ),                        // meters
00327         mTrackFocusObject(TRUE),
00328 
00329         mFrameAgent(),
00330 
00331         mCrouching(FALSE),
00332         mIsBusy(FALSE),
00333 
00334         // movement keys below
00335 
00336         mControlFlags(0x00000000),
00337         mbFlagsDirty(FALSE),
00338         mbFlagsNeedReset(FALSE),
00339 
00340         mbJump(FALSE),
00341 
00342         mAutoPilot(FALSE),
00343         mAutoPilotFlyOnStop(FALSE),
00344         mAutoPilotTargetGlobal(),
00345         mAutoPilotStopDistance(1.f),
00346         mAutoPilotUseRotation(FALSE),
00347         mAutoPilotTargetFacing(LLVector3::zero),
00348         mAutoPilotTargetDist(0.f),
00349         mAutoPilotFinishedCallback(NULL),
00350         mAutoPilotCallbackData(NULL),
00351         
00352 
00353         mEffectColor(0.f, 1.f, 1.f, 1.f),
00354         mHaveHomePosition(FALSE),
00355         mHomeRegionHandle( 0 ),
00356         mNearChatRadius(CHAT_NORMAL_RADIUS / 2.f),
00357         mGodLevel( GOD_NOT ),
00358 
00359 
00360         mNextFidgetTime(0.f),
00361         mCurrentFidget(0),
00362         mFirstLogin(FALSE),
00363         mGenderChosen(FALSE),
00364         mAgentWearablesUpdateSerialNum(0),
00365         mWearablesLoaded(FALSE),
00366         mTextureCacheQueryID(0),
00367         mAppearanceSerialNum(0)
00368 {
00369 
00370         U32 i;
00371         for (i = 0; i < TOTAL_CONTROLS; i++)
00372         {
00373                 mControlsTakenCount[i] = 0;
00374                 mControlsTakenPassedOnCount[i] = 0;
00375         }
00376 
00377         // Initialize movement keys
00378         mAtKey                          = 0;    // Either 1, 0, or -1... indicates that movement-key is pressed
00379         mWalkKey                        = 0;    // like AtKey, but causes less forward thrust
00380         mLeftKey                        = 0;
00381         mUpKey                          = 0;
00382         mYawKey                         = 0.f;
00383         mPitchKey                       = 0;
00384 
00385         mOrbitLeftKey           = 0.f;
00386         mOrbitRightKey          = 0.f;
00387         mOrbitUpKey                     = 0.f;
00388         mOrbitDownKey           = 0.f;
00389         mOrbitInKey                     = 0.f;
00390         mOrbitOutKey            = 0.f;
00391 
00392         mPanUpKey                       = 0.f;
00393         mPanDownKey                     = 0.f;
00394         mPanLeftKey                     = 0.f;
00395         mPanRightKey            = 0.f;
00396         mPanInKey                       = 0.f;
00397         mPanOutKey                      = 0.f;
00398 
00399         mActiveCacheQueries = new S32[BAKED_TEXTURE_COUNT];
00400         for (i = 0; i < (U32)BAKED_TEXTURE_COUNT; i++)
00401         {
00402                 mActiveCacheQueries[i] = 0;
00403         }
00404 
00405         //Ventrella
00406         mCameraUpVector = LLVector3::z_axis;// default is straight up 
00407         mFollowCam.setMaxCameraDistantFromSubject( MAX_CAMERA_DISTANCE_FROM_AGENT );
00408         //end ventrella
00409 }
00410 
00411 // Requires gSavedSettings to be initialized.
00412 //-----------------------------------------------------------------------------
00413 // init()
00414 //-----------------------------------------------------------------------------
00415 void LLAgent::init()
00416 {
00417         mDrawDistance = gSavedSettings.getF32("RenderFarClip");
00418 
00419         gCamera = new LLViewerCamera();
00420 
00421         gCamera->setView(DEFAULT_FIELD_OF_VIEW);
00422         // Leave at 0.1 meters until we have real near clip management
00423         gCamera->setNear(0.1f);
00424         gCamera->setFar(mDrawDistance);                 // if you want to change camera settings, do so in camera.h
00425         gCamera->setAspect( gViewerWindow->getDisplayAspectRatio() );           // default, overridden in LLViewerWindow::reshape
00426         gCamera->setViewHeightInPixels(768);                    // default, overridden in LLViewerWindow::reshape
00427 
00428         setFlying( gSavedSettings.getBOOL("FlyingAtExit") );
00429 
00430         mCameraFocusOffsetTarget = LLVector4(gSavedSettings.getVector3("CameraOffsetBuild"));
00431         mCameraOffsetDefault = gSavedSettings.getVector3("CameraOffsetDefault");
00432 //      mCameraOffsetNorm = mCameraOffsetDefault;
00433 //      mCameraOffsetNorm.normVec();
00434         mCameraCollidePlane.clearVec();
00435         mCurrentCameraDistance = mCameraOffsetDefault.magVec();
00436         mTargetCameraDistance = mCurrentCameraDistance;
00437         mCameraZoomFraction = 1.f;
00438         mTrackFocusObject = gSavedSettings.getBOOL("TrackFocusObject");
00439 
00440 //      LLDebugVarMessageBox::show("Camera Lag", &CAMERA_FOCUS_HALF_LIFE, 0.5f, 0.01f);
00441         gSavedSettings.getControl("RenderHideGroupTitle")->addListener(&mHideGroupTitleListener);
00442         gSavedSettings.getControl("EffectColor")->addListener(&mEffectColorListener);
00443 
00444         mEffectColor = gSavedSettings.getColor4("EffectColor");
00445         
00446         mInitialized = TRUE;
00447 }
00448 
00449 //-----------------------------------------------------------------------------
00450 // cleanup()
00451 //-----------------------------------------------------------------------------
00452 void LLAgent::cleanup()
00453 {
00454         setSitCamera(LLUUID::null);
00455         mAvatarObject = NULL;
00456         mLookAt = NULL;
00457         mPointAt = NULL;
00458         mRegionp = NULL;
00459         setFocusObject(NULL);
00460         mFadeObjects.clear();
00461 }
00462 
00463 //-----------------------------------------------------------------------------
00464 // LLAgent()
00465 //-----------------------------------------------------------------------------
00466 LLAgent::~LLAgent()
00467 {
00468         cleanup();
00469 
00470         delete [] mActiveCacheQueries;
00471         mActiveCacheQueries = NULL;
00472 
00473         delete gCamera;
00474         gCamera = NULL;
00475 }
00476 
00477 // Change camera back to third person, stop the autopilot,
00478 // deselect stuff, etc.
00479 //-----------------------------------------------------------------------------
00480 // resetView()
00481 //-----------------------------------------------------------------------------
00482 void LLAgent::resetView(BOOL reset_camera)
00483 {
00484         if (mAutoPilot)
00485         {
00486                 stopAutoPilot(TRUE);
00487         }
00488 
00489         if (!gNoRender)
00490         {
00491                 gSelectMgr->unhighlightAll();
00492 
00493                 // By popular request, keep land selection while walking around. JC
00494                 // gParcelMgr->deselectLand();
00495 
00496                 // force deselect when walking and attachment is selected
00497                 // this is so people don't wig out when their avatar moves without animating
00498                 if (gSelectMgr->getSelection()->isAttachment())
00499                 {
00500                         gSelectMgr->deselectAll();
00501                 }
00502 
00503                 // Hide all popup menus
00504                 gMenuHolder->hideMenus();
00505         }
00506 
00507         if (reset_camera && !gSavedSettings.getBOOL("FreezeTime"))
00508         {
00509                 if (!gViewerWindow->getLeftMouseDown() && cameraThirdPerson())
00510                 {
00511                         // leaving mouse-steer mode
00512                         LLVector3 agent_at_axis = getAtAxis();
00513                         agent_at_axis -= projected_vec(agent_at_axis, getReferenceUpVector());
00514                         agent_at_axis.normVec();
00515                         gAgent.resetAxes(lerp(getAtAxis(), agent_at_axis, LLCriticalDamp::getInterpolant(0.3f)));
00516                 }
00517 
00518                 setFocusOnAvatar(TRUE, ANIMATE);
00519         }
00520 
00521         if (mAvatarObject.notNull())
00522         {
00523                 mAvatarObject->mHUDTargetZoom = 1.f;
00524         }
00525 }
00526 
00527 void LLAgent::ageChat()
00528 {
00529         if (mAvatarObject)
00530         {
00531                 // get amount of time since I last chatted
00532                 F64 elapsed_time = (F64)mAvatarObject->mChatTimer.getElapsedTimeF32();
00533                 // add in frame time * 3 (so it ages 4x)
00534                 mAvatarObject->mChatTimer.setAge(elapsed_time + (F64)gFrameDTClamped * (CHAT_AGE_FAST_RATE - 1.0));
00535         }
00536 }
00537 
00538 // Allow camera to be moved somewhere other than behind avatar.
00539 //-----------------------------------------------------------------------------
00540 // unlockView()
00541 //-----------------------------------------------------------------------------
00542 void LLAgent::unlockView()
00543 {
00544         if (getFocusOnAvatar())
00545         {
00546                 if (mAvatarObject)
00547                 {
00548                         setFocusGlobal( LLVector3d::zero, mAvatarObject->mID );
00549                 }
00550                 setFocusOnAvatar(FALSE, FALSE); // no animation
00551         }
00552 }
00553 
00554 
00555 //-----------------------------------------------------------------------------
00556 // moveAt()
00557 //-----------------------------------------------------------------------------
00558 void LLAgent::moveAt(S32 direction)
00559 {
00560         // age chat timer so it fades more quickly when you are intentionally moving
00561         ageChat();
00562 
00563         setKey(direction, mAtKey);
00564 
00565         if (direction > 0)
00566         {
00567                 setControlFlags(AGENT_CONTROL_AT_POS | AGENT_CONTROL_FAST_AT);
00568         }
00569         else if (direction < 0)
00570         {
00571                 setControlFlags(AGENT_CONTROL_AT_NEG | AGENT_CONTROL_FAST_AT);
00572         }
00573 
00574         resetView();
00575 }
00576 
00577 //-----------------------------------------------------------------------------
00578 // moveAtNudge()
00579 //-----------------------------------------------------------------------------
00580 void LLAgent::moveAtNudge(S32 direction)
00581 {
00582         // age chat timer so it fades more quickly when you are intentionally moving
00583         ageChat();
00584 
00585         setKey(direction, mWalkKey);
00586 
00587         if (direction > 0)
00588         {
00589                 setControlFlags(AGENT_CONTROL_NUDGE_AT_POS);
00590         }
00591         else if (direction < 0)
00592         {
00593                 setControlFlags(AGENT_CONTROL_NUDGE_AT_NEG);
00594         }
00595 
00596         resetView();
00597 }
00598 
00599 //-----------------------------------------------------------------------------
00600 // moveLeft()
00601 //-----------------------------------------------------------------------------
00602 void LLAgent::moveLeft(S32 direction)
00603 {
00604         // age chat timer so it fades more quickly when you are intentionally moving
00605         ageChat();
00606 
00607         setKey(direction, mLeftKey);
00608 
00609         if (direction > 0)
00610         {
00611                 setControlFlags(AGENT_CONTROL_LEFT_POS | AGENT_CONTROL_FAST_LEFT);
00612         }
00613         else if (direction < 0)
00614         {
00615                 setControlFlags(AGENT_CONTROL_LEFT_NEG | AGENT_CONTROL_FAST_LEFT);
00616         }
00617 
00618         resetView();
00619 }
00620 
00621 //-----------------------------------------------------------------------------
00622 // moveLeftNudge()
00623 //-----------------------------------------------------------------------------
00624 void LLAgent::moveLeftNudge(S32 direction)
00625 {
00626         // age chat timer so it fades more quickly when you are intentionally moving
00627         ageChat();
00628 
00629         setKey(direction, mLeftKey);
00630 
00631         if (direction > 0)
00632         {
00633                 setControlFlags(AGENT_CONTROL_NUDGE_LEFT_POS);
00634         }
00635         else if (direction < 0)
00636         {
00637                 setControlFlags(AGENT_CONTROL_NUDGE_LEFT_NEG);
00638         }
00639 
00640         resetView();
00641 }
00642 
00643 //-----------------------------------------------------------------------------
00644 // moveUp()
00645 //-----------------------------------------------------------------------------
00646 void LLAgent::moveUp(S32 direction)
00647 {
00648         // age chat timer so it fades more quickly when you are intentionally moving
00649         ageChat();
00650 
00651         setKey(direction, mUpKey);
00652 
00653         if (direction > 0)
00654         {
00655                 setControlFlags(AGENT_CONTROL_UP_POS | AGENT_CONTROL_FAST_UP);
00656         }
00657         else if (direction < 0)
00658         {
00659                 setControlFlags(AGENT_CONTROL_UP_NEG | AGENT_CONTROL_FAST_UP);
00660         }
00661 
00662         resetView();
00663 }
00664 
00665 //-----------------------------------------------------------------------------
00666 // moveYaw()
00667 //-----------------------------------------------------------------------------
00668 void LLAgent::moveYaw(F32 mag)
00669 {
00670         mYawKey = mag;
00671 
00672         if (mag > 0)
00673         {
00674                 setControlFlags(AGENT_CONTROL_YAW_POS);
00675         }
00676         else if (mag < 0)
00677         {
00678                 setControlFlags(AGENT_CONTROL_YAW_NEG);
00679         }
00680 
00681         resetView();
00682 }
00683 
00684 //-----------------------------------------------------------------------------
00685 // movePitch()
00686 //-----------------------------------------------------------------------------
00687 void LLAgent::movePitch(S32 direction)
00688 {
00689         setKey(direction, mPitchKey);
00690 
00691         if (direction > 0)
00692         {
00693                 setControlFlags(AGENT_CONTROL_PITCH_POS );
00694         }
00695         else if (direction < 0)
00696         {
00697                 setControlFlags(AGENT_CONTROL_PITCH_NEG);
00698         }
00699 }
00700 
00701 
00702 // Does this parcel allow you to fly?
00703 BOOL LLAgent::canFly()
00704 {
00705         if (isGodlike()) return TRUE;
00706 
00707         if (!gParcelMgr) return FALSE;
00708 
00709         LLViewerRegion* regionp = getRegion();
00710         if (regionp && regionp->getBlockFly()) return FALSE;
00711         
00712         LLParcel* parcel = gParcelMgr->getAgentParcel();
00713         if (!parcel) return FALSE;
00714 
00715         // Allow owners to fly on their own land.
00716         if (LLViewerParcelMgr::isParcelOwnedByAgent(parcel, GP_LAND_ALLOW_FLY))
00717         {
00718                 return TRUE;
00719         }
00720 
00721         return parcel->getAllowFly();
00722 }
00723 
00724 
00725 //-----------------------------------------------------------------------------
00726 // setFlying()
00727 //-----------------------------------------------------------------------------
00728 void LLAgent::setFlying(BOOL fly)
00729 {
00730         if (mAvatarObject.notNull())
00731         {
00732                 if(mAvatarObject->mSignaledAnimations.find(ANIM_AGENT_STANDUP) != mAvatarObject->mSignaledAnimations.end())
00733                 {
00734                         return;
00735                 }
00736 
00737                 // don't allow taking off while sitting
00738                 if (fly && mAvatarObject->mIsSitting)
00739                 {
00740                         return;
00741                 }
00742         }
00743 
00744         if (fly)
00745         {
00746                 BOOL was_flying = getFlying();
00747                 if (gParcelMgr)
00748                 {
00749                         if (!canFly() && !was_flying)
00750                         {
00751                                 // parcel doesn't let you start fly
00752                                 // gods can always fly
00753                                 // and it's OK if you're already flying
00754                                 make_ui_sound("UISndBadKeystroke");
00755                                 return;
00756                         }
00757                 }
00758                 if( !was_flying )
00759                 {
00760                         gViewerStats->incStat(LLViewerStats::ST_FLY_COUNT);
00761                 }
00762                 setControlFlags(AGENT_CONTROL_FLY);
00763                 gSavedSettings.setBOOL("FlyBtnState", TRUE);
00764         }
00765         else
00766         {
00767                 clearControlFlags(AGENT_CONTROL_FLY);
00768                 gSavedSettings.setBOOL("FlyBtnState", FALSE);
00769         }
00770         mbFlagsDirty = TRUE;
00771 }
00772 
00773 
00774 // UI based mechanism of setting fly state
00775 //-----------------------------------------------------------------------------
00776 // toggleFlying()
00777 //-----------------------------------------------------------------------------
00778 void LLAgent::toggleFlying()
00779 {
00780         BOOL fly = !(mControlFlags & AGENT_CONTROL_FLY);
00781 
00782         setFlying( fly );
00783         resetView();
00784 }
00785 
00786 
00787 //-----------------------------------------------------------------------------
00788 // setRegion()
00789 //-----------------------------------------------------------------------------
00790 void LLAgent::setRegion(LLViewerRegion *regionp)
00791 {
00792         llassert(regionp);
00793         if (mRegionp != regionp)
00794         {
00795                 // JC - Avoid this, causes out-of-bounds array write deep within
00796                 // Windows.
00797                 // char host_name[MAX_STRING];
00798                 // regionp->getHost().getHostName(host_name, MAX_STRING);
00799 
00800                 char ip[MAX_STRING];            /*Flawfinder: ignore*/
00801                 regionp->getHost().getString(ip, MAX_STRING);
00802                 llinfos << "Moving agent into region: " << regionp->getName()
00803                                 << " located at " << ip << llendl;
00804                 if (mRegionp)
00805                 {
00806                         // We've changed regions, we're now going to change our agent coordinate frame.
00807                         mAgentOriginGlobal = regionp->getOriginGlobal();
00808                         LLVector3d agent_offset_global = mRegionp->getOriginGlobal();
00809 
00810                         LLVector3 delta;
00811                         delta.setVec(regionp->getOriginGlobal() - mRegionp->getOriginGlobal());
00812 
00813                         setPositionAgent(getPositionAgent() - delta);
00814                         LLVector3 camera_position_agent = gCamera->getOrigin();
00815                         gCamera->setOrigin(camera_position_agent - delta);
00816 
00817                         // Update all of the regions.
00818                         gWorldPointer->updateAgentOffset(agent_offset_global);
00819 
00820                         // Hack to keep sky in the agent's region, otherwise it may get deleted - DJS 08/02/02
00821                         if (gSky.mVOSkyp)
00822                         {
00823                                 gSky.mVOSkyp->setRegion(regionp);
00824                         }
00825                         if (gSky.mVOStarsp)
00826                         {
00827                                 gSky.mVOStarsp->setRegion(regionp);
00828                         }
00829                         if (gSky.mVOGroundp)
00830                         {
00831                                 gSky.mVOGroundp->setRegion(regionp);
00832                         }
00833 
00834                 }
00835                 else
00836                 {
00837                         // First time initialization.
00838                         // We've changed regions, we're now going to change our agent coordinate frame.
00839                         mAgentOriginGlobal = regionp->getOriginGlobal();
00840 
00841                         LLVector3 delta;
00842                         delta.setVec(regionp->getOriginGlobal());
00843 
00844                         setPositionAgent(getPositionAgent() - delta);
00845                         LLVector3 camera_position_agent = gCamera->getOrigin();
00846                         gCamera->setOrigin(camera_position_agent - delta);
00847 
00848                         // Update all of the regions.
00849                         gWorldPointer->updateAgentOffset(mAgentOriginGlobal);
00850                 }
00851         }
00852         mRegionp = regionp;
00853 
00854         // Must shift hole-covering water object locations because local
00855         // coordinate frame changed.
00856         gWorldPointer->updateWaterObjects();
00857 
00858         // keep a list of regions we've been too
00859         // this is just an interesting stat, logged at the dataserver
00860         // we could trake this at the dataserver side, but that's harder
00861         U64 handle = regionp->getHandle();
00862         mRegionsVisited.insert(handle);
00863 
00864         gSelectMgr->updateSelectionCenter();
00865 }
00866 
00867 
00868 //-----------------------------------------------------------------------------
00869 // getRegion()
00870 //-----------------------------------------------------------------------------
00871 LLViewerRegion *LLAgent::getRegion() const
00872 {
00873         return mRegionp;
00874 }
00875 
00876 
00877 const LLHost& LLAgent::getRegionHost() const
00878 {
00879         if (mRegionp)
00880         {
00881                 return mRegionp->getHost();
00882         }
00883         else
00884         {
00885                 return LLHost::invalid;
00886         }
00887 }
00888 
00889 
00890 //-----------------------------------------------------------------------------
00891 // inPrelude()
00892 //-----------------------------------------------------------------------------
00893 BOOL LLAgent::inPrelude()
00894 {
00895         return mRegionp && mRegionp->isPrelude();
00896 }
00897 
00898 
00899 //-----------------------------------------------------------------------------
00900 // canManageEstate()
00901 //-----------------------------------------------------------------------------
00902 
00903 BOOL LLAgent::canManageEstate() const
00904 {
00905         return mRegionp && mRegionp->canManageEstate();
00906 }
00907 
00908 //-----------------------------------------------------------------------------
00909 // sendMessage()
00910 //-----------------------------------------------------------------------------
00911 void LLAgent::sendMessage()
00912 {
00913         if (gDisconnected)
00914         {
00915                 llwarns << "Trying to send message when disconnected!" << llendl;
00916                 return;
00917         }
00918         if (!mRegionp)
00919         {
00920                 llerrs << "No region for agent yet!" << llendl;
00921         }
00922         gMessageSystem->sendMessage(mRegionp->getHost());
00923 }
00924 
00925 
00926 //-----------------------------------------------------------------------------
00927 // sendReliableMessage()
00928 //-----------------------------------------------------------------------------
00929 void LLAgent::sendReliableMessage()
00930 {
00931         if (gDisconnected)
00932         {
00933                 llwarns << "Trying to send message when disconnected!" << llendl;
00934                 return;
00935         }
00936         if (!mRegionp)
00937         {
00938                 llwarns << "LLAgent::sendReliableMessage No region for agent yet, not sending message!" << llendl;
00939                 return;
00940         }
00941         gMessageSystem->sendReliable(mRegionp->getHost());
00942 }
00943 
00944 //-----------------------------------------------------------------------------
00945 // getVelocity()
00946 //-----------------------------------------------------------------------------
00947 LLVector3 LLAgent::getVelocity() const
00948 {
00949         if (mAvatarObject)
00950         {
00951                 return mAvatarObject->getVelocity();
00952         }
00953         else
00954         {
00955                 return LLVector3::zero;
00956         }
00957 }
00958 
00959 
00960 //-----------------------------------------------------------------------------
00961 // setPositionAgent()
00962 //-----------------------------------------------------------------------------
00963 void LLAgent::setPositionAgent(const LLVector3 &pos_agent)
00964 {
00965         if (!pos_agent.isFinite())
00966         {
00967                 llerrs << "setPositionAgent is not a number" << llendl;
00968         }
00969 
00970         if (!mAvatarObject.isNull() && mAvatarObject->getParent())
00971         {
00972                 LLVector3 pos_agent_sitting;
00973                 LLVector3d pos_agent_d;
00974                 LLViewerObject *parent = (LLViewerObject*)mAvatarObject->getParent();
00975 
00976                 pos_agent_sitting = mAvatarObject->getPosition() * parent->getRotation() + parent->getPositionAgent();
00977                 pos_agent_d.setVec(pos_agent_sitting);
00978 
00979                 mFrameAgent.setOrigin(pos_agent_sitting);
00980                 mPositionGlobal = pos_agent_d + mAgentOriginGlobal;
00981         }
00982         else
00983         {
00984                 mFrameAgent.setOrigin(pos_agent);
00985 
00986                 LLVector3d pos_agent_d;
00987                 pos_agent_d.setVec(pos_agent);
00988                 mPositionGlobal = pos_agent_d + mAgentOriginGlobal;
00989         }
00990 }
00991 
00992 //-----------------------------------------------------------------------------
00993 // slamLookAt()
00994 //-----------------------------------------------------------------------------
00995 void LLAgent::slamLookAt(const LLVector3 &look_at)
00996 {
00997         LLVector3 look_at_norm = look_at;
00998         look_at_norm.mV[VZ] = 0.f;
00999         look_at_norm.normVec();
01000         resetAxes(look_at_norm);
01001 }
01002 
01003 //-----------------------------------------------------------------------------
01004 // getPositionGlobal()
01005 //-----------------------------------------------------------------------------
01006 const LLVector3d &LLAgent::getPositionGlobal() 
01007 {
01008         if (!mAvatarObject.isNull() && !mAvatarObject->mDrawable.isNull())
01009         {
01010                 mPositionGlobal = getPosGlobalFromAgent(mAvatarObject->getRenderPosition());
01011         }
01012         else
01013         {
01014                 mPositionGlobal = getPosGlobalFromAgent(mFrameAgent.getOrigin());
01015         }
01016 
01017         return mPositionGlobal;
01018 }
01019 
01020 //-----------------------------------------------------------------------------
01021 // getPositionAgent()
01022 //-----------------------------------------------------------------------------
01023 const LLVector3 &LLAgent::getPositionAgent()
01024 {
01025         if(!mAvatarObject.isNull() && !mAvatarObject->mDrawable.isNull())
01026         {
01027                 mFrameAgent.setOrigin(mAvatarObject->getRenderPosition());      
01028         }
01029 
01030         return mFrameAgent.getOrigin();
01031 }
01032 
01033 //-----------------------------------------------------------------------------
01034 // getRegionsVisited()
01035 //-----------------------------------------------------------------------------
01036 S32 LLAgent::getRegionsVisited() const
01037 {
01038         return mRegionsVisited.size();
01039 }
01040 
01041 //-----------------------------------------------------------------------------
01042 // getDistanceTraveled()
01043 //-----------------------------------------------------------------------------
01044 F64 LLAgent::getDistanceTraveled() const
01045 {
01046         return mDistanceTraveled;
01047 }
01048 
01049 
01050 //-----------------------------------------------------------------------------
01051 // getPosAgentFromGlobal()
01052 //-----------------------------------------------------------------------------
01053 LLVector3 LLAgent::getPosAgentFromGlobal(const LLVector3d &pos_global) const
01054 {
01055         LLVector3 pos_agent;
01056         pos_agent.setVec(pos_global - mAgentOriginGlobal);
01057         return pos_agent;
01058 }
01059 
01060 
01061 //-----------------------------------------------------------------------------
01062 // getPosGlobalFromAgent()
01063 //-----------------------------------------------------------------------------
01064 LLVector3d LLAgent::getPosGlobalFromAgent(const LLVector3 &pos_agent) const
01065 {
01066         LLVector3d pos_agent_d;
01067         pos_agent_d.setVec(pos_agent);
01068         return pos_agent_d + mAgentOriginGlobal;
01069 }
01070 
01071 
01072 //-----------------------------------------------------------------------------
01073 // resetAxes()
01074 //-----------------------------------------------------------------------------
01075 void LLAgent::resetAxes()
01076 {
01077         mFrameAgent.resetAxes();
01078 }
01079 
01080 
01081 // Copied from LLCamera::setOriginAndLookAt
01082 // Look_at must be unit vector
01083 //-----------------------------------------------------------------------------
01084 // resetAxes()
01085 //-----------------------------------------------------------------------------
01086 void LLAgent::resetAxes(const LLVector3 &look_at)
01087 {
01088         LLVector3       skyward = getReferenceUpVector();
01089 
01090         // if look_at has zero length, fail
01091         // if look_at and skyward are parallel, fail
01092         //
01093         // Test both of these conditions with a cross product.
01094         LLVector3 cross(look_at % skyward);
01095         if (cross.isNull())
01096         {
01097                 llinfos << "LLAgent::resetAxes cross-product is zero" << llendl;
01098                 return;
01099         }
01100 
01101         // Make sure look_at and skyward are not parallel
01102         // and neither are zero length
01103         LLVector3 left(skyward % look_at);
01104         LLVector3 up(look_at % left);
01105 
01106         mFrameAgent.setAxes(look_at, left, up);
01107 }
01108 
01109 
01110 //-----------------------------------------------------------------------------
01111 // rotate()
01112 //-----------------------------------------------------------------------------
01113 void LLAgent::rotate(F32 angle, const LLVector3 &axis) 
01114 { 
01115         mFrameAgent.rotate(angle, axis); 
01116 }
01117 
01118 
01119 //-----------------------------------------------------------------------------
01120 // rotate()
01121 //-----------------------------------------------------------------------------
01122 void LLAgent::rotate(F32 angle, F32 x, F32 y, F32 z) 
01123 { 
01124         mFrameAgent.rotate(angle, x, y, z); 
01125 }
01126 
01127 
01128 //-----------------------------------------------------------------------------
01129 // rotate()
01130 //-----------------------------------------------------------------------------
01131 void LLAgent::rotate(const LLMatrix3 &matrix) 
01132 { 
01133         mFrameAgent.rotate(matrix); 
01134 }
01135 
01136 
01137 //-----------------------------------------------------------------------------
01138 // rotate()
01139 //-----------------------------------------------------------------------------
01140 void LLAgent::rotate(const LLQuaternion &quaternion) 
01141 { 
01142         mFrameAgent.rotate(quaternion); 
01143 }
01144 
01145 
01146 //-----------------------------------------------------------------------------
01147 // getReferenceUpVector()
01148 //-----------------------------------------------------------------------------
01149 LLVector3 LLAgent::getReferenceUpVector()
01150 {
01151         // this vector is in the coordinate frame of the avatar's parent object, or the world if none
01152         LLVector3 up_vector = LLVector3::z_axis;
01153         if (mAvatarObject.notNull() && 
01154                 mAvatarObject->getParent() &&
01155                 mAvatarObject->mDrawable.notNull())
01156         {
01157                 U32 camera_mode = mCameraAnimating ? mLastCameraMode : mCameraMode;
01158                 // and in third person...
01159                 if (camera_mode == CAMERA_MODE_THIRD_PERSON)
01160                 {
01161                         // make the up vector point to the absolute +z axis
01162                         up_vector = up_vector * ~((LLViewerObject*)mAvatarObject->getParent())->getRenderRotation();
01163                 }
01164                 else if (camera_mode == CAMERA_MODE_MOUSELOOK)
01165                 {
01166                         // make the up vector point to the avatar's +z axis
01167                         up_vector = up_vector * mAvatarObject->mDrawable->getRotation();
01168                 }
01169         }
01170 
01171         return up_vector;
01172 }
01173 
01174 
01175 // Radians, positive is forward into ground
01176 //-----------------------------------------------------------------------------
01177 // pitch()
01178 //-----------------------------------------------------------------------------
01179 void LLAgent::pitch(F32 angle)
01180 {
01181         // don't let user pitch if pointed almost all the way down or up
01182         
01183         // A dot B = mag(A) * mag(B) * cos(angle between A and B)
01184         // so... cos(angle between A and B) = A dot B / mag(A) / mag(B)
01185         //                                  = A dot B for unit vectors
01186 
01187         LLVector3 skyward = getReferenceUpVector();
01188 
01189         F32                     look_down_limit;
01190         F32                     look_up_limit = 10.f * DEG_TO_RAD;
01191 
01192         F32 angle_from_skyward = acos( mFrameAgent.getAtAxis() * skyward );
01193 
01194         if (mAvatarObject.notNull() && mAvatarObject->mIsSitting)
01195         {
01196                 look_down_limit = 130.f * DEG_TO_RAD;
01197         }
01198         else
01199         {
01200                 look_down_limit = 170.f * DEG_TO_RAD;
01201         }
01202 
01203         // clamp pitch to limits
01204         if ((angle >= 0.f) && (angle_from_skyward + angle > look_down_limit))
01205         {
01206                 angle = look_down_limit - angle_from_skyward;
01207         }
01208         else if ((angle < 0.f) && (angle_from_skyward + angle < look_up_limit))
01209         {
01210                 angle = look_up_limit - angle_from_skyward;
01211         }
01212 
01213         mFrameAgent.pitch(angle);
01214 }
01215 
01216 
01217 //-----------------------------------------------------------------------------
01218 // roll()
01219 //-----------------------------------------------------------------------------
01220 void LLAgent::roll(F32 angle)
01221 {
01222         mFrameAgent.roll(angle);
01223 }
01224 
01225 
01226 //-----------------------------------------------------------------------------
01227 // yaw()
01228 //-----------------------------------------------------------------------------
01229 void LLAgent::yaw(F32 angle)
01230 {
01231         if (!rotateGrabbed())
01232         {
01233                 mFrameAgent.rotate(angle, getReferenceUpVector());
01234         }
01235 }
01236 
01237 
01238 // Returns a quat that represents the rotation of the agent in the absolute frame
01239 //-----------------------------------------------------------------------------
01240 // getQuat()
01241 //-----------------------------------------------------------------------------
01242 LLQuaternion LLAgent::getQuat() const
01243 {
01244         return mFrameAgent.getQuaternion();
01245 }
01246 
01247 
01248 //-----------------------------------------------------------------------------
01249 // calcFocusOffset()
01250 //-----------------------------------------------------------------------------
01251 LLVector3d LLAgent::calcFocusOffset(LLViewerObject *object, S32 x, S32 y)
01252 {
01253         // calculate offset based on view direction
01254         BOOL is_avatar = object->isAvatar();
01255         LLMatrix4 obj_matrix = is_avatar  ? ((LLVOAvatar*)object)->mPelvisp->getWorldMatrix() : object->getRenderMatrix();
01256         LLQuaternion obj_rot = is_avatar  ? ((LLVOAvatar*)object)->mPelvisp->getWorldRotation() : object->getRenderRotation();
01257         LLVector3 obj_pos = is_avatar ? ((LLVOAvatar*)object)->mPelvisp->getWorldPosition() : object->getRenderPosition();
01258         LLQuaternion inv_obj_rot = ~obj_rot;
01259 
01260         LLVector3 obj_dir_abs = obj_pos - gCamera->getOrigin();
01261         obj_dir_abs.rotVec(inv_obj_rot);
01262         obj_dir_abs.normVec();
01263         obj_dir_abs.abs();
01264 
01265         LLVector3 object_extents = object->getScale();
01266         // make sure they object extents are non-zero
01267         object_extents.clamp(0.001f, F32_MAX);
01268         LLVector3 object_half_extents = object_extents * 0.5f;
01269 
01270         obj_dir_abs.mV[VX] = obj_dir_abs.mV[VX] / object_extents.mV[VX];
01271         obj_dir_abs.mV[VY] = obj_dir_abs.mV[VY] / object_extents.mV[VY];
01272         obj_dir_abs.mV[VZ] = obj_dir_abs.mV[VZ] / object_extents.mV[VZ];
01273 
01274         LLVector3 normal;
01275         if (obj_dir_abs.mV[VX] > obj_dir_abs.mV[VY] && obj_dir_abs.mV[VX] > obj_dir_abs.mV[VZ])
01276         {
01277                 normal.setVec(obj_matrix.getFwdRow4());
01278         }
01279         else if (obj_dir_abs.mV[VY] > obj_dir_abs.mV[VZ])
01280         {
01281                 normal.setVec(obj_matrix.getLeftRow4());
01282         }
01283         else
01284         {
01285                 normal.setVec(obj_matrix.getUpRow4());
01286         }
01287         normal.normVec();
01288 
01289         LLVector3d focus_pt_global;
01290         // RN: should we check return value for valid pick?
01291         gViewerWindow->mousePointOnPlaneGlobal(focus_pt_global, x, y, gAgent.getPosGlobalFromAgent(obj_pos), normal);
01292         LLVector3 focus_pt = gAgent.getPosAgentFromGlobal(focus_pt_global);
01293         // find vector from camera to focus point in object coordinates
01294         LLVector3 camera_focus_vec = focus_pt - gCamera->getOrigin();
01295         // convert to object-local space
01296         camera_focus_vec.rotVec(inv_obj_rot);
01297 
01298         // find vector from object origin to focus point in object coordinates
01299         LLVector3 focus_delta = focus_pt - obj_pos;
01300         // convert to object-local space
01301         focus_delta.rotVec(inv_obj_rot);
01302 
01303         // calculate clip percentage needed to get focus offset back in bounds along the camera_focus axis
01304         LLVector3 clip_fraction;
01305 
01306         for (U32 axis = VX; axis <= VZ; axis++)
01307         {
01308                 F32 clip_amt;
01309                 if (focus_delta.mV[axis] > 0.f)
01310                 {
01311                         clip_amt = llmax(0.f, focus_delta.mV[axis] - object_half_extents.mV[axis]);
01312                 }
01313                 else
01314                 {
01315                         clip_amt = llmin(0.f, focus_delta.mV[axis] + object_half_extents.mV[axis]);
01316                 }
01317 
01318                 // don't divide by very small nunber
01319                 if (llabs(camera_focus_vec.mV[axis]) < 0.0001f)
01320                 {
01321                         clip_fraction.mV[axis] = 0.f;
01322                 }
01323                 else
01324                 {
01325                         clip_fraction.mV[axis] = clip_amt / camera_focus_vec.mV[axis];
01326                 }
01327         }
01328 
01329         LLVector3 abs_clip_fraction = clip_fraction;
01330         abs_clip_fraction.abs();
01331 
01332         // find greatest shrinkage factor and
01333         // rescale focus offset to inside object extents
01334         if (abs_clip_fraction.mV[VX] > abs_clip_fraction.mV[VY] &&
01335                 abs_clip_fraction.mV[VX] > abs_clip_fraction.mV[VZ])
01336         {
01337                 focus_delta -= clip_fraction.mV[VX] * camera_focus_vec;
01338         }
01339         else if (abs_clip_fraction.mV[VY] > abs_clip_fraction.mV[VZ])
01340         {
01341                 focus_delta -= clip_fraction.mV[VY] * camera_focus_vec;
01342         }
01343         else
01344         {
01345                 focus_delta -= clip_fraction.mV[VZ] * camera_focus_vec;
01346         }
01347 
01348         // convert back to world space
01349         focus_delta.rotVec(obj_rot);
01350         
01351         if (!is_avatar) 
01352         {
01353                 //unproject relative clicked coordinate from window coordinate using GL
01354                 glPushMatrix();
01355                 glMatrixMode(GL_PROJECTION);
01356                 glLoadMatrixf((const GLfloat*) gCamera->getProjection().mMatrix);
01357                 glMatrixMode(GL_MODELVIEW);
01358                 glLoadMatrixf((const GLfloat*) gCamera->getModelview().mMatrix);
01359                 glMultMatrixf((const GLfloat*) obj_matrix.mMatrix);
01360 
01361                 GLint viewport[4];
01362                 GLdouble modelview[16];
01363                 GLdouble projection[16];
01364                 GLfloat winX, winY, winZ;
01365                 GLdouble posX, posY, posZ;
01366 
01367                 glGetDoublev( GL_MODELVIEW_MATRIX, modelview );
01368                 glGetDoublev( GL_PROJECTION_MATRIX, projection );
01369                 glGetIntegerv( GL_VIEWPORT, viewport );
01370 
01371                 winX = ((F32)x) * gViewerWindow->getDisplayScale().mV[VX];
01372                 winY = ((F32)y) * gViewerWindow->getDisplayScale().mV[VY];
01373                 glReadPixels( llfloor(winX), llfloor(winY), 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &winZ );
01374 
01375                 gluUnProject( winX, winY, winZ, modelview, projection, viewport, &posX, &posY, &posZ);
01376 
01377                 glPopMatrix();
01378 
01379                 LLVector3 obj_rel = LLVector3((F32)posX, (F32)posY, (F32)posZ);
01380                 LLVector3 obj_center = LLVector3(0, 0, 0);
01381                 obj_rel = obj_rel * object->getRenderMatrix(); //mDrawable->getWorldMatrix();
01382                 obj_center = obj_center * object->getRenderMatrix();//mDrawable->getWorldMatrix();
01383                 obj_rel -= object->getRenderPosition();//mDrawable->getWorldPosition();
01384                 
01385                 //now that we have the object relative position, we should bias toward the center of the object 
01386                 //based on the distance of the camera to the focus point vs. the distance of the camera to the focus
01387 
01388                 F32 relDist = llabs(obj_rel * gCamera->getAtAxis());
01389                 F32 viewDist = dist_vec(obj_center + obj_rel, gCamera->getOrigin());
01390 
01391 
01392                 LLBBox obj_bbox = object->getBoundingBoxAgent();
01393                 F32 bias = 0.f;
01394 
01395                 LLVector3 virtual_camera_pos = gAgent.getPosAgentFromGlobal(mFocusTargetGlobal + (getCameraPositionGlobal() - mFocusTargetGlobal) / (1.f + mCameraFOVZoomFactor));
01396 
01397                 if(obj_bbox.containsPointAgent(virtual_camera_pos))
01398                 {
01399                         // if the camera is inside the object (large, hollow objects, for example)
01400                         // force focus point all the way to destination depth, away from object center
01401                         bias = 1.f;
01402                 }
01403                 else
01404                 {
01405                         // perform magic number biasing of focus point towards surface vs. planar center
01406                         bias = clamp_rescale(relDist/viewDist, 0.1f, 0.7f, 0.0f, 1.0f);
01407                 }
01408                 
01409                 obj_rel = lerp(focus_delta, obj_rel, bias);
01410                 
01411                 return LLVector3d(obj_rel);
01412         }
01413 
01414         return LLVector3d(focus_delta.mV[VX], focus_delta.mV[VY], focus_delta.mV[VZ]);
01415 }
01416 
01417 //-----------------------------------------------------------------------------
01418 // calcCameraMinDistance()
01419 //-----------------------------------------------------------------------------
01420 BOOL LLAgent::calcCameraMinDistance(F32 &obj_min_distance)
01421 {
01422         BOOL soft_limit = FALSE; // is the bounding box to be treated literally (volumes) or as an approximation (avatars)
01423 
01424         if (!mFocusObject || mFocusObject->isDead())
01425         {
01426                 obj_min_distance = 0.f;
01427                 return TRUE;
01428         }
01429 
01430         if (mFocusObject->mDrawable.isNull())
01431         {
01432 #ifdef LL_RELEASE_FOR_DOWNLOAD
01433                 llwarns << "Focus object with no drawable!" << llendl;
01434 #else
01435                 mFocusObject->dump();
01436                 llerrs << "Focus object with no drawable!" << llendl;
01437 #endif
01438                 obj_min_distance = 0.f;
01439                 return TRUE;
01440         }
01441         
01442         LLQuaternion inv_object_rot = ~mFocusObject->getRenderRotation();
01443         LLVector3 target_offset_origin = mFocusObjectOffset;
01444         LLVector3 camera_offset_target(getCameraPositionAgent() - getPosAgentFromGlobal(mFocusTargetGlobal));
01445 
01446         // convert offsets into object local space
01447         camera_offset_target.rotVec(inv_object_rot);
01448         target_offset_origin.rotVec(inv_object_rot);
01449 
01450         // push around object extents based on target offset
01451         LLVector3 object_extents = mFocusObject->getScale();
01452         if (mFocusObject->isAvatar())
01453         {
01454                 // fudge factors that lets you zoom in on avatars a bit more (which don't do FOV zoom)
01455                 object_extents.mV[VX] *= AVATAR_ZOOM_MIN_X_FACTOR;
01456                 object_extents.mV[VY] *= AVATAR_ZOOM_MIN_Y_FACTOR;
01457                 object_extents.mV[VZ] *= AVATAR_ZOOM_MIN_Z_FACTOR;
01458                 soft_limit = TRUE;
01459         }
01460         LLVector3 abs_target_offset = target_offset_origin;
01461         abs_target_offset.abs();
01462 
01463         LLVector3 target_offset_dir = target_offset_origin;
01464         F32 object_radius = mFocusObject->getVObjRadius();
01465 
01466         BOOL target_outside_object_extents = FALSE;
01467 
01468         for (U32 i = VX; i <= VZ; i++)
01469         {
01470                 if (abs_target_offset.mV[i] * 2.f > object_extents.mV[i] + OBJECT_EXTENTS_PADDING)
01471                 {
01472                         target_outside_object_extents = TRUE;
01473                 }
01474                 if (camera_offset_target.mV[i] > 0.f)
01475                 {
01476                         object_extents.mV[i] -= target_offset_origin.mV[i] * 2.f;
01477                 }
01478                 else
01479                 {
01480                         object_extents.mV[i] += target_offset_origin.mV[i] * 2.f;
01481                 }
01482         }
01483 
01484         // don't shrink the object extents so far that the object inverts
01485         object_extents.clamp(0.001f, F32_MAX);
01486 
01487         // move into first octant
01488         LLVector3 camera_offset_target_abs_norm = camera_offset_target;
01489         camera_offset_target_abs_norm.abs();
01490         // make sure offset is non-zero
01491         camera_offset_target_abs_norm.clamp(0.001f, F32_MAX);
01492         camera_offset_target_abs_norm.normVec();
01493 
01494         // find camera position relative to normalized object extents
01495         LLVector3 camera_offset_target_scaled = camera_offset_target_abs_norm;
01496         camera_offset_target_scaled.mV[VX] /= object_extents.mV[VX];
01497         camera_offset_target_scaled.mV[VY] /= object_extents.mV[VY];
01498         camera_offset_target_scaled.mV[VZ] /= object_extents.mV[VZ];
01499 
01500         if (camera_offset_target_scaled.mV[VX] > camera_offset_target_scaled.mV[VY] && 
01501                 camera_offset_target_scaled.mV[VX] > camera_offset_target_scaled.mV[VZ])
01502         {
01503                 if (camera_offset_target_abs_norm.mV[VX] < 0.001f)
01504                 {
01505                         obj_min_distance = object_extents.mV[VX] * 0.5f;
01506                 }
01507                 else
01508                 {
01509                         obj_min_distance = object_extents.mV[VX] * 0.5f / camera_offset_target_abs_norm.mV[VX];
01510                 }
01511         }
01512         else if (camera_offset_target_scaled.mV[VY] > camera_offset_target_scaled.mV[VZ])
01513         {
01514                 if (camera_offset_target_abs_norm.mV[VY] < 0.001f)
01515                 {
01516                         obj_min_distance = object_extents.mV[VY] * 0.5f;
01517                 }
01518                 else
01519                 {
01520                         obj_min_distance = object_extents.mV[VY] * 0.5f / camera_offset_target_abs_norm.mV[VY];
01521                 }
01522         }
01523         else
01524         {
01525                 if (camera_offset_target_abs_norm.mV[VZ] < 0.001f)
01526                 {
01527                         obj_min_distance = object_extents.mV[VZ] * 0.5f;
01528                 }
01529                 else
01530                 {
01531                         obj_min_distance = object_extents.mV[VZ] * 0.5f / camera_offset_target_abs_norm.mV[VZ];
01532                 }
01533         }
01534 
01535         LLVector3 object_split_axis;
01536         LLVector3 target_offset_scaled = target_offset_origin;
01537         target_offset_scaled.abs();
01538         target_offset_scaled.normVec();
01539         target_offset_scaled.mV[VX] /= object_extents.mV[VX];
01540         target_offset_scaled.mV[VY] /= object_extents.mV[VY];
01541         target_offset_scaled.mV[VZ] /= object_extents.mV[VZ];
01542 
01543         if (target_offset_scaled.mV[VX] > target_offset_scaled.mV[VY] && 
01544                 target_offset_scaled.mV[VX] > target_offset_scaled.mV[VZ])
01545         {
01546                 object_split_axis = LLVector3::x_axis;
01547         }
01548         else if (target_offset_scaled.mV[VY] > target_offset_scaled.mV[VZ])
01549         {
01550                 object_split_axis = LLVector3::y_axis;
01551         }
01552         else
01553         {
01554                 object_split_axis = LLVector3::z_axis;
01555         }
01556 
01557         LLVector3 camera_offset_object(getCameraPositionAgent() - mFocusObject->getPositionAgent());
01558 
01559         // length projected orthogonal to target offset
01560         F32 camera_offset_dist = (camera_offset_object - target_offset_dir * (camera_offset_object * target_offset_dir)).magVec();
01561 
01562         // calculate whether the target point would be "visible" if it were outside the bounding box
01563         // on the opposite of the splitting plane defined by object_split_axis;
01564         BOOL exterior_target_visible = FALSE;
01565         if (camera_offset_dist > object_radius)
01566         {
01567                 // target is visible from camera, so turn off fov zoom
01568                 exterior_target_visible = TRUE;
01569         }
01570 
01571         F32 camera_offset_clip = camera_offset_object * object_split_axis;
01572         F32 target_offset_clip = target_offset_dir * object_split_axis;
01573 
01574         // target has moved outside of object extents
01575         // check to see if camera and target are on same side 
01576         if (target_outside_object_extents)
01577         {
01578                 if (camera_offset_clip > 0.f && target_offset_clip > 0.f)
01579                 {
01580                         return FALSE;
01581                 }
01582                 else if (camera_offset_clip < 0.f && target_offset_clip < 0.f)
01583                 {
01584                         return FALSE;
01585                 }
01586         }
01587 
01588         // clamp obj distance to diagonal of 10 by 10 cube
01589         obj_min_distance = llmin(obj_min_distance, 10.f * F_SQRT3);
01590 
01591         obj_min_distance += gCamera->getNear() + (soft_limit ? 0.1f : 0.2f);
01592         
01593         return TRUE;
01594 }
01595 
01596 F32 LLAgent::getCameraZoomFraction()
01597 {
01598         // 0.f -> camera zoomed all the way out
01599         // 1.f -> camera zoomed all the way in
01600         LLObjectSelectionHandle selection = gSelectMgr->getSelection();
01601         if (selection->getObjectCount() && selection->getSelectType() == SELECT_TYPE_HUD)
01602         {
01603                 // already [0,1]
01604                 return mAvatarObject->mHUDTargetZoom;
01605         }
01606         else if (mFocusOnAvatar && cameraThirdPerson())
01607         {
01608                 return clamp_rescale(mCameraZoomFraction, MIN_ZOOM_FRACTION, MAX_ZOOM_FRACTION, 1.f, 0.f);
01609         }
01610         else if (cameraCustomizeAvatar())
01611         {
01612                 F32 distance = (F32)mCameraFocusOffsetTarget.magVec();
01613                 return clamp_rescale(distance, APPEARANCE_MIN_ZOOM, APPEARANCE_MAX_ZOOM, 1.f, 0.f );
01614         }
01615         else
01616         {
01617                 F32 min_zoom;
01618                 const F32 DIST_FUDGE = 16.f; // meters
01619                 F32 max_zoom = gWorldPointer ? llmin(mDrawDistance - DIST_FUDGE, 
01620                                                                 gWorldPointer->getRegionWidthInMeters() - DIST_FUDGE,
01621                                                                 MAX_CAMERA_DISTANCE_FROM_AGENT) : MAX_CAMERA_DISTANCE_FROM_AGENT;
01622 
01623                 F32 distance = (F32)mCameraFocusOffsetTarget.magVec();
01624                 if (mFocusObject.notNull())
01625                 {
01626                         if (mFocusObject->isAvatar())
01627                         {
01628                                 min_zoom = AVATAR_MIN_ZOOM;
01629                         }
01630                         else
01631                         {
01632                                 min_zoom = OBJECT_MIN_ZOOM;
01633                         }
01634                 }
01635                 else
01636                 {
01637                         min_zoom = LAND_MIN_ZOOM;
01638                 }
01639 
01640                 return clamp_rescale(distance, min_zoom, max_zoom, 1.f, 0.f);
01641         }
01642 }
01643 
01644 void LLAgent::setCameraZoomFraction(F32 fraction)
01645 {
01646         // 0.f -> camera zoomed all the way out
01647         // 1.f -> camera zoomed all the way in
01648         LLObjectSelectionHandle selection = gSelectMgr->getSelection();
01649 
01650         if (selection->getObjectCount() && selection->getSelectType() == SELECT_TYPE_HUD)
01651         {
01652                 mAvatarObject->mHUDTargetZoom = fraction;
01653         }
01654         else if (mFocusOnAvatar && cameraThirdPerson())
01655         {
01656                 mCameraZoomFraction = rescale(fraction, 0.f, 1.f, MAX_ZOOM_FRACTION, MIN_ZOOM_FRACTION);
01657         }
01658         else if (cameraCustomizeAvatar())
01659         {
01660                 LLVector3d camera_offset_dir = mCameraFocusOffsetTarget;
01661                 camera_offset_dir.normVec();
01662                 mCameraFocusOffsetTarget = camera_offset_dir * rescale(fraction, 0.f, 1.f, APPEARANCE_MAX_ZOOM, APPEARANCE_MIN_ZOOM);
01663         }
01664         else
01665         {
01666                 F32 min_zoom = LAND_MIN_ZOOM;
01667                 const F32 DIST_FUDGE = 16.f; // meters
01668                 F32 max_zoom = llmin(mDrawDistance - DIST_FUDGE, 
01669                                                                 gWorldPointer->getRegionWidthInMeters() - DIST_FUDGE,
01670                                                                 MAX_CAMERA_DISTANCE_FROM_AGENT);
01671 
01672                 if (mFocusObject.notNull())
01673                 {
01674                         if (mFocusObject.notNull())
01675                         {
01676                                 if (mFocusObject->isAvatar())
01677                                 {
01678                                         min_zoom = AVATAR_MIN_ZOOM;
01679                                 }
01680                                 else
01681                                 {
01682                                         min_zoom = OBJECT_MIN_ZOOM;
01683                                 }
01684                         }
01685                 }
01686 
01687                 LLVector3d camera_offset_dir = mCameraFocusOffsetTarget;
01688                 camera_offset_dir.normVec();
01689                 mCameraFocusOffsetTarget = camera_offset_dir * rescale(fraction, 0.f, 1.f, max_zoom, min_zoom);
01690         }
01691         startCameraAnimation();
01692 }
01693 
01694 
01695 //-----------------------------------------------------------------------------
01696 // cameraOrbitAround()
01697 //-----------------------------------------------------------------------------
01698 void LLAgent::cameraOrbitAround(const F32 radians)
01699 {
01700         LLObjectSelectionHandle selection = gSelectMgr->getSelection();
01701         if (selection->getObjectCount() && selection->getSelectType() == SELECT_TYPE_HUD)
01702         {
01703                 // do nothing for hud selection
01704         }
01705         else if (mFocusOnAvatar && (mCameraMode == CAMERA_MODE_THIRD_PERSON || mCameraMode == CAMERA_MODE_FOLLOW))
01706         {
01707                 mFrameAgent.rotate(radians, getReferenceUpVector());
01708         }
01709         else
01710         {
01711                 mCameraFocusOffsetTarget.rotVec(radians, 0.f, 0.f, 1.f);
01712                 
01713                 cameraZoomIn(1.f);
01714         }
01715 }
01716 
01717 
01718 //-----------------------------------------------------------------------------
01719 // cameraOrbitOver()
01720 //-----------------------------------------------------------------------------
01721 void LLAgent::cameraOrbitOver(const F32 angle)
01722 {
01723         LLObjectSelectionHandle selection = gSelectMgr->getSelection();
01724         if (selection->getObjectCount() && selection->getSelectType() == SELECT_TYPE_HUD)
01725         {
01726                 // do nothing for hud selection
01727         }
01728         else if (mFocusOnAvatar && mCameraMode == CAMERA_MODE_THIRD_PERSON)
01729         {
01730                 pitch(angle);
01731         }
01732         else
01733         {
01734                 LLVector3 camera_offset_unit(mCameraFocusOffsetTarget);
01735                 camera_offset_unit.normVec();
01736 
01737                 F32 angle_from_up = acos( camera_offset_unit * getReferenceUpVector() );
01738 
01739                 LLVector3d left_axis;
01740                 left_axis.setVec(gCamera->getLeftAxis());
01741                 F32 new_angle = llclamp(angle_from_up - angle, 1.f * DEG_TO_RAD, 179.f * DEG_TO_RAD);
01742                 mCameraFocusOffsetTarget.rotVec(angle_from_up - new_angle, left_axis);
01743 
01744                 cameraZoomIn(1.f);
01745         }
01746 }
01747 
01748 //-----------------------------------------------------------------------------
01749 // cameraZoomIn()
01750 //-----------------------------------------------------------------------------
01751 void LLAgent::cameraZoomIn(const F32 fraction)
01752 {
01753         if (gDisconnected)
01754         {
01755                 return;
01756         }
01757 
01758         LLObjectSelectionHandle selection = gSelectMgr->getSelection();
01759         if (selection->getObjectCount() && selection->getSelectType() == SELECT_TYPE_HUD)
01760         {
01761                 // just update hud zoom level
01762                 mAvatarObject->mHUDTargetZoom /= fraction;
01763                 return;
01764         }
01765 
01766 
01767         LLVector3d      camera_offset(mCameraFocusOffsetTarget);
01768         LLVector3d      camera_offset_unit(mCameraFocusOffsetTarget);
01769         F32 min_zoom = LAND_MIN_ZOOM;
01770         F32 current_distance = (F32)camera_offset_unit.normVec();
01771         F32 new_distance = current_distance * fraction;
01772 
01773         // Don't move through focus point
01774         if (mFocusObject)
01775         {
01776                 LLVector3 camera_offset_dir((F32)camera_offset_unit.mdV[VX], (F32)camera_offset_unit.mdV[VY], (F32)camera_offset_unit.mdV[VZ]);
01777 
01778                 if (mFocusObject->isAvatar())
01779                 {
01780                         calcCameraMinDistance(min_zoom);
01781                 }
01782                 else
01783                 {
01784                         min_zoom = OBJECT_MIN_ZOOM;
01785                 }
01786         }
01787 
01788         new_distance = llmax(new_distance, min_zoom); 
01789 
01790         // Don't zoom too far back
01791         const F32 DIST_FUDGE = 16.f; // meters
01792         F32 max_distance = llmin(mDrawDistance - DIST_FUDGE, 
01793                                                          gWorldPointer->getRegionWidthInMeters() - DIST_FUDGE );
01794 
01795         if (new_distance > max_distance)
01796         {
01797                 new_distance = max_distance;
01798 
01799                 /*
01800                 // Unless camera is unlocked
01801                 if (!LLViewerCamera::sDisableCameraConstraints)
01802                 {
01803                         return;
01804                 }
01805                 */
01806         }
01807 
01808         if( cameraCustomizeAvatar() )
01809         {
01810                 new_distance = llclamp( new_distance, APPEARANCE_MIN_ZOOM, APPEARANCE_MAX_ZOOM );
01811         }
01812 
01813         mCameraFocusOffsetTarget = new_distance * camera_offset_unit;
01814 }
01815 
01816 //-----------------------------------------------------------------------------
01817 // cameraOrbitIn()
01818 //-----------------------------------------------------------------------------
01819 void LLAgent::cameraOrbitIn(const F32 meters)
01820 {
01821         if (mFocusOnAvatar && mCameraMode == CAMERA_MODE_THIRD_PERSON)
01822         {
01823                 F32 camera_offset_dist = llmax(0.001f, mCameraOffsetDefault.magVec());
01824                 
01825                 mCameraZoomFraction = (mTargetCameraDistance - meters) / camera_offset_dist;
01826 
01827                 if (!gSavedSettings.getBOOL("FreezeTime") && mCameraZoomFraction < MIN_ZOOM_FRACTION && meters > 0.f)
01828                 {
01829                         // No need to animate, camera is already there.
01830                         changeCameraToMouselook(FALSE);
01831                 }
01832 
01833                 mCameraZoomFraction = llclamp(mCameraZoomFraction, MIN_ZOOM_FRACTION, MAX_ZOOM_FRACTION);
01834         }
01835         else
01836         {
01837                 LLVector3d      camera_offset(mCameraFocusOffsetTarget);
01838                 LLVector3d      camera_offset_unit(mCameraFocusOffsetTarget);
01839                 F32 current_distance = (F32)camera_offset_unit.normVec();
01840                 F32 new_distance = current_distance - meters;
01841                 F32 min_zoom = LAND_MIN_ZOOM;
01842                 
01843                 // Don't move through focus point
01844                 if (mFocusObject.notNull())
01845                 {
01846                         if (mFocusObject->isAvatar())
01847                         {
01848                                 min_zoom = AVATAR_MIN_ZOOM;
01849                         }
01850                         else
01851                         {
01852                                 min_zoom = OBJECT_MIN_ZOOM;
01853                         }
01854                 }
01855 
01856                 new_distance = llmax(new_distance, min_zoom);
01857 
01858                 // Don't zoom too far back
01859                 const F32 DIST_FUDGE = 16.f; // meters
01860                 F32 max_distance = llmin(mDrawDistance - DIST_FUDGE, 
01861                                                                  gWorldPointer->getRegionWidthInMeters() - DIST_FUDGE );
01862 
01863                 if (new_distance > max_distance)
01864                 {
01865                         // Unless camera is unlocked
01866                         if (!gSavedSettings.getBOOL("DisableCameraConstraints"))
01867                         {
01868                                 return;
01869                         }
01870                 }
01871 
01872                 if( CAMERA_MODE_CUSTOMIZE_AVATAR == getCameraMode() )
01873                 {
01874                         llclamp( new_distance, APPEARANCE_MIN_ZOOM, APPEARANCE_MAX_ZOOM );
01875                 }
01876 
01877                 // Compute new camera offset
01878                 mCameraFocusOffsetTarget = new_distance * camera_offset_unit;
01879                 cameraZoomIn(1.f);
01880         }
01881 }
01882 
01883 
01884 //-----------------------------------------------------------------------------
01885 // cameraPanIn()
01886 //-----------------------------------------------------------------------------
01887 void LLAgent::cameraPanIn(F32 meters)
01888 {
01889         LLVector3d at_axis;
01890         at_axis.setVec(gCamera->getAtAxis());
01891 
01892         mFocusTargetGlobal += meters * at_axis;
01893         mFocusGlobal = mFocusTargetGlobal;
01894         // don't enforce zoom constraints as this is the only way for users to get past them easily
01895         updateFocusOffset();
01896 }
01897 
01898 //-----------------------------------------------------------------------------
01899 // cameraPanLeft()
01900 //-----------------------------------------------------------------------------
01901 void LLAgent::cameraPanLeft(F32 meters)
01902 {
01903         LLVector3d left_axis;
01904         left_axis.setVec(gCamera->getLeftAxis());
01905 
01906         mFocusTargetGlobal += meters * left_axis;
01907         mFocusGlobal = mFocusTargetGlobal;
01908         cameraZoomIn(1.f);
01909         updateFocusOffset();
01910 }
01911 
01912 //-----------------------------------------------------------------------------
01913 // cameraPanUp()
01914 //-----------------------------------------------------------------------------
01915 void LLAgent::cameraPanUp(F32 meters)
01916 {
01917         LLVector3d up_axis;
01918         up_axis.setVec(gCamera->getUpAxis());
01919 
01920         mFocusTargetGlobal += meters * up_axis;
01921         mFocusGlobal = mFocusTargetGlobal;
01922         cameraZoomIn(1.f);
01923         updateFocusOffset();
01924 }
01925 
01926 //-----------------------------------------------------------------------------
01927 // setKey()
01928 //-----------------------------------------------------------------------------
01929 void LLAgent::setKey(const S32 direction, S32 &key)
01930 {
01931         if (direction > 0)
01932         {
01933                 key = 1;
01934         }
01935         else if (direction < 0)
01936         {
01937                 key = -1;
01938         }
01939         else
01940         {
01941                 key = 0;
01942         }
01943 }
01944 
01945 
01946 //-----------------------------------------------------------------------------
01947 // getControlFlags()
01948 //-----------------------------------------------------------------------------
01949 U32 LLAgent::getControlFlags()
01950 {
01951 /*
01952         // HACK -- avoids maintenance of control flags when camera mode is turned on or off,
01953         // only worries about it when the flags are measured
01954         if (mCameraMode == CAMERA_MODE_MOUSELOOK) 
01955         {
01956                 if ( !(mControlFlags & AGENT_CONTROL_MOUSELOOK) )
01957                 {
01958                         mControlFlags |= AGENT_CONTROL_MOUSELOOK;
01959                 }
01960         }
01961 */
01962         return mControlFlags;
01963 }
01964 
01965 //-----------------------------------------------------------------------------
01966 // setControlFlags()
01967 //-----------------------------------------------------------------------------
01968 void LLAgent::setControlFlags(U32 mask)
01969 {
01970         mControlFlags |= mask;
01971         mbFlagsDirty = TRUE;
01972 }
01973 
01974 
01975 //-----------------------------------------------------------------------------
01976 // clearControlFlags()
01977 //-----------------------------------------------------------------------------
01978 void LLAgent::clearControlFlags(U32 mask)
01979 {
01980         U32 old_flags = mControlFlags;
01981         mControlFlags &= ~mask;
01982         if (old_flags != mControlFlags)
01983         {
01984                 mbFlagsDirty = TRUE;
01985         }
01986 }
01987 
01988 //-----------------------------------------------------------------------------
01989 // controlFlagsDirty()
01990 //-----------------------------------------------------------------------------
01991 BOOL LLAgent::controlFlagsDirty() const
01992 {
01993         return mbFlagsDirty;
01994 }
01995 
01996 //-----------------------------------------------------------------------------
01997 // enableControlFlagReset()
01998 //-----------------------------------------------------------------------------
01999 void LLAgent::enableControlFlagReset()
02000 {
02001         mbFlagsNeedReset = TRUE;
02002 }
02003 
02004 //-----------------------------------------------------------------------------
02005 // resetControlFlags()
02006 //-----------------------------------------------------------------------------
02007 void LLAgent::resetControlFlags()
02008 {
02009         if (mbFlagsNeedReset)
02010         {
02011                 mbFlagsNeedReset = FALSE;
02012                 mbFlagsDirty = FALSE;
02013                 // reset all of the ephemeral flags
02014                 // some flags are managed elsewhere
02015                 mControlFlags &= AGENT_CONTROL_AWAY | AGENT_CONTROL_FLY | AGENT_CONTROL_MOUSELOOK;
02016         }
02017 }
02018 
02019 //-----------------------------------------------------------------------------
02020 // setAFK()
02021 //-----------------------------------------------------------------------------
02022 void LLAgent::setAFK()
02023 {
02024         // Drones can't go AFK
02025         if (gNoRender)
02026         {
02027                 return;
02028         }
02029 
02030         if (!gAgent.getRegion())
02031         {
02032                 // Don't set AFK if we're not talking to a region yet.
02033                 return;
02034         }
02035 
02036         if (!(mControlFlags & AGENT_CONTROL_AWAY))
02037         {
02038                 sendAnimationRequest(ANIM_AGENT_AWAY, ANIM_REQUEST_START);
02039                 setControlFlags(AGENT_CONTROL_AWAY | AGENT_CONTROL_STOP);
02040                 gAwayTimer.start();
02041                 if (gAFKMenu)
02042                 {
02043                         //*TODO:Translate
02044                         gAFKMenu->setLabel(LLString("Set Not Away"));
02045                 }
02046         }
02047 }
02048 
02049 //-----------------------------------------------------------------------------
02050 // clearAFK()
02051 //-----------------------------------------------------------------------------
02052 void LLAgent::clearAFK()
02053 {
02054         gAwayTriggerTimer.reset();
02055 
02056         // Gods can sometimes get into away state (via gestures)
02057         // without setting the appropriate control flag. JC
02058         LLVOAvatar* av = mAvatarObject;
02059         if (mControlFlags & AGENT_CONTROL_AWAY
02060                 || (av
02061                         && (av->mSignaledAnimations.find(ANIM_AGENT_AWAY) != av->mSignaledAnimations.end())))
02062         {
02063                 sendAnimationRequest(ANIM_AGENT_AWAY, ANIM_REQUEST_STOP);
02064                 clearControlFlags(AGENT_CONTROL_AWAY);
02065                 if (gAFKMenu)
02066                 {
02067                         //*TODO:Translate
02068                         gAFKMenu->setLabel(LLString("Set Away"));
02069                 }
02070         }
02071 }
02072 
02073 //-----------------------------------------------------------------------------
02074 // getAFK()
02075 //-----------------------------------------------------------------------------
02076 BOOL LLAgent::getAFK() const
02077 {
02078         return (mControlFlags & AGENT_CONTROL_AWAY) != 0;
02079 }
02080 
02081 //-----------------------------------------------------------------------------
02082 // setBusy()
02083 //-----------------------------------------------------------------------------
02084 void LLAgent::setBusy()
02085 {
02086         sendAnimationRequest(ANIM_AGENT_BUSY, ANIM_REQUEST_START);
02087         mIsBusy = TRUE;
02088         if (gBusyMenu)
02089         {
02090                 //*TODO:Translate
02091                 gBusyMenu->setLabel(LLString("Set Not Busy"));
02092         }
02093         if (gFloaterMute)
02094         {
02095                 gFloaterMute->updateButtons();
02096         }
02097 }
02098 
02099 //-----------------------------------------------------------------------------
02100 // clearBusy()
02101 //-----------------------------------------------------------------------------
02102 void LLAgent::clearBusy()
02103 {
02104         mIsBusy = FALSE;
02105         sendAnimationRequest(ANIM_AGENT_BUSY, ANIM_REQUEST_STOP);
02106         if (gBusyMenu)
02107         {
02108                 //*TODO:Translate
02109                 gBusyMenu->setLabel(LLString("Set Busy"));
02110         }
02111         if (gFloaterMute)
02112         {
02113                 gFloaterMute->updateButtons();
02114         }
02115 }
02116 
02117 //-----------------------------------------------------------------------------
02118 // getBusy()
02119 //-----------------------------------------------------------------------------
02120 BOOL LLAgent::getBusy() const
02121 {
02122         return mIsBusy;
02123 }
02124 
02125 
02126 //-----------------------------------------------------------------------------
02127 // startAutoPilotGlobal()
02128 //-----------------------------------------------------------------------------
02129 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)
02130 {
02131         if (!gAgent.getAvatarObject() || !gWorldPointer)
02132         {
02133                 return;
02134         }
02135         
02136         mAutoPilotFinishedCallback = finish_callback;
02137         mAutoPilotCallbackData = callback_data;
02138         mAutoPilotRotationThreshold = rot_threshold;
02139         mAutoPilotBehaviorName = behavior_name;
02140 
02141         LLVector3d delta_pos( target_global );
02142         delta_pos -= getPositionGlobal();
02143         F64 distance = delta_pos.magVec();
02144         LLVector3d trace_target = target_global;
02145 
02146         trace_target.mdV[VZ] -= 10.f;
02147 
02148         LLVector3d intersection;
02149         LLVector3 normal;
02150         LLViewerObject *hit_obj;
02151         F32 heightDelta = gWorldPointer->resolveStepHeightGlobal(NULL, target_global, trace_target, intersection, normal, &hit_obj);
02152 
02153         if (stop_distance > 0.f)
02154         {
02155                 mAutoPilotStopDistance = stop_distance;
02156         }
02157         else
02158         {
02159                 // Guess at a reasonable stop distance.
02160                 mAutoPilotStopDistance = fsqrtf( distance );
02161                 if (mAutoPilotStopDistance < 0.5f) 
02162                 {
02163                         mAutoPilotStopDistance = 0.5f;
02164                 }
02165         }
02166 
02167         mAutoPilotFlyOnStop = getFlying();
02168 
02169         if (distance > 30.0)
02170         {
02171                 setFlying(TRUE);
02172         }
02173 
02174         if ( distance > 1.f && heightDelta > (sqrtf(mAutoPilotStopDistance) + 1.f))
02175         {
02176                 setFlying(TRUE);
02177                 mAutoPilotFlyOnStop = TRUE;
02178         }
02179 
02180         mAutoPilot = TRUE;
02181         mAutoPilotTargetGlobal = target_global;
02182 
02183         // trace ray down to find height of destination from ground
02184         LLVector3d traceEndPt = target_global;
02185         traceEndPt.mdV[VZ] -= 20.f;
02186 
02187         LLVector3d targetOnGround;
02188         LLVector3 groundNorm;
02189         LLViewerObject *obj;
02190 
02191         gWorldPointer->resolveStepHeightGlobal(NULL, target_global, traceEndPt, targetOnGround, groundNorm, &obj);
02192         F64 target_height = llmax((F64)gAgent.getAvatarObject()->getPelvisToFoot(), target_global.mdV[VZ] - targetOnGround.mdV[VZ]);
02193 
02194         // clamp z value of target to minimum height above ground
02195         mAutoPilotTargetGlobal.mdV[VZ] = targetOnGround.mdV[VZ] + target_height;
02196         mAutoPilotTargetDist = (F32)dist_vec(gAgent.getPositionGlobal(), mAutoPilotTargetGlobal);
02197         if (target_rotation)
02198         {
02199                 mAutoPilotUseRotation = TRUE;
02200                 mAutoPilotTargetFacing = LLVector3::x_axis * *target_rotation;
02201                 mAutoPilotTargetFacing.mV[VZ] = 0.f;
02202                 mAutoPilotTargetFacing.normVec();
02203         }
02204         else
02205         {
02206                 mAutoPilotUseRotation = FALSE;
02207         }
02208 
02209         mAutoPilotNoProgressFrameCount = 0;
02210 }
02211 
02212 
02213 //-----------------------------------------------------------------------------
02214 // startFollowPilot()
02215 //-----------------------------------------------------------------------------
02216 void LLAgent::startFollowPilot(const LLUUID &leader_id)
02217 {
02218         if (!mAutoPilot) return;
02219 
02220         mLeaderID = leader_id;
02221         if ( mLeaderID.isNull() ) return;
02222 
02223         LLViewerObject* object = gObjectList.findObject(mLeaderID);
02224         if (!object) 
02225         {
02226                 mLeaderID = LLUUID::null;
02227                 return;
02228         }
02229 
02230         startAutoPilotGlobal(object->getPositionGlobal());
02231 }
02232 
02233 
02234 //-----------------------------------------------------------------------------
02235 // stopAutoPilot()
02236 //-----------------------------------------------------------------------------
02237 void LLAgent::stopAutoPilot(BOOL user_cancel)
02238 {
02239         if (mAutoPilot)
02240         {
02241                 mAutoPilot = FALSE;
02242                 if (mAutoPilotUseRotation && !user_cancel)
02243                 {
02244                         resetAxes(mAutoPilotTargetFacing);
02245                 }
02246                 //NB: auto pilot can terminate for a reason other than reaching the destination
02247                 if (mAutoPilotFinishedCallback)
02248                 {
02249                         mAutoPilotFinishedCallback(!user_cancel && dist_vec(gAgent.getPositionGlobal(), mAutoPilotTargetGlobal) < mAutoPilotStopDistance, mAutoPilotCallbackData);
02250                 }
02251                 mLeaderID = LLUUID::null;
02252 
02253                 // If the user cancelled, don't change the fly state
02254                 if (!user_cancel)
02255                 {
02256                         setFlying(mAutoPilotFlyOnStop);
02257                 }
02258                 setControlFlags(AGENT_CONTROL_STOP);
02259 
02260                 if (user_cancel && !mAutoPilotBehaviorName.empty())
02261                 {
02262                         if (mAutoPilotBehaviorName == "Sit")
02263                                 LLNotifyBox::showXml("CancelledSit");
02264                         else if (mAutoPilotBehaviorName == "Attach")
02265                                 LLNotifyBox::showXml("CancelledAttach");
02266                         else
02267                                 LLNotifyBox::showXml("Cancelled");
02268                 }
02269         }
02270 }
02271 
02272 
02273 // Returns necessary agent pitch and yaw changes, radians.
02274 //-----------------------------------------------------------------------------
02275 // autoPilot()
02276 //-----------------------------------------------------------------------------
02277 void LLAgent::autoPilot(F32 *delta_yaw)
02278 {
02279         if (mAutoPilot)
02280         {
02281                 if (!mLeaderID.isNull())
02282                 {
02283                         LLViewerObject* object = gObjectList.findObject(mLeaderID);
02284                         if (!object) 
02285                         {
02286                                 stopAutoPilot();
02287                                 return;
02288                         }
02289                         mAutoPilotTargetGlobal = object->getPositionGlobal();
02290                 }
02291                 
02292                 if (!mAvatarObject)
02293                 {
02294                         return;
02295                 }
02296 
02297                 if (mAvatarObject->mInAir)
02298                 {
02299                         setFlying(TRUE);
02300                 }
02301         
02302                 LLVector3 at;
02303                 at.setVec(mFrameAgent.getAtAxis());
02304                 LLVector3 target_agent = getPosAgentFromGlobal(mAutoPilotTargetGlobal);
02305                 LLVector3 direction = target_agent - getPositionAgent();
02306 
02307                 F32 target_dist = direction.magVec();
02308 
02309                 if (target_dist >= mAutoPilotTargetDist)
02310                 {
02311                         mAutoPilotNoProgressFrameCount++;
02312                         if (mAutoPilotNoProgressFrameCount > AUTOPILOT_MAX_TIME_NO_PROGRESS * gFPSClamped)
02313                         {
02314                                 stopAutoPilot();
02315                                 return;
02316                         }
02317                 }
02318 
02319                 mAutoPilotTargetDist = target_dist;
02320 
02321                 // Make this a two-dimensional solution
02322                 at.mV[VZ] = 0.f;
02323                 direction.mV[VZ] = 0.f;
02324 
02325                 at.normVec();
02326                 F32 xy_distance = direction.normVec();
02327 
02328                 F32 yaw = 0.f;
02329                 if (mAutoPilotTargetDist > mAutoPilotStopDistance)
02330                 {
02331                         yaw = angle_between(mFrameAgent.getAtAxis(), direction);
02332                 }
02333                 else if (mAutoPilotUseRotation)
02334                 {
02335                         // we're close now just aim at target facing
02336                         yaw = angle_between(at, mAutoPilotTargetFacing);
02337                         direction = mAutoPilotTargetFacing;
02338                 }
02339 
02340                 yaw = 4.f * yaw / gFPSClamped;
02341 
02342                 // figure out which direction to turn
02343                 LLVector3 scratch(at % direction);
02344 
02345                 if (scratch.mV[VZ] > 0.f)
02346                 {
02347                         setControlFlags(AGENT_CONTROL_YAW_POS);
02348                 }
02349                 else
02350                 {
02351                         yaw = -yaw;
02352                         setControlFlags(AGENT_CONTROL_YAW_NEG);
02353                 }
02354 
02355                 *delta_yaw = yaw;
02356 
02357                 // Compute when to start slowing down and when to stop
02358                 F32 stop_distance = mAutoPilotStopDistance;
02359                 F32 slow_distance;
02360                 if (getFlying())
02361                 {
02362                         slow_distance = llmax(6.f, mAutoPilotStopDistance + 5.f);
02363                         stop_distance = llmax(2.f, mAutoPilotStopDistance);
02364                 }
02365                 else
02366                 {
02367                         slow_distance = llmax(3.f, mAutoPilotStopDistance + 2.f);
02368                 }
02369 
02370                 // If we're flying, handle autopilot points above or below you.
02371                 if (getFlying() && xy_distance < AUTOPILOT_HEIGHT_ADJUST_DISTANCE)
02372                 {
02373                         if (mAvatarObject)
02374                         {
02375                                 F64 current_height = mAvatarObject->getPositionGlobal().mdV[VZ];
02376                                 F32 delta_z = (F32)(mAutoPilotTargetGlobal.mdV[VZ] - current_height);
02377                                 F32 slope = delta_z / xy_distance;
02378                                 if (slope > 0.45f && delta_z > 6.f)
02379                                 {
02380                                         setControlFlags(AGENT_CONTROL_FAST_UP | AGENT_CONTROL_UP_POS);
02381                                 }
02382                                 else if (slope > 0.002f && delta_z > 0.5f)
02383                                 {
02384                                         setControlFlags(AGENT_CONTROL_UP_POS);
02385                                 }
02386                                 else if (slope < -0.45f && delta_z < -6.f && current_height > AUTOPILOT_MIN_TARGET_HEIGHT_OFF_GROUND)
02387                                 {
02388                                         setControlFlags(AGENT_CONTROL_FAST_UP | AGENT_CONTROL_UP_NEG);
02389                                 }
02390                                 else if (slope < -0.002f && delta_z < -0.5f && current_height > AUTOPILOT_MIN_TARGET_HEIGHT_OFF_GROUND)
02391                                 {
02392                                         setControlFlags(AGENT_CONTROL_UP_NEG);
02393                                 }
02394                         }
02395                 }
02396 
02397                 //  calculate delta rotation to target heading
02398                 F32 delta_target_heading = angle_between(mFrameAgent.getAtAxis(), mAutoPilotTargetFacing);
02399 
02400                 if (xy_distance > slow_distance && yaw < (F_PI / 10.f))
02401                 {
02402                         // walking/flying fast
02403                         setControlFlags(AGENT_CONTROL_FAST_AT | AGENT_CONTROL_AT_POS);
02404                 }
02405                 else if (mAutoPilotTargetDist > mAutoPilotStopDistance)
02406                 {
02407                         // walking/flying slow
02408                         if (at * direction > 0.9f)
02409                         {
02410                                 setControlFlags(AGENT_CONTROL_AT_POS);
02411                         }
02412                         else if (at * direction < -0.9f)
02413                         {
02414                                 setControlFlags(AGENT_CONTROL_AT_NEG);
02415                         }
02416                 }
02417 
02418                 // check to see if we need to keep rotating to target orientation
02419                 if (mAutoPilotTargetDist < mAutoPilotStopDistance)
02420                 {
02421                         setControlFlags(AGENT_CONTROL_STOP);
02422                         if(!mAutoPilotUseRotation || (delta_target_heading < mAutoPilotRotationThreshold))
02423                         {
02424                                 stopAutoPilot();
02425                         }
02426                 }
02427         }
02428 }
02429 
02430 
02431 //-----------------------------------------------------------------------------
02432 // propagate()
02433 //-----------------------------------------------------------------------------
02434 void LLAgent::propagate(const F32 dt)
02435 {
02436         // Update UI based on agent motion
02437         LLFloaterMove *floater_move = LLFloaterMove::getInstance();
02438         if (floater_move)
02439         {
02440                 floater_move->mForwardButton   ->setToggleState( mAtKey > 0 || mWalkKey > 0 );
02441                 floater_move->mBackwardButton  ->setToggleState( mAtKey < 0 || mWalkKey < 0 );
02442                 floater_move->mSlideLeftButton ->setToggleState( mLeftKey > 0 );
02443                 floater_move->mSlideRightButton->setToggleState( mLeftKey < 0 );
02444                 floater_move->mTurnLeftButton  ->setToggleState( mYawKey > 0.f );
02445                 floater_move->mTurnRightButton ->setToggleState( mYawKey < 0.f );
02446                 floater_move->mMoveUpButton    ->setToggleState( mUpKey > 0 );
02447                 floater_move->mMoveDownButton  ->setToggleState( mUpKey < 0 );
02448         }
02449 
02450         // handle rotation based on keyboard levels
02451         const F32 YAW_RATE = 90.f * DEG_TO_RAD;                         // radians per second
02452         yaw( YAW_RATE * mYawKey * dt );
02453 
02454         const F32 PITCH_RATE = 90.f * DEG_TO_RAD;                       // radians per second
02455         pitch(PITCH_RATE * (F32) mPitchKey * dt);
02456         
02457         // handle auto-land behavior
02458         if (mAvatarObject)
02459         {
02460                 BOOL in_air = mAvatarObject->mInAir;
02461                 LLVector3 land_vel = getVelocity();
02462                 land_vel.mV[VZ] = 0.f;
02463 
02464                 if (!in_air 
02465                         && mUpKey < 0 
02466                         && land_vel.magVecSquared() < MAX_VELOCITY_AUTO_LAND_SQUARED
02467                         && gSavedSettings.getBOOL("AutomaticFly"))
02468                 {
02469                         // land automatically
02470                         setFlying(FALSE);
02471                 }
02472         }
02473 
02474         // clear keys
02475         mAtKey = 0;
02476         mWalkKey = 0;
02477         mLeftKey = 0;
02478         mUpKey = 0;
02479         mYawKey = 0.f;
02480         mPitchKey = 0;
02481 }
02482 
02483 //-----------------------------------------------------------------------------
02484 // updateAgentPosition()
02485 //-----------------------------------------------------------------------------
02486 void LLAgent::updateAgentPosition(const F32 dt, const F32 yaw_radians, const S32 mouse_x, const S32 mouse_y)
02487 {
02488         propagate(dt);
02489 
02490         // static S32 cameraUpdateCount = 0;
02491 
02492         rotate(yaw_radians, 0, 0, 1);
02493         
02494         //
02495         // Check for water and land collision, set underwater flag
02496         //
02497 
02498         updateLookAt(mouse_x, mouse_y);
02499 }
02500 
02501 //-----------------------------------------------------------------------------
02502 // updateLookAt()
02503 //-----------------------------------------------------------------------------
02504 void LLAgent::updateLookAt(const S32 mouse_x, const S32 mouse_y)
02505 {
02506         static LLVector3 last_at_axis;
02507 
02508 
02509         if ( mAvatarObject.isNull() )
02510         {
02511                 return;
02512         }
02513 
02514         LLQuaternion av_inv_rot = ~mAvatarObject->mRoot.getWorldRotation();
02515         LLVector3 root_at = LLVector3::x_axis * mAvatarObject->mRoot.getWorldRotation();
02516 
02517         if      ((gViewerWindow->getMouseVelocityStat()->getCurrent() < 0.01f) &&
02518                 (root_at * last_at_axis > 0.95f ))
02519         {
02520                 LLVector3 vel = mAvatarObject->getVelocity();
02521                 if (vel.magVecSquared() > 4.f)
02522                 {
02523                         setLookAt(LOOKAT_TARGET_IDLE, mAvatarObject, vel * av_inv_rot);
02524                 }
02525                 else
02526                 {
02527                         // *FIX: rotate mframeagent by sit object's rotation?
02528                         LLQuaternion look_rotation = mAvatarObject->mIsSitting ? mAvatarObject->getRenderRotation() : mFrameAgent.getQuaternion(); // use camera's current rotation
02529                         LLVector3 look_offset = LLVector3(2.f, 0.f, 0.f) * look_rotation * av_inv_rot;
02530                         setLookAt(LOOKAT_TARGET_IDLE, mAvatarObject, look_offset);
02531                 }
02532                 last_at_axis = root_at;
02533                 return;
02534         }
02535 
02536         last_at_axis = root_at;
02537         
02538         if (CAMERA_MODE_CUSTOMIZE_AVATAR == getCameraMode())
02539         {
02540                 setLookAt(LOOKAT_TARGET_NONE, mAvatarObject, LLVector3(-2.f, 0.f, 0.f));        
02541         }
02542         else
02543         {
02544                 // Move head based on cursor position
02545                 ELookAtType lookAtType = LOOKAT_TARGET_NONE;
02546                 LLVector3 headLookAxis;
02547                 LLCoordFrame frameCamera = *((LLCoordFrame*)gCamera);
02548 
02549                 F32 x_from_center = mouse_x_from_center( mouse_x );     // range from -0.5 to 0.5
02550                 F32 y_from_center = mouse_y_from_center( mouse_y );     // range from -0.5 to 0.5
02551 
02552                 if (cameraMouselook())
02553                 {
02554                         lookAtType = LOOKAT_TARGET_MOUSELOOK;
02555                 }
02556                 else if (cameraThirdPerson())
02557                 {
02558                         frameCamera.yaw( - x_from_center * gSavedSettings.getF32("YawFromMousePosition") * DEG_TO_RAD);
02559                         frameCamera.pitch( - y_from_center * gSavedSettings.getF32("PitchFromMousePosition") * DEG_TO_RAD);
02560                         lookAtType = LOOKAT_TARGET_FREELOOK;
02561                 }
02562 
02563                 headLookAxis = frameCamera.getAtAxis();
02564                 // RN: we use world-space offset for mouselook and freelook
02565                 //headLookAxis = headLookAxis * av_inv_rot;
02566                 setLookAt(lookAtType, mAvatarObject, headLookAxis);
02567         }
02568 }
02569 
02570 // friends and operators
02571 
02572 std::ostream& operator<<(std::ostream &s, const LLAgent &agent)
02573 {
02574         // This is unfinished, but might never be used. 
02575         // We'll just leave it for now; we can always delete it.
02576         s << " { "
02577           << "  Frame = " << agent.mFrameAgent << "\n"
02578           << " }";
02579         return s;
02580 }
02581 
02582 
02583 // ------------------- Beginning of legacy LLCamera hack ----------------------
02584 // This section is included for legacy LLCamera support until
02585 // it is no longer needed.  Some legacy code must exist in 
02586 // non-legacy functions, and is labeled with "// legacy" comments.
02587 
02588 //-----------------------------------------------------------------------------
02589 // setAvatarObject()
02590 //-----------------------------------------------------------------------------
02591 void LLAgent::setAvatarObject(LLVOAvatar *avatar)                       
02592 { 
02593         mAvatarObject = avatar;
02594 
02595         if (!avatar)
02596         {
02597                 llinfos << "Setting LLAgent::mAvatarObject to NULL" << llendl;
02598                 return;
02599         }
02600 
02601         if (!mLookAt)
02602         {
02603                 mLookAt = (LLHUDEffectLookAt *)gHUDManager->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_LOOKAT);
02604         }
02605         if (!mPointAt)
02606         {
02607                 mPointAt = (LLHUDEffectPointAt *)gHUDManager->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINTAT);
02608         }
02609         
02610         if (!mLookAt.isNull())
02611         {
02612                 mLookAt->setSourceObject(avatar);
02613         }
02614         if (!mPointAt.isNull())
02615         {
02616                 mPointAt->setSourceObject(avatar);
02617         }
02618 
02619         sendAgentWearablesRequest();
02620 }
02621 
02622 // TRUE if your own avatar needs to be rendered.  Usually only
02623 // in third person and build.
02624 //-----------------------------------------------------------------------------
02625 // needsRenderAvatar()
02626 //-----------------------------------------------------------------------------
02627 BOOL LLAgent::needsRenderAvatar()
02628 {
02629         if (cameraMouselook() && !LLVOAvatar::sVisibleInFirstPerson)
02630         {
02631                 return FALSE;
02632         }
02633 
02634         return mShowAvatar && mGenderChosen;
02635 }
02636 
02637 // TRUE if we need to render your own avatar's head.
02638 BOOL LLAgent::needsRenderHead()
02639 {
02640         return mShowAvatar && !cameraMouselook();
02641 }
02642 
02643 //-----------------------------------------------------------------------------
02644 // startTyping()
02645 //-----------------------------------------------------------------------------
02646 void LLAgent::startTyping()
02647 {
02648         mTypingTimer.reset();
02649 
02650         if (getRenderState() & AGENT_STATE_TYPING)
02651         {
02652                 // already typing, don't trigger a different animation
02653                 return;
02654         }
02655         setRenderState(AGENT_STATE_TYPING);
02656 
02657         if (mChatTimer.getElapsedTimeF32() < 2.f)
02658         {
02659                 LLViewerObject* chatter = gObjectList.findObject(mLastChatterID);
02660                 if (chatter && chatter->isAvatar())
02661                 {
02662                         gAgent.setLookAt(LOOKAT_TARGET_RESPOND, chatter, LLVector3::zero);
02663                 }
02664         }
02665 
02666         if (gSavedSettings.getBOOL("PlayTypingAnim"))
02667         {
02668                 sendAnimationRequest(ANIM_AGENT_TYPE, ANIM_REQUEST_START);
02669         }
02670         sendChat("", 0, CHAT_TYPE_START, false);
02671 
02672         // Addition for avatar list support.
02673         // Makes the fact that this avatar is typing appear in the list
02674         if ( NULL != gFloaterAvatarList )
02675         {
02676                 LLAvatarListEntry *ent = gFloaterAvatarList->getAvatarEntry(getID());
02677                 if ( NULL != ent )
02678                 {
02679                         ent->setActivity(ACTIVITY_TYPING);
02680                 }
02681         }
02682 }
02683 
02684 //-----------------------------------------------------------------------------
02685 // stopTyping()
02686 //-----------------------------------------------------------------------------
02687 void LLAgent::stopTyping()
02688 {
02689         if (mRenderState & AGENT_STATE_TYPING)
02690         {
02691                 clearRenderState(AGENT_STATE_TYPING);
02692                 sendAnimationRequest(ANIM_AGENT_TYPE, ANIM_REQUEST_STOP);
02693                 sendChat("", 0, CHAT_TYPE_STOP, false);
02694         }
02695 }
02696 
02697 //-----------------------------------------------------------------------------
02698 // setRenderState()
02699 //-----------------------------------------------------------------------------
02700 void LLAgent::setRenderState(U8 newstate)
02701 {
02702         mRenderState |= newstate;
02703 }
02704 
02705 //-----------------------------------------------------------------------------
02706 // clearRenderState()
02707 //-----------------------------------------------------------------------------
02708 void LLAgent::clearRenderState(U8 clearstate)
02709 {
02710         mRenderState &= ~clearstate;
02711 }
02712 
02713 
02714 //-----------------------------------------------------------------------------
02715 // getRenderState()
02716 //-----------------------------------------------------------------------------
02717 U8 LLAgent::getRenderState()
02718 {
02719         if (gNoRender || gToolMgr == NULL || gSelectMgr == NULL || gKeyboard == NULL)
02720         {
02721                 return 0;
02722         }
02723 
02724         // *FIX: don't do stuff in a getter!  This is infinite loop city!
02725         if ((mTypingTimer.getElapsedTimeF32() > TYPING_TIMEOUT_SECS) 
02726                 && (mRenderState & AGENT_STATE_TYPING))
02727         {
02728                 stopTyping();
02729         }
02730         
02731         if ((!gSelectMgr->getSelection()->isEmpty() && gSelectMgr->shouldShowSelection())
02732                 || gToolMgr->getCurrentTool()->isEditing() )
02733         {
02734                 setRenderState(AGENT_STATE_EDITING);
02735         }
02736         else
02737         {
02738                 clearRenderState(AGENT_STATE_EDITING);
02739         }
02740 
02741         return mRenderState;
02742 }
02743 
02744 //-----------------------------------------------------------------------------
02745 //-----------------------------------------------------------------------------
02746 
02747 static const LLFloaterView::skip_list_t& get_skip_list()
02748 {
02749         static LLFloaterView::skip_list_t skip_list;
02750         skip_list.insert(gFloaterMap);
02751         return skip_list;
02752 }
02753 
02754 //-----------------------------------------------------------------------------
02755 // endAnimationUpdateUI()
02756 //-----------------------------------------------------------------------------
02757 void LLAgent::endAnimationUpdateUI()
02758 {
02759         if (mCameraMode == mLastCameraMode)
02760         {
02761                 // We're already done endAnimationUpdateUI for this transition.
02762                 return;
02763         }
02764 
02765         // clean up UI from mode we're leaving
02766         if ( mLastCameraMode == CAMERA_MODE_MOUSELOOK )
02767         {
02768                 // show mouse cursor
02769                 gViewerWindow->showCursor();
02770                 // show menus
02771                 gMenuBarView->setVisible(TRUE);
02772                 gStatusBar->setVisibleForMouselook(true);
02773 
02774                 gToolMgr->setCurrentToolset(gBasicToolset);
02775 
02776                 // Only pop if we have pushed...
02777                 if (TRUE == mViewsPushed)
02778                 {
02779                         mViewsPushed = FALSE;
02780                         gFloaterView->popVisibleAll(get_skip_list());
02781                 }
02782 
02783                 gAgent.setLookAt(LOOKAT_TARGET_CLEAR);
02784                 if( gMorphView )
02785                 {
02786                         gMorphView->setVisible( FALSE );
02787                 }
02788 
02789                 // Disable mouselook-specific animations
02790                 if (mAvatarObject)
02791                 {
02792                         if( mAvatarObject->isAnyAnimationSignaled(AGENT_GUN_AIM_ANIMS, NUM_AGENT_GUN_AIM_ANIMS) )
02793                         {
02794                                 if (mAvatarObject->mSignaledAnimations.find(ANIM_AGENT_AIM_RIFLE_R) != mAvatarObject->mSignaledAnimations.end())
02795                                 {
02796                                         sendAnimationRequest(ANIM_AGENT_AIM_RIFLE_R, ANIM_REQUEST_STOP);
02797                                         sendAnimationRequest(ANIM_AGENT_HOLD_RIFLE_R, ANIM_REQUEST_START);
02798                                 }
02799                                 if (mAvatarObject->mSignaledAnimations.find(ANIM_AGENT_AIM_HANDGUN_R) != mAvatarObject->mSignaledAnimations.end())
02800                                 {
02801                                         sendAnimationRequest(ANIM_AGENT_AIM_HANDGUN_R, ANIM_REQUEST_STOP);
02802                                         sendAnimationRequest(ANIM_AGENT_HOLD_HANDGUN_R, ANIM_REQUEST_START);
02803                                 }
02804                                 if (mAvatarObject->mSignaledAnimations.find(ANIM_AGENT_AIM_BAZOOKA_R) != mAvatarObject->mSignaledAnimations.end())
02805                                 {
02806                                         sendAnimationRequest(ANIM_AGENT_AIM_BAZOOKA_R, ANIM_REQUEST_STOP);
02807                                         sendAnimationRequest(ANIM_AGENT_HOLD_BAZOOKA_R, ANIM_REQUEST_START);
02808                                 }
02809                                 if (mAvatarObject->mSignaledAnimations.find(ANIM_AGENT_AIM_BOW_L) != mAvatarObject->mSignaledAnimations.end())
02810                                 {
02811                                         sendAnimationRequest(ANIM_AGENT_AIM_BOW_L, ANIM_REQUEST_STOP);
02812                                         sendAnimationRequest(ANIM_AGENT_HOLD_BOW_L, ANIM_REQUEST_START);
02813                                 }
02814                         }
02815                 }
02816         }
02817         else
02818         if(     mLastCameraMode == CAMERA_MODE_CUSTOMIZE_AVATAR )
02819         {
02820                 // make sure we ask to save changes
02821 
02822                 gToolMgr->setCurrentToolset(gBasicToolset);
02823 
02824                 // HACK: If we're quitting, and we were in customize avatar, don't
02825                 // let the mini-map go visible again. JC
02826                 if (!gQuitRequested)
02827                 {
02828                         gFloaterMap->popVisible();
02829                 }
02830 
02831                 if( gMorphView )
02832                 {
02833                         gMorphView->setVisible( FALSE );
02834                 }
02835 
02836                 if (mAvatarObject)
02837                 {
02838                         sendAnimationRequest(ANIM_AGENT_CUSTOMIZE, ANIM_REQUEST_STOP);
02839                         sendAnimationRequest(ANIM_AGENT_CUSTOMIZE_DONE, ANIM_REQUEST_START);
02840                 }
02841                 setLookAt(LOOKAT_TARGET_CLEAR);
02842         }
02843 
02844         //---------------------------------------------------------------------
02845         // Set up UI for mode we're entering
02846         //---------------------------------------------------------------------
02847         if (mCameraMode == CAMERA_MODE_MOUSELOOK)
02848         {
02849                 // hide menus
02850                 gMenuBarView->setVisible(FALSE);
02851                 gStatusBar->setVisibleForMouselook(false);
02852 
02853                 // clear out camera lag effect
02854                 mCameraLag.clearVec();
02855 
02856                 // JC - Added for always chat in third person option
02857                 gFocusMgr.setKeyboardFocus(NULL, NULL);
02858 
02859                 gToolMgr->setCurrentToolset(gMouselookToolset);
02860 
02861                 mViewsPushed = TRUE;
02862 
02863                 gFloaterView->pushVisibleAll(FALSE, get_skip_list());
02864 
02865                 if( gMorphView )
02866                 {
02867                         gMorphView->setVisible(FALSE);
02868                 }
02869 
02870                 gIMMgr->setFloaterOpen( FALSE );
02871                 gConsole->setVisible( TRUE );
02872 
02873                 if (mAvatarObject)
02874                 {
02875                         // Trigger mouselook-specific animations
02876                         if( mAvatarObject->isAnyAnimationSignaled(AGENT_GUN_HOLD_ANIMS, NUM_AGENT_GUN_HOLD_ANIMS) )
02877                         {
02878                                 if (mAvatarObject->mSignaledAnimations.find(ANIM_AGENT_HOLD_RIFLE_R) != mAvatarObject->mSignaledAnimations.end())
02879                                 {
02880                                         sendAnimationRequest(ANIM_AGENT_HOLD_RIFLE_R, ANIM_REQUEST_STOP);
02881                                         sendAnimationRequest(ANIM_AGENT_AIM_RIFLE_R, ANIM_REQUEST_START);
02882                                 }
02883                                 if (mAvatarObject->mSignaledAnimations.find(ANIM_AGENT_HOLD_HANDGUN_R) != mAvatarObject->mSignaledAnimations.end())
02884                                 {
02885                                         sendAnimationRequest(ANIM_AGENT_HOLD_HANDGUN_R, ANIM_REQUEST_STOP);
02886                                         sendAnimationRequest(ANIM_AGENT_AIM_HANDGUN_R, ANIM_REQUEST_START);
02887                                 }
02888                                 if (mAvatarObject->mSignaledAnimations.find(ANIM_AGENT_HOLD_BAZOOKA_R) != mAvatarObject->mSignaledAnimations.end())
02889                                 {
02890                                         sendAnimationRequest(ANIM_AGENT_HOLD_BAZOOKA_R, ANIM_REQUEST_STOP);
02891                                         sendAnimationRequest(ANIM_AGENT_AIM_BAZOOKA_R, ANIM_REQUEST_START);
02892                                 }
02893                                 if (mAvatarObject->mSignaledAnimations.find(ANIM_AGENT_HOLD_BOW_L) != mAvatarObject->mSignaledAnimations.end())
02894                                 {
02895                                         sendAnimationRequest(ANIM_AGENT_HOLD_BOW_L, ANIM_REQUEST_STOP);
02896                                         sendAnimationRequest(ANIM_AGENT_AIM_BOW_L, ANIM_REQUEST_START);
02897                                 }
02898                         }
02899                         if (mAvatarObject->getParent())
02900                         {
02901                                 LLVector3 at_axis = gCamera->getAtAxis();
02902                                 LLViewerObject* root_object = (LLViewerObject*)mAvatarObject->getRoot();
02903                                 if (root_object->flagCameraDecoupled())
02904                                 {
02905                                         resetAxes(at_axis);
02906                                 }
02907                                 else
02908                                 {
02909                                         resetAxes(at_axis * ~((LLViewerObject*)mAvatarObject->getParent())->getRenderRotation());
02910                                 }
02911                         }
02912                 }
02913 
02914         }
02915         else if (mCameraMode == CAMERA_MODE_CUSTOMIZE_AVATAR)
02916         {
02917                 gToolMgr->setCurrentToolset(gFaceEditToolset);
02918 
02919                 gFloaterMap->pushVisible(FALSE);
02920                 /*
02921                 LLView *view;
02922                 for (view = gFloaterView->getFirstChild(); view; view = gFloaterView->getNextChild())
02923                 {
02924                         view->pushVisible(FALSE);
02925                 }
02926                 */
02927 
02928                 if( gMorphView )
02929                 {
02930                         gMorphView->setVisible( TRUE );
02931                 }
02932 
02933                 // freeze avatar
02934                 if (mAvatarObject)
02935                 {
02936                         mPauseRequest = mAvatarObject->requestPause();
02937                 }
02938         }
02939 
02940         if (getAvatarObject())
02941         {
02942                 getAvatarObject()->updateAttachmentVisibility(mCameraMode);
02943         }
02944 
02945         gFloaterTools->dirty();
02946 
02947         // Don't let this be called more than once if the camera
02948         // mode hasn't changed.  --JC
02949         mLastCameraMode = mCameraMode;
02950 
02951 }
02952 
02953 
02954 //-----------------------------------------------------------------------------
02955 // updateCamera()
02956 //-----------------------------------------------------------------------------
02957 void LLAgent::updateCamera()
02958 {
02959         //Ventrella - changed camera_skyward to the new global "mCameraUpVector"
02960         mCameraUpVector = LLVector3::z_axis;
02961         //LLVector3     camera_skyward(0.f, 0.f, 1.f);
02962         //end Ventrella
02963 
02964         U32 camera_mode = mCameraAnimating ? mLastCameraMode : mCameraMode;
02965 
02966         validateFocusObject();
02967 
02968         if (!mAvatarObject.isNull() && 
02969                 mAvatarObject->mIsSitting &&
02970                 camera_mode == CAMERA_MODE_MOUSELOOK)
02971         {
02972                 //Ventrella
02973                 //changed camera_skyward to the new global "mCameraUpVector"
02974                 mCameraUpVector = mCameraUpVector * mAvatarObject->getRenderRotation();
02975                 //end Ventrella
02976         }
02977 
02978         if (cameraThirdPerson() && mFocusOnAvatar && LLFollowCamMgr::getActiveFollowCamParams())
02979         {
02980                 changeCameraToFollow();
02981         }
02982 
02983         //Ventrella
02984         //NOTE - this needs to be integrated into a general upVector system here within llAgent. 
02985         if ( camera_mode == CAMERA_MODE_FOLLOW && mFocusOnAvatar )
02986         {
02987                 mCameraUpVector = mFollowCam.getUpVector();
02988         }
02989         //end Ventrella
02990 
02991         if (mSitCameraEnabled)
02992         {
02993                 if (mSitCameraReferenceObject->isDead())
02994                 {
02995                         setSitCamera(LLUUID::null);
02996                 }
02997         }
02998 
02999         // Update UI with our camera inputs
03000         if (gFloaterCamera)
03001         {
03002                 gFloaterCamera->mRotate->setToggleState(
03003                         mOrbitRightKey > 0.f,   // left
03004                         mOrbitUpKey > 0.f,              // top
03005                         mOrbitLeftKey > 0.f,    // right
03006                         mOrbitDownKey > 0.f);   // bottom
03007 
03008                 gFloaterCamera->mZoom->setToggleState( 
03009                         mOrbitInKey > 0.f,              // top
03010                         mOrbitOutKey > 0.f);    // bottom
03011 
03012                 gFloaterCamera->mTrack->setToggleState(
03013                         mPanLeftKey > 0.f,              // left
03014                         mPanUpKey > 0.f,                // top
03015                         mPanRightKey > 0.f,             // right
03016                         mPanDownKey > 0.f);             // bottom
03017         }
03018 
03019         // Handle camera movement based on keyboard.
03020         const F32 ORBIT_OVER_RATE = 90.f * DEG_TO_RAD;                  // radians per second
03021         const F32 ORBIT_AROUND_RATE = 90.f * DEG_TO_RAD;                // radians per second
03022         const F32 PAN_RATE = 5.f;                                                               // meters per second
03023 
03024         if( mOrbitUpKey || mOrbitDownKey )
03025         {
03026                 F32 input_rate = mOrbitUpKey - mOrbitDownKey;
03027                 cameraOrbitOver( input_rate * ORBIT_OVER_RATE / gFPSClamped );
03028         }
03029 
03030         if( mOrbitLeftKey || mOrbitRightKey)
03031         {
03032                 F32 input_rate = mOrbitLeftKey - mOrbitRightKey;
03033                 cameraOrbitAround( input_rate * ORBIT_AROUND_RATE / gFPSClamped );
03034         }
03035 
03036         if( mOrbitInKey || mOrbitOutKey )
03037         {
03038                 F32 input_rate = mOrbitInKey - mOrbitOutKey;
03039                 
03040                 LLVector3d to_focus = gAgent.getPosGlobalFromAgent(gCamera->getOrigin()) - calcFocusPositionTargetGlobal();
03041                 F32 distance_to_focus = (F32)to_focus.magVec();
03042                 // Move at distance (in meters) meters per second
03043                 cameraOrbitIn( input_rate * distance_to_focus / gFPSClamped );
03044         }
03045 
03046         if( mPanInKey || mPanOutKey )
03047         {
03048                 F32 input_rate = mPanInKey - mPanOutKey;
03049                 cameraPanIn( input_rate * PAN_RATE / gFPSClamped );
03050         }
03051 
03052         if( mPanRightKey || mPanLeftKey )
03053         {
03054                 F32 input_rate = mPanRightKey - mPanLeftKey;
03055                 cameraPanLeft( input_rate * -PAN_RATE / gFPSClamped );
03056         }
03057 
03058         if( mPanUpKey || mPanDownKey )
03059         {
03060                 F32 input_rate = mPanUpKey - mPanDownKey;
03061                 cameraPanUp( input_rate * PAN_RATE / gFPSClamped );
03062         }
03063 
03064         // Clear camera keyboard keys.
03065         mOrbitLeftKey           = 0.f;
03066         mOrbitRightKey          = 0.f;
03067         mOrbitUpKey                     = 0.f;
03068         mOrbitDownKey           = 0.f;
03069         mOrbitInKey                     = 0.f;
03070         mOrbitOutKey            = 0.f;
03071 
03072         mPanRightKey            = 0.f;
03073         mPanLeftKey                     = 0.f;
03074         mPanUpKey                       = 0.f;
03075         mPanDownKey                     = 0.f;
03076         mPanInKey                       = 0.f;
03077         mPanOutKey                      = 0.f;
03078 
03079         // lerp camera focus offset
03080         mCameraFocusOffset = lerp(mCameraFocusOffset, mCameraFocusOffsetTarget, LLCriticalDamp::getInterpolant(CAMERA_FOCUS_HALF_LIFE));
03081 
03082         //Ventrella
03083         if ( mCameraMode == CAMERA_MODE_FOLLOW )
03084         {
03085                 if ( !mAvatarObject.isNull() )
03086                 {
03087                         //--------------------------------------------------------------------------------
03088                         // this is where the avatar's position and rotation are given to followCam, and 
03089                         // where it is updated. All three of its attributes are updated: (1) position, 
03090                         // (2) focus, and (3) upvector. They can then be queried elsewhere in llAgent.
03091                         //--------------------------------------------------------------------------------
03092                         // *TODO: use combined rotation of frameagent and sit object
03093                         LLQuaternion avatarRotationForFollowCam = mAvatarObject->mIsSitting ? mAvatarObject->getRenderRotation() : mFrameAgent.getQuaternion();
03094 
03095                         LLFollowCamParams* current_cam = LLFollowCamMgr::getActiveFollowCamParams();
03096                         if (current_cam)
03097                         {
03098                                 mFollowCam.copyParams(*current_cam);
03099                                 mFollowCam.setSubjectPositionAndRotation( mAvatarObject->getRenderPosition(), avatarRotationForFollowCam );
03100                                 mFollowCam.update();
03101                         }
03102                         else
03103                         {
03104                                 changeCameraToThirdPerson(TRUE);
03105                         }
03106                 }
03107         }
03108         // end Ventrella
03109 
03110         BOOL hit_limit;
03111         LLVector3d camera_pos_global;
03112         LLVector3d camera_target_global = calcCameraPositionTargetGlobal(&hit_limit);
03113         mCameraVirtualPositionAgent = getPosAgentFromGlobal(camera_target_global);
03114         LLVector3d focus_target_global = calcFocusPositionTargetGlobal();
03115 
03116         // perform field of view correction
03117         mCameraFOVZoomFactor = calcCameraFOVZoomFactor();
03118         camera_target_global = focus_target_global + (camera_target_global - focus_target_global) * (1.f + mCameraFOVZoomFactor);
03119 
03120         // do alpha fade on focus object
03121         F32 fade_increment = mFocusObjectFadeTimer.getElapsedTimeAndResetF32();
03122 
03123         if (mFocusObject.notNull() && !mFocusObject->isAttachment() && mFocusObject->mDrawable.notNull())
03124         {
03125                 F32 increment = fade_increment;
03126                 if (mFocusObjectDist < -0.2f)
03127                 {
03128                         increment *= -1.f;
03129                 }
03130 
03131                 if (mFocusObject->getVObjRadius() > MIN_RADIUS_ALPHA_SIZZLE)
03132                 {
03133                         S32 num_faces = mFocusObject->mDrawable->getNumFaces();
03134                         for (S32 i = 0; i < num_faces; i++)
03135                         {
03136                                 LLFace* facep = mFocusObject->mDrawable->getFace(i);
03137                                 F32 fade = facep->mAlphaFade;
03138                                 fade = llclamp(fade + increment, 0.f, 1.f);
03139                                 facep->mAlphaFade = fade;
03140                         }
03141                 }
03142         }
03143 
03144         // do alpha fade in on fade objects
03145         std::set< LLPointer<LLViewerObject> >::iterator fade_object_it;
03146         for (fade_object_it = mFadeObjects.begin(); fade_object_it != mFadeObjects.end(); )
03147         {
03148                 LLViewerObject* fade_object = *fade_object_it;
03149                 if (fade_object->isDead())
03150                 {
03151                         // remove from list
03152                         mFadeObjects.erase(fade_object_it++);
03153                 }
03154                 else
03155                 {
03156                         LLDrawable* drawablep = fade_object->mDrawable;
03157                         if (drawablep && fade_object->getVObjRadius() > MIN_RADIUS_ALPHA_SIZZLE)
03158                         {
03159                                 S32 num_faces = drawablep->getNumFaces();
03160                                 BOOL fade_done = TRUE;
03161                                 for (S32 i = 0; i < num_faces; i++)
03162                                 {
03163                                         LLFace* facep = drawablep->getFace(i);
03164                                         F32 fade = facep->mAlphaFade;
03165                                         fade = llclamp(fade - fade_increment, 0.f, 1.f);
03166                                         facep->mAlphaFade = fade;
03167                                         if (fade > 0.f)
03168                                         {
03169                                                 fade_done = FALSE;
03170                                         }
03171                                 }
03172                                 if (fade_done)
03173                                 {
03174                                         mFadeObjects.erase(fade_object_it++);
03175                                 }
03176                                 else
03177                                 {
03178                                         fade_object_it++;
03179                                 }
03180                         }
03181                         else
03182                         {
03183                                 fade_object_it++;
03184                         }
03185                 }
03186         }
03187 
03188         mShowAvatar = TRUE; // can see avatar by default
03189 
03190         // Adjust position for animation
03191         if (mCameraAnimating)
03192         {
03193                 F32 time = mAnimationTimer.getElapsedTimeF32();
03194 
03195                 // yet another instance of critically damped motion, hooray!
03196                 // F32 fraction_of_animation = 1.f - pow(2.f, -time / CAMERA_ZOOM_HALF_LIFE);
03197 
03198                 // linear interpolation
03199                 F32 fraction_of_animation = time / mAnimationDuration;
03200 
03201                 BOOL isfirstPerson = mCameraMode == CAMERA_MODE_MOUSELOOK;
03202                 BOOL wasfirstPerson = mLastCameraMode == CAMERA_MODE_MOUSELOOK;
03203                 F32 fraction_animation_to_skip;
03204 
03205                 if (mAnimationCameraStartGlobal == camera_target_global)
03206                 {
03207                         fraction_animation_to_skip = 0.f;
03208                 }
03209                 else
03210                 {
03211                         LLVector3d cam_delta = mAnimationCameraStartGlobal - camera_target_global;
03212                         fraction_animation_to_skip = HEAD_BUFFER_SIZE / (F32)cam_delta.magVec();
03213                 }
03214                 F32 animation_start_fraction = (wasfirstPerson) ? fraction_animation_to_skip : 0.f;
03215                 F32 animation_finish_fraction =  (isfirstPerson) ? (1.f - fraction_animation_to_skip) : 1.f;
03216         
03217                 if (fraction_of_animation < animation_finish_fraction)
03218                 {
03219                         if (fraction_of_animation < animation_start_fraction || fraction_of_animation > animation_finish_fraction )
03220                         {
03221                                 mShowAvatar = FALSE;
03222                         }
03223 
03224                         // ...adjust position for animation
03225                         camera_pos_global = lerp(mAnimationCameraStartGlobal, camera_target_global, fraction_of_animation);
03226                         mFocusGlobal = lerp(mAnimationFocusStartGlobal, focus_target_global, fraction_of_animation);
03227                 }
03228                 else
03229                 {
03230                         // ...animation complete
03231                         mCameraAnimating = FALSE;
03232 
03233                         camera_pos_global = camera_target_global;
03234                         mFocusGlobal = focus_target_global;
03235 
03236                         endAnimationUpdateUI();
03237                         mShowAvatar = TRUE;
03238                 }
03239 
03240                 if (getAvatarObject() && mCameraMode != CAMERA_MODE_MOUSELOOK)
03241                 {
03242                         getAvatarObject()->updateAttachmentVisibility(mCameraMode);
03243                 }
03244         }
03245         else
03246         {
03247                 camera_pos_global = camera_target_global;
03248                 mFocusGlobal = focus_target_global;
03249                 mShowAvatar = TRUE;
03250         }
03251 
03252         mCameraCurrentFOVZoomFactor = lerp(mCameraCurrentFOVZoomFactor, mCameraFOVZoomFactor, LLCriticalDamp::getInterpolant(FOV_ZOOM_HALF_LIFE));
03253 
03254 //      llinfos << "Current FOV Zoom: " << mCameraCurrentFOVZoomFactor << " Target FOV Zoom: " << mCameraFOVZoomFactor << " Object penetration: " << mFocusObjectDist << llendl;
03255 
03256         F32 ui_offset = 0.f;
03257         if( CAMERA_MODE_CUSTOMIZE_AVATAR == mCameraMode ) 
03258         {
03259                 ui_offset = calcCustomizeAvatarUIOffset( camera_pos_global );
03260         }
03261 
03262 
03263         LLVector3 focus_agent = getPosAgentFromGlobal(mFocusGlobal);
03264         
03265         mCameraPositionAgent    = getPosAgentFromGlobal(camera_pos_global);
03266 
03267         // Move the camera
03268 
03269         //Ventrella
03270         gCamera->updateCameraLocation(mCameraPositionAgent, mCameraUpVector, focus_agent);
03271         //gCamera->updateCameraLocation(mCameraPositionAgent, camera_skyward, focus_agent);
03272         //end Ventrella
03273 
03274         //RN: translate UI offset after camera is oriented properly
03275         gCamera->translate(gCamera->getLeftAxis() * ui_offset);
03276         
03277         // Change FOV
03278         gCamera->setView(gCamera->getDefaultFOV() / (1.f + mCameraCurrentFOVZoomFactor));
03279 
03280         // follow camera when in customize mode
03281         if (cameraCustomizeAvatar())    
03282         {
03283                 setLookAt(LOOKAT_TARGET_FOCUS, NULL, mCameraPositionAgent);
03284         }
03285 
03286         // Send the camera position to the spatialized voice system.
03287         if(gVoiceClient && getRegion())
03288         {
03289                 LLMatrix3 rot;
03290                 rot.setRows(gCamera->getAtAxis(), gCamera->getLeftAxis (),  gCamera->getUpAxis());              
03291 
03292                 // MBW -- XXX -- Setting velocity to 0 for now.  May figure it out later...
03293                 gVoiceClient->setCameraPosition(
03294                                 getRegion()->getPosGlobalFromRegion(gCamera->getOrigin()),// position
03295                                 LLVector3::zero,                        // velocity
03296                                 rot);                                           // rotation matrix
03297         }
03298 
03299         // update the travel distance stat
03300         // this isn't directly related to the camera
03301         // but this seemed like the best place to do this
03302         LLVector3d global_pos = getPositionGlobal(); 
03303         if (! mLastPositionGlobal.isExactlyZero())
03304         {
03305                 LLVector3d delta = global_pos - mLastPositionGlobal;
03306                 mDistanceTraveled += delta.magVec();
03307         }
03308         mLastPositionGlobal = global_pos;
03309         
03310         if (LLVOAvatar::sVisibleInFirstPerson && mAvatarObject.notNull() && !mAvatarObject->mIsSitting && cameraMouselook())
03311         {
03312                 LLVector3 head_pos = mAvatarObject->mHeadp->getWorldPosition() + 
03313                         LLVector3(0.08f, 0.f, 0.05f) * mAvatarObject->mHeadp->getWorldRotation() + 
03314                         LLVector3(0.1f, 0.f, 0.f) * mAvatarObject->mPelvisp->getWorldRotation();
03315                 LLVector3 diff = mCameraPositionAgent - head_pos;
03316                 diff = diff * ~mAvatarObject->mRoot.getWorldRotation();
03317 
03318                 LLJoint* torso_joint = mAvatarObject->mTorsop;
03319                 LLJoint* chest_joint = mAvatarObject->mChestp;
03320                 LLVector3 torso_scale = torso_joint->getScale();
03321                 LLVector3 chest_scale = chest_joint->getScale();
03322 
03323                 // shorten avatar skeleton to avoid foot interpenetration
03324                 if (!mAvatarObject->mInAir)
03325                 {
03326                         LLVector3 chest_offset = LLVector3(0.f, 0.f, chest_joint->getPosition().mV[VZ]) * torso_joint->getWorldRotation();
03327                         F32 z_compensate = llclamp(-diff.mV[VZ], -0.2f, 1.f);
03328                         F32 scale_factor = llclamp(1.f - ((z_compensate * 0.5f) / chest_offset.mV[VZ]), 0.5f, 1.2f);
03329                         torso_joint->setScale(LLVector3(1.f, 1.f, scale_factor));
03330 
03331                         LLJoint* neck_joint = mAvatarObject->mNeckp;
03332                         LLVector3 neck_offset = LLVector3(0.f, 0.f, neck_joint->getPosition().mV[VZ]) * chest_joint->getWorldRotation();
03333                         scale_factor = llclamp(1.f - ((z_compensate * 0.5f) / neck_offset.mV[VZ]), 0.5f, 1.2f);
03334                         chest_joint->setScale(LLVector3(1.f, 1.f, scale_factor));
03335                         diff.mV[VZ] = 0.f;
03336                 }
03337 
03338                 mAvatarObject->mPelvisp->setPosition(mAvatarObject->mPelvisp->getPosition() + diff);
03339 
03340                 mAvatarObject->mRoot.updateWorldMatrixChildren();
03341 
03342                 for(LLViewerJointAttachment *attachment = mAvatarObject->mAttachmentPoints.getFirstData();
03343                         attachment;
03344                         attachment = mAvatarObject->mAttachmentPoints.getNextData())
03345                 {
03346                         LLViewerObject *attached_object = attachment->getObject();
03347                         if (attached_object && !attached_object->isDead() && attached_object->mDrawable.notNull())
03348                         {
03349                                 // clear any existing "early" movements of attachment
03350                                 attached_object->mDrawable->clearState(LLDrawable::EARLY_MOVE);
03351                                 gPipeline.updateMoveNormalAsync(attached_object->mDrawable);
03352                                 attached_object->updateText();
03353                         }
03354                 }
03355 
03356                 torso_joint->setScale(torso_scale);
03357                 chest_joint->setScale(chest_scale);
03358         }
03359 }
03360 
03361 void LLAgent::updateFocusOffset()
03362 {
03363         validateFocusObject();
03364         if (mFocusObject.notNull())
03365         {
03366                 LLVector3d obj_pos = getPosGlobalFromAgent(mFocusObject->getRenderPosition());
03367                 mFocusObjectOffset.setVec(mFocusTargetGlobal - obj_pos);
03368         }
03369 }
03370 
03371 void LLAgent::validateFocusObject()
03372 {
03373         if (mFocusObject.notNull() && 
03374                 (mFocusObject->isDead()))
03375         {
03376                 mFocusObjectOffset.clearVec();
03377                 clearFocusObject();
03378                 mCameraFOVZoomFactor = 0.f;
03379         }
03380 }
03381 
03382 //-----------------------------------------------------------------------------
03383 // calcCustomizeAvatarUIOffset()
03384 //-----------------------------------------------------------------------------
03385 F32 LLAgent::calcCustomizeAvatarUIOffset( const LLVector3d& camera_pos_global )
03386 {
03387         F32 ui_offset = 0.f;
03388 
03389         if( gFloaterCustomize )
03390         {
03391                 const LLRect& rect = gFloaterCustomize->getRect();
03392 
03393                 // Move the camera so that the avatar isn't covered up by this floater.
03394                 F32 fraction_of_fov = 0.5f - (0.5f * (1.f - llmin(1.f, ((F32)rect.getWidth() / (F32)gViewerWindow->getWindowWidth()))));
03395                 F32 apparent_angle = fraction_of_fov * gCamera->getView() * gCamera->getAspect();  // radians
03396                 F32 offset = tan(apparent_angle);
03397 
03398                 if( rect.mLeft < (gViewerWindow->getWindowWidth() - rect.mRight) )
03399                 {
03400                         // Move the avatar to the right (camera to the left)
03401                         ui_offset = offset;
03402                 }
03403                 else
03404                 {
03405                         // Move the avatar to the left (camera to the right)
03406                         ui_offset = -offset;
03407                 }
03408         }
03409         F32 range = (F32)dist_vec(camera_pos_global, gAgent.getFocusGlobal());
03410         mUIOffset = lerp(mUIOffset, ui_offset, LLCriticalDamp::getInterpolant(0.05f));
03411         return mUIOffset * range;
03412 }
03413 
03414 //-----------------------------------------------------------------------------
03415 // calcFocusPositionTargetGlobal()
03416 //-----------------------------------------------------------------------------
03417 LLVector3d LLAgent::calcFocusPositionTargetGlobal()
03418 {
03419         if (mFocusObject.notNull() && mFocusObject->isDead())
03420         {
03421                 clearFocusObject();
03422         }
03423 
03424         // Ventrella
03425         if ( mCameraMode == CAMERA_MODE_FOLLOW && mFocusOnAvatar )
03426         {
03427                 mFocusTargetGlobal = gAgent.getPosGlobalFromAgent(mFollowCam.getSimulatedFocus());
03428                 return mFocusTargetGlobal;
03429         }// End Ventrella 
03430         else if (mCameraMode == CAMERA_MODE_MOUSELOOK)
03431         {
03432                 LLVector3d at_axis(1.0, 0.0, 0.0);
03433                 LLQuaternion agent_rot = mFrameAgent.getQuaternion();
03434                 if (!mAvatarObject.isNull() && mAvatarObject->getParent())
03435                 {
03436                         LLViewerObject* root_object = (LLViewerObject*)mAvatarObject->getRoot();
03437                         if (!root_object->flagCameraDecoupled())
03438                         {
03439                                 agent_rot *= ((LLViewerObject*)(mAvatarObject->getParent()))->getRenderRotation();
03440                         }
03441                 }
03442                 at_axis = at_axis * agent_rot;
03443                 mFocusTargetGlobal = calcCameraPositionTargetGlobal() + at_axis;
03444                 return mFocusTargetGlobal;
03445         }
03446         else if (mCameraMode == CAMERA_MODE_CUSTOMIZE_AVATAR)
03447         {
03448                 return mFocusTargetGlobal;
03449         }
03450         else if (!mFocusOnAvatar)
03451         {
03452                 if (mFocusObject.notNull() && !mFocusObject->isDead() && mFocusObject->mDrawable.notNull())
03453                 {
03454                         LLDrawable* drawablep = mFocusObject->mDrawable;
03455                         
03456                         if (mTrackFocusObject &&
03457                                 drawablep && 
03458                                 drawablep->isActive())
03459                         {
03460                                 if (!mFocusObject->isAvatar())
03461                                 {
03462                                         if (mFocusObject->isSelected())
03463                                         {
03464                                                 gPipeline.updateMoveNormalAsync(drawablep);
03465                                         }
03466                                         else
03467                                         {
03468                                                 if (drawablep->isState(LLDrawable::MOVE_UNDAMPED))
03469                                                 {
03470                                                         gPipeline.updateMoveNormalAsync(drawablep);
03471                                                 }
03472                                                 else
03473                                                 {
03474                                                         gPipeline.updateMoveDampedAsync(drawablep);
03475                                                 }
03476                                         }
03477                                 }
03478                         }
03479                         // if not tracking object, update offset based on new object position
03480                         else
03481                         {
03482                                 updateFocusOffset();
03483                         }
03484                         LLVector3 focus_agent = mFocusObject->getRenderPosition() + mFocusObjectOffset;
03485                         mFocusTargetGlobal.setVec(getPosGlobalFromAgent(focus_agent));
03486                 }
03487                 return mFocusTargetGlobal;
03488         }
03489         else if (mSitCameraEnabled && mAvatarObject.notNull() && mAvatarObject->mIsSitting && mSitCameraReferenceObject.notNull())
03490         {
03491                 // sit camera
03492                 LLVector3 object_pos = mSitCameraReferenceObject->getRenderPosition();
03493                 LLQuaternion object_rot = mSitCameraReferenceObject->getRenderRotation();
03494 
03495                 LLVector3 target_pos = object_pos + (mSitCameraFocus * object_rot);
03496                 return getPosGlobalFromAgent(target_pos);
03497         }
03498         else
03499         {
03500                 // ...offset from avatar
03501                 LLVector3d focus_offset;
03502                 focus_offset.setVec(gSavedSettings.getVector3("FocusOffsetDefault"));
03503 
03504                 LLQuaternion agent_rot = mFrameAgent.getQuaternion();
03505                 if (!mAvatarObject.isNull() && mAvatarObject->getParent())
03506                 {
03507                         agent_rot *= ((LLViewerObject*)(mAvatarObject->getParent()))->getRenderRotation();
03508                 }
03509 
03510                 focus_offset = focus_offset * agent_rot;
03511 
03512                 return getPositionGlobal() + focus_offset;
03513         }
03514 }
03515 
03516 void LLAgent::setupSitCamera()
03517 {
03518         // agent frame entering this function is in world coordinates
03519         if (mAvatarObject.notNull() && mAvatarObject->getParent())
03520         {
03521                 LLQuaternion parent_rot = ((LLViewerObject*)mAvatarObject->getParent())->getRenderRotation();
03522                 // slam agent coordinate frame to proper parent local version
03523                 LLVector3 at_axis = mFrameAgent.getAtAxis();
03524                 at_axis.mV[VZ] = 0.f;
03525                 at_axis.normVec();
03526                 resetAxes(at_axis * ~parent_rot);
03527         }
03528 }
03529 
03530 //-----------------------------------------------------------------------------
03531 // getCameraPositionAgent()
03532 //-----------------------------------------------------------------------------
03533 const LLVector3 &LLAgent::getCameraPositionAgent() const
03534 {
03535         return gCamera->getOrigin();
03536 }
03537 
03538 //-----------------------------------------------------------------------------
03539 // getCameraPositionGlobal()
03540 //-----------------------------------------------------------------------------
03541 LLVector3d LLAgent::getCameraPositionGlobal() const
03542 {
03543         if (gCamera)
03544         {
03545                 return getPosGlobalFromAgent(gCamera->getOrigin());
03546         }
03547         else
03548         {
03549                 return (LLVector3d::zero);
03550         }
03551 }
03552 
03553 //-----------------------------------------------------------------------------
03554 // calcCameraFOVZoomFactor()
03555 //-----------------------------------------------------------------------------
03556 F32     LLAgent::calcCameraFOVZoomFactor()
03557 {
03558         LLVector3 camera_offset_dir;
03559         camera_offset_dir.setVec(mCameraFocusOffset);
03560 
03561         if (mCameraMode == CAMERA_MODE_MOUSELOOK)
03562         {
03563                 return 0.f;
03564         }
03565         else if (mFocusObject.notNull() && !mFocusObject->isAvatar())
03566         {
03567                 // don't FOV zoom on mostly transparent objects
03568                 LLVector3 focus_offset = mFocusObjectOffset;
03569                 F32 obj_min_dist = 0.f;
03570                 calcCameraMinDistance(obj_min_dist);
03571                 F32 current_distance = llmax(0.001f, camera_offset_dir.magVec());
03572 
03573                 mFocusObjectDist = obj_min_dist - current_distance;
03574 
03575                 F32 new_fov_zoom = llclamp(mFocusObjectDist / current_distance, 0.f, 1000.f);
03576                 return new_fov_zoom;
03577         }
03578         else // focusing on land or avatar
03579         {
03580                 // keep old field of view until user changes focus explicitly
03581                 return mCameraFOVZoomFactor;
03582                 //return 0.f;
03583         }
03584 }
03585 
03586 //-----------------------------------------------------------------------------
03587 // calcCameraPositionTargetGlobal()
03588 //-----------------------------------------------------------------------------
03589 LLVector3d LLAgent::calcCameraPositionTargetGlobal(BOOL *hit_limit)
03590 {
03591         // Compute base camera position and look-at points.
03592         F32                     camera_land_height;
03593         LLVector3d      frame_center_global = mAvatarObject.isNull() ? getPositionGlobal() 
03594                                                                                                                          : getPosGlobalFromAgent(mAvatarObject->mRoot.getWorldPosition());
03595                 
03596         LLVector3   upAxis = getUpAxis();
03597         BOOL            isConstrained = FALSE;
03598         LLVector3d      head_offset;
03599         head_offset.setVec(mThirdPersonHeadOffset);
03600 
03601         LLVector3d camera_position_global;
03602 
03603         // Ventrella 
03604         if ( mCameraMode == CAMERA_MODE_FOLLOW && mFocusOnAvatar )
03605         {
03606                 camera_position_global = gAgent.getPosGlobalFromAgent(mFollowCam.getSimulatedPosition());
03607         }// End Ventrella
03608         else if (mCameraMode == CAMERA_MODE_MOUSELOOK)
03609         {
03610                 if (mAvatarObject.isNull() || mAvatarObject->mDrawable.isNull())
03611                 {
03612                         llwarns << "Null avatar drawable!" << llendl;
03613                         return LLVector3d::zero;
03614                 }
03615                 head_offset.clearVec();
03616                 if (mAvatarObject->mIsSitting && mAvatarObject->getParent())
03617                 {
03618                         mAvatarObject->updateHeadOffset();
03619                         head_offset.mdV[VX] = mAvatarObject->mHeadOffset.mV[VX];
03620                         head_offset.mdV[VY] = mAvatarObject->mHeadOffset.mV[VY];
03621                         head_offset.mdV[VZ] = mAvatarObject->mHeadOffset.mV[VZ] + 0.1f;
03622                         const LLMatrix4& mat = ((LLViewerObject*) mAvatarObject->getParent())->getRenderMatrix();
03623                         camera_position_global = getPosGlobalFromAgent
03624                                                                 ((mAvatarObject->getPosition()+
03625                                                                  LLVector3(head_offset)*mAvatarObject->getRotation()) * mat);
03626                 }
03627                 else
03628                 {
03629                         head_offset.mdV[VZ] = mAvatarObject->mHeadOffset.mV[VZ];
03630                         if (mAvatarObject->mIsSitting)
03631                         {
03632                                 head_offset.mdV[VZ] += 0.1;
03633                         }
03634                         camera_position_global = getPosGlobalFromAgent(mAvatarObject->getRenderPosition());//frame_center_global;
03635                         head_offset = head_offset * mAvatarObject->getRenderRotation();
03636                         camera_position_global = camera_position_global + head_offset;
03637                 }
03638         }
03639         else if (mCameraMode == CAMERA_MODE_THIRD_PERSON && mFocusOnAvatar)
03640         {
03641                 LLVector3 local_camera_offset;
03642                 F32 camera_distance = 0.f;
03643 
03644                 if (mSitCameraEnabled 
03645                         && mAvatarObject.notNull() 
03646                         && mAvatarObject->mIsSitting 
03647                         && mSitCameraReferenceObject.notNull())
03648                 {
03649                         // sit camera
03650                         LLVector3 object_pos = mSitCameraReferenceObject->getRenderPosition();
03651                         LLQuaternion object_rot = mSitCameraReferenceObject->getRenderRotation();
03652 
03653                         LLVector3 target_pos = object_pos + (mSitCameraPos * object_rot);
03654 
03655                         camera_position_global = getPosGlobalFromAgent(target_pos);
03656                 }
03657                 else
03658                 {
03659                         local_camera_offset = mCameraZoomFraction * mCameraOffsetDefault;
03660                         
03661                         // are we sitting down?
03662                         if (mAvatarObject.notNull() && mAvatarObject->getParent())
03663                         {
03664                                 LLQuaternion parent_rot = ((LLViewerObject*)mAvatarObject->getParent())->getRenderRotation();
03665                                 // slam agent coordinate frame to proper parent local version
03666                                 LLVector3 at_axis = mFrameAgent.getAtAxis() * parent_rot;
03667                                 at_axis.mV[VZ] = 0.f;
03668                                 at_axis.normVec();
03669                                 resetAxes(at_axis * ~parent_rot);
03670 
03671                                 local_camera_offset = local_camera_offset * mFrameAgent.getQuaternion() * parent_rot;
03672                         }
03673                         else
03674                         {
03675                                 local_camera_offset = mFrameAgent.rotateToAbsolute( local_camera_offset );
03676                         }
03677 
03678                         if (!mCameraCollidePlane.isExactlyZero() && (mAvatarObject.isNull() || !mAvatarObject->mIsSitting))
03679                         {
03680                                 LLVector3 plane_normal;
03681                                 plane_normal.setVec(mCameraCollidePlane.mV);
03682 
03683                                 F32 offset_dot_norm = local_camera_offset * plane_normal;
03684                                 if (llabs(offset_dot_norm) < 0.001f)
03685                                 {
03686                                         offset_dot_norm = 0.001f;
03687                                 }
03688                                 
03689                                 camera_distance = local_camera_offset.normVec();
03690 
03691                                 F32 pos_dot_norm = getPosAgentFromGlobal(frame_center_global + head_offset) * plane_normal;
03692                                 
03693                                 // if agent is outside the colliding half-plane
03694                                 if (pos_dot_norm > mCameraCollidePlane.mV[VW])
03695                                 {
03696                                         // check to see if camera is on the opposite side (inside) the half-plane
03697                                         if (offset_dot_norm + pos_dot_norm < mCameraCollidePlane.mV[VW])
03698                                         {
03699                                                 // diminish offset by factor to push it back outside the half-plane
03700                                                 camera_distance *= (pos_dot_norm - mCameraCollidePlane.mV[VW] - CAMERA_COLLIDE_EPSILON) / -offset_dot_norm;
03701                                         }
03702                                 }
03703                                 else
03704                                 {
03705                                         if (offset_dot_norm + pos_dot_norm > mCameraCollidePlane.mV[VW])
03706                                         {
03707                                                 camera_distance *= (mCameraCollidePlane.mV[VW] - pos_dot_norm - CAMERA_COLLIDE_EPSILON) / offset_dot_norm;
03708                                         }
03709                                 }
03710                         }
03711                         else
03712                         {
03713                                 camera_distance = local_camera_offset.normVec();
03714                         }
03715 
03716                         mTargetCameraDistance = llmax(camera_distance, MIN_CAMERA_DISTANCE);
03717 
03718                         if (mTargetCameraDistance != mCurrentCameraDistance)
03719                         {
03720                                 F32 camera_lerp_amt = LLCriticalDamp::getInterpolant(CAMERA_ZOOM_HALF_LIFE);
03721 
03722                                 mCurrentCameraDistance = lerp(mCurrentCameraDistance, mTargetCameraDistance, camera_lerp_amt);
03723                         }
03724 
03725                         // Make the camera distance current
03726                         local_camera_offset *= mCurrentCameraDistance;
03727 
03728                         // set the global camera position
03729                         LLVector3d camera_offset;
03730                         
03731                         LLVector3 av_pos = mAvatarObject.isNull() ? LLVector3::zero : mAvatarObject->getRenderPosition();
03732                         camera_offset.setVec( local_camera_offset );
03733                         camera_position_global = frame_center_global + head_offset + camera_offset;
03734 
03735                         if (!mAvatarObject.isNull())
03736                         {
03737                                 LLVector3d camera_lag_d;
03738                                 F32 lag_interp = LLCriticalDamp::getInterpolant(CAMERA_LAG_HALF_LIFE);
03739                                 LLVector3 target_lag;
03740                                 LLVector3 vel = getVelocity();
03741 
03742                                 // lag by appropriate amount for flying
03743                                 F32 time_in_air = mAvatarObject->mTimeInAir.getElapsedTimeF32();
03744                                 if(!mCameraAnimating && mAvatarObject->mInAir && time_in_air > GROUND_TO_AIR_CAMERA_TRANSITION_START_TIME)
03745                                 {
03746                                         LLVector3 frame_at_axis = mFrameAgent.getAtAxis();
03747                                         frame_at_axis -= projected_vec(frame_at_axis, getReferenceUpVector());
03748                                         frame_at_axis.normVec();
03749 
03750                                         //transition smoothly in air mode, to avoid camera pop
03751                                         F32 u = (time_in_air - GROUND_TO_AIR_CAMERA_TRANSITION_START_TIME) / GROUND_TO_AIR_CAMERA_TRANSITION_TIME;
03752                                         u = llclamp(u, 0.f, 1.f);
03753 
03754                                         lag_interp *= u;
03755 
03756                                         if (gViewerWindow->getLeftMouseDown() && gLastHitObjectID == mAvatarObject->getID())
03757                                         {
03758                                                 // disable camera lag when using mouse-directed steering
03759                                                 target_lag.clearVec();
03760                                         }
03761                                         else
03762                                         {
03763                                                 target_lag = vel * gSavedSettings.getF32("DynamicCameraStrength") / 30.f;
03764                                         }
03765 
03766                                         mCameraLag = lerp(mCameraLag, target_lag, lag_interp);
03767 
03768                                         F32 lag_dist = mCameraLag.magVec();
03769                                         if (lag_dist > MAX_CAMERA_LAG)
03770                                         {
03771                                                 mCameraLag = mCameraLag * MAX_CAMERA_LAG / lag_dist;
03772                                         }
03773 
03774                                         // clamp camera lag so that avatar is always in front
03775                                         F32 dot = (mCameraLag - (frame_at_axis * (MIN_CAMERA_LAG * u))) * frame_at_axis;
03776                                         if (dot < -(MIN_CAMERA_LAG * u))
03777                                         {
03778                                                 mCameraLag -= (dot + (MIN_CAMERA_LAG * u)) * frame_at_axis;
03779                                         }
03780                                 }
03781                                 else
03782                                 {
03783                                         mCameraLag = lerp(mCameraLag, LLVector3::zero, LLCriticalDamp::getInterpolant(0.15f));
03784                                 }
03785 
03786                                 camera_lag_d.setVec(mCameraLag);
03787                                 camera_position_global = camera_position_global - camera_lag_d;
03788                         }
03789                 }
03790         }
03791         else
03792         {
03793                 LLVector3d focusPosGlobal = calcFocusPositionTargetGlobal();
03794                 // camera gets pushed out later wrt mCameraFOVZoomFactor...this is "raw" value
03795                 camera_position_global = focusPosGlobal + mCameraFocusOffset;
03796         }
03797 
03798         if (!gSavedSettings.getBOOL("DisableCameraConstraints") && !gAgent.isGodlike())
03799         {
03800                 LLViewerRegion* regionp = gWorldPointer->getRegionFromPosGlobal(
03801                         camera_position_global);
03802                 bool constrain = true;
03803                 if(regionp && regionp->canManageEstate())
03804                 {
03805                         constrain = false;
03806                 }
03807                 if(constrain)
03808                 {
03809                         F32 max_dist = ( CAMERA_MODE_CUSTOMIZE_AVATAR == mCameraMode ) ?
03810                                 APPEARANCE_MAX_ZOOM : MAX_CAMERA_DISTANCE_FROM_AGENT;
03811 
03812                         LLVector3d camera_offset = camera_position_global
03813                                 - gAgent.getPositionGlobal();
03814                         F32 camera_distance = (F32)camera_offset.magVec();
03815 
03816                         if(camera_distance > max_dist)
03817                         {
03818                                 camera_position_global = gAgent.getPositionGlobal() + 
03819                                         (max_dist / camera_distance) * camera_offset;
03820                                 isConstrained = TRUE;
03821                         }
03822                 }
03823 
03824 // JC - Could constrain camera based on parcel stuff here.
03825 //                      LLViewerRegion *regionp = gWorldPointer->getRegionFromPosGlobal(camera_position_global);
03826 //                      
03827 //                      if (regionp && !regionp->mParcelOverlay->isBuildCameraAllowed(regionp->getPosRegionFromGlobal(camera_position_global)))
03828 //                      {
03829 //                              camera_position_global = last_position_global;
03830 //
03831 //                              isConstrained = TRUE;
03832 //                      }
03833         }
03834 
03835         // Don't let camera go underground
03836         F32 camera_min_off_ground = getCameraMinOffGround();
03837 
03838         if (gWorldPointer)
03839         {
03840                 camera_land_height = gWorldPointer->resolveLandHeightGlobal(camera_position_global);
03841         }
03842         else
03843         {
03844                 camera_land_height = 0.f;
03845         }
03846 
03847         if (camera_position_global.mdV[VZ] < camera_land_height + camera_min_off_ground)
03848         {
03849                 camera_position_global.mdV[VZ] = camera_land_height + camera_min_off_ground;
03850                 isConstrained = TRUE;
03851         }
03852 
03853 
03854         if (hit_limit)
03855         {
03856                 *hit_limit = isConstrained;
03857         }
03858 
03859         return camera_position_global;
03860 }
03861 
03862 
03863 //-----------------------------------------------------------------------------
03864 // handleScrollWheel()
03865 //-----------------------------------------------------------------------------
03866 void LLAgent::handleScrollWheel(S32 clicks)
03867 {
03868         if ( mCameraMode == CAMERA_MODE_FOLLOW && gAgent.getFocusOnAvatar())
03869         {
03870                 if ( ! mFollowCam.getPositionLocked() ) // not if the followCam position is locked in place
03871                 {
03872                         mFollowCam.zoom( clicks ); 
03873                         if ( mFollowCam.isZoomedToMinimumDistance() )
03874                         {
03875                                 changeCameraToMouselook(FALSE);
03876                         }
03877                 }
03878         }
03879         else
03880         {
03881                 LLObjectSelectionHandle selection = gSelectMgr->getSelection();
03882                 const F32 ROOT_ROOT_TWO = sqrt(F_SQRT2);
03883 
03884                 // Block if camera is animating
03885                 if (mCameraAnimating)
03886                 {
03887                         return;
03888                 }
03889 
03890                 if (selection->getObjectCount() && selection->getSelectType() == SELECT_TYPE_HUD)
03891                 {
03892                         F32 zoom_factor = (F32)pow(0.8, -clicks);
03893                         cameraZoomIn(zoom_factor);
03894                 }
03895                 else if (mFocusOnAvatar && mCameraMode == CAMERA_MODE_THIRD_PERSON)
03896                 {
03897                         F32 current_zoom_fraction = mTargetCameraDistance / mCameraOffsetDefault.magVec();
03898                         current_zoom_fraction *= 1.f - pow(ROOT_ROOT_TWO, clicks);
03899                         
03900                         cameraOrbitIn(current_zoom_fraction * mCameraOffsetDefault.magVec());
03901                 }
03902                 else
03903                 {
03904                         F32 current_zoom_fraction = (F32)mCameraFocusOffsetTarget.magVec();
03905                         cameraOrbitIn(current_zoom_fraction * (1.f - pow(ROOT_ROOT_TWO, clicks)));
03906                 }
03907         }
03908 }
03909 
03910 
03911 //-----------------------------------------------------------------------------
03912 // getCameraMinOffGround()
03913 //-----------------------------------------------------------------------------
03914 F32 LLAgent::getCameraMinOffGround()
03915 {
03916         if (mCameraMode == CAMERA_MODE_MOUSELOOK)
03917         {
03918                 return 0.f;
03919         }
03920         else
03921         {
03922                 if (gSavedSettings.getBOOL("DisableCameraConstraints"))
03923                 {
03924                         return -1000.f;
03925                 }
03926                 else
03927                 {
03928                         return 0.5f;
03929                 }
03930         }
03931 }
03932 
03933 
03934 //-----------------------------------------------------------------------------
03935 // resetCamera()
03936 //-----------------------------------------------------------------------------
03937 void LLAgent::resetCamera()
03938 {
03939         // Remove any pitch from the avatar
03940         LLVector3 at = mFrameAgent.getAtAxis();
03941         at.mV[VZ] = 0.f;
03942         at.normVec();
03943         gAgent.resetAxes(at);
03944         // have to explicitly clear field of view zoom now
03945         mCameraFOVZoomFactor = 0.f;
03946 
03947         updateCamera();
03948 }
03949 
03950 //-----------------------------------------------------------------------------
03951 // changeCameraToMouselook()
03952 //-----------------------------------------------------------------------------
03953 void LLAgent::changeCameraToMouselook(BOOL animate)
03954 {
03955         // visibility changes at end of animation
03956         gViewerWindow->getWindow()->resetBusyCount();
03957 
03958         // unpause avatar animation
03959         mPauseRequest = NULL;
03960 
03961         gToolMgr->setCurrentToolset(gMouselookToolset);
03962 
03963         gSavedSettings.setBOOL("FirstPersonBtnState",   FALSE);
03964         gSavedSettings.setBOOL("MouselookBtnState",             TRUE);
03965         gSavedSettings.setBOOL("ThirdPersonBtnState",   FALSE);
03966         gSavedSettings.setBOOL("BuildBtnState",                 FALSE);
03967 
03968         if (mAvatarObject)
03969         {
03970                 mAvatarObject->stopMotion( ANIM_AGENT_BODY_NOISE );
03971                 mAvatarObject->stopMotion( ANIM_AGENT_BREATHE_ROT );
03972         }
03973 
03974         //gViewerWindow->stopGrab();
03975         gSelectMgr->deselectAll();
03976         gViewerWindow->hideCursor();
03977         gViewerWindow->moveCursorToCenter();
03978 
03979         if( mCameraMode != CAMERA_MODE_MOUSELOOK )
03980         {
03981                 gViewerWindow->setKeyboardFocus( NULL, NULL );
03982                 
03983                 mLastCameraMode = mCameraMode;
03984                 mCameraMode = CAMERA_MODE_MOUSELOOK;
03985                 U32 old_flags = mControlFlags;
03986                 setControlFlags(AGENT_CONTROL_MOUSELOOK);
03987                 if (old_flags != mControlFlags)
03988                 {
03989                         mbFlagsDirty = TRUE;
03990                 }
03991 
03992                 if (animate)
03993                 {
03994                         startCameraAnimation();
03995                 }
03996                 else
03997                 {
03998                         mCameraAnimating = FALSE;
03999                         endAnimationUpdateUI();
04000                 }
04001         }
04002 }
04003 
04004 
04005 //-----------------------------------------------------------------------------
04006 // changeCameraToDefault()
04007 //-----------------------------------------------------------------------------
04008 void LLAgent::changeCameraToDefault()
04009 {
04010         if (LLFollowCamMgr::getActiveFollowCamParams())
04011         {
04012                 changeCameraToFollow();
04013         }
04014         else
04015         {
04016                 changeCameraToThirdPerson();
04017         }
04018 }
04019 
04020 
04021 // Ventrella
04022 //-----------------------------------------------------------------------------
04023 // changeCameraToFollow()
04024 //-----------------------------------------------------------------------------
04025 void LLAgent::changeCameraToFollow(BOOL animate)
04026 {
04027         if( mCameraMode != CAMERA_MODE_FOLLOW )
04028         {
04029                 if (mCameraMode == CAMERA_MODE_MOUSELOOK)
04030                 {
04031                         animate = FALSE;
04032                 }
04033                 startCameraAnimation();
04034 
04035                 mLastCameraMode = mCameraMode;
04036                 mCameraMode = CAMERA_MODE_FOLLOW;
04037 
04038                 // bang-in the current focus, position, and up vector of the follow cam
04039                 mFollowCam.reset( mCameraPositionAgent, gCamera->getPointOfInterest(), LLVector3::z_axis );
04040                 
04041                 if (gBasicToolset)
04042                 {
04043                         gToolMgr->setCurrentToolset(gBasicToolset);
04044                 }
04045 
04046                 if (mAvatarObject)
04047                 {
04048                         mAvatarObject->mPelvisp->setPosition(LLVector3::zero);
04049                         mAvatarObject->startMotion( ANIM_AGENT_BODY_NOISE );
04050                         mAvatarObject->startMotion( ANIM_AGENT_BREATHE_ROT );
04051                 }
04052 
04053                 gSavedSettings.setBOOL("FirstPersonBtnState",   FALSE);
04054                 gSavedSettings.setBOOL("MouselookBtnState",             FALSE);
04055                 gSavedSettings.setBOOL("ThirdPersonBtnState",   TRUE);
04056                 gSavedSettings.setBOOL("BuildBtnState",                 FALSE);
04057 
04058                 // unpause avatar animation
04059                 mPauseRequest = NULL;
04060 
04061                 U32 old_flags = mControlFlags;
04062                 clearControlFlags(AGENT_CONTROL_MOUSELOOK);
04063                 if (old_flags != mControlFlags)
04064                 {
04065                         mbFlagsDirty = TRUE;
04066                 }
04067 
04068                 if (animate)
04069                 {
04070                         startCameraAnimation();
04071                 }
04072                 else
04073                 {
04074                         mCameraAnimating = FALSE;
04075                         endAnimationUpdateUI();
04076                 }
04077         }
04078 }
04079 
04080 //-----------------------------------------------------------------------------
04081 // changeCameraToThirdPerson()
04082 //-----------------------------------------------------------------------------
04083 void LLAgent::changeCameraToThirdPerson(BOOL animate)
04084 {
04085 //printf( "changeCameraToThirdPerson\n" );
04086 
04087         gViewerWindow->getWindow()->resetBusyCount();
04088 
04089         mCameraZoomFraction = INITIAL_ZOOM_FRACTION;
04090 
04091         if (mAvatarObject)
04092         {
04093                 mAvatarObject->mPelvisp->setPosition(LLVector3::zero);
04094                 mAvatarObject->startMotion( ANIM_AGENT_BODY_NOISE );
04095                 mAvatarObject->startMotion( ANIM_AGENT_BREATHE_ROT );
04096         }
04097 
04098         gSavedSettings.setBOOL("FirstPersonBtnState",   FALSE);
04099         gSavedSettings.setBOOL("MouselookBtnState",             FALSE);
04100         gSavedSettings.setBOOL("ThirdPersonBtnState",   TRUE);
04101         gSavedSettings.setBOOL("BuildBtnState",                 FALSE);
04102 
04103         LLVector3 at_axis;
04104 
04105         // unpause avatar animation
04106         mPauseRequest = NULL;
04107 
04108         if( mCameraMode != CAMERA_MODE_THIRD_PERSON )
04109         {
04110                 if (gBasicToolset)
04111                 {
04112                         gToolMgr->setCurrentToolset(gBasicToolset);
04113                 }
04114 
04115                 mCameraLag.clearVec();
04116                 if (mCameraMode == CAMERA_MODE_MOUSELOOK)
04117                 {
04118                         mCurrentCameraDistance = MIN_CAMERA_DISTANCE;
04119                         mTargetCameraDistance = MIN_CAMERA_DISTANCE;
04120                         animate = FALSE;
04121                 }
04122                 mLastCameraMode = mCameraMode;
04123                 mCameraMode = CAMERA_MODE_THIRD_PERSON;
04124                 U32 old_flags = mControlFlags;
04125                 clearControlFlags(AGENT_CONTROL_MOUSELOOK);
04126                 if (old_flags != mControlFlags)
04127                 {
04128                         mbFlagsDirty = TRUE;
04129                 }
04130 
04131         }
04132 
04133         // Remove any pitch from the avatar
04134         if (!mAvatarObject.isNull() && mAvatarObject->getParent())
04135         {
04136                 LLQuaternion obj_rot = ((LLViewerObject*)mAvatarObject->getParent())->getRenderRotation();
04137                 at_axis = gCamera->getAtAxis();
04138                 at_axis.mV[VZ] = 0.f;
04139                 at_axis.normVec();
04140                 resetAxes(at_axis * ~obj_rot);
04141         }
04142         else
04143         {
04144                 at_axis = mFrameAgent.getAtAxis();
04145                 at_axis.mV[VZ] = 0.f;
04146                 at_axis.normVec();
04147                 resetAxes(at_axis);
04148         }
04149 
04150 
04151         if (animate)
04152         {
04153                 startCameraAnimation();
04154         }
04155         else
04156         {
04157                 mCameraAnimating = FALSE;
04158                 endAnimationUpdateUI();
04159         }
04160 }
04161 
04162 //-----------------------------------------------------------------------------
04163 // changeCameraToCustomizeAvatar()
04164 //-----------------------------------------------------------------------------
04165 void LLAgent::changeCameraToCustomizeAvatar(BOOL animate)
04166 {
04167         setControlFlags(AGENT_CONTROL_STAND_UP); // force stand up
04168         gViewerWindow->getWindow()->resetBusyCount();
04169 
04170         if (gFaceEditToolset)
04171         {
04172                 gToolMgr->setCurrentToolset(gFaceEditToolset);
04173         }
04174 
04175         gSavedSettings.setBOOL("FirstPersonBtnState", FALSE);
04176         gSavedSettings.setBOOL("MouselookBtnState", FALSE);
04177         gSavedSettings.setBOOL("ThirdPersonBtnState", FALSE);
04178         gSavedSettings.setBOOL("BuildBtnState", FALSE);
04179 
04180         if (animate)
04181         {
04182                 startCameraAnimation();
04183         }
04184 
04185         // Remove any pitch from the avatar
04186         LLVector3 at = mFrameAgent.getAtAxis();
04187         at.mV[VZ] = 0.f;
04188         at.normVec();
04189         gAgent.resetAxes(at);
04190 
04191         if( mCameraMode != CAMERA_MODE_CUSTOMIZE_AVATAR )
04192         {
04193                 mLastCameraMode = mCameraMode;
04194                 mCameraMode = CAMERA_MODE_CUSTOMIZE_AVATAR;
04195                 U32 old_flags = mControlFlags;
04196                 clearControlFlags(AGENT_CONTROL_MOUSELOOK);
04197                 if (old_flags != mControlFlags)
04198                 {
04199                         mbFlagsDirty = TRUE;
04200                 }
04201 
04202                 gViewerWindow->setKeyboardFocus( NULL, NULL );
04203                 gViewerWindow->setMouseCapture( NULL );
04204 
04205                 LLVOAvatar::onCustomizeStart();
04206         }
04207 
04208         if (animate && !mAvatarObject.isNull())
04209         {
04210                 sendAnimationRequest(ANIM_AGENT_CUSTOMIZE, ANIM_REQUEST_START);
04211                 mAvatarObject->startMotion(ANIM_AGENT_CUSTOMIZE);
04212                 LLMotion* turn_motion = mAvatarObject->findMotion(ANIM_AGENT_CUSTOMIZE);
04213 
04214                 if (turn_motion)
04215                 {
04216                         mAnimationDuration = turn_motion->getDuration() + CUSTOMIZE_AVATAR_CAMERA_ANIM_SLOP;
04217 
04218                 }
04219                 else
04220                 {
04221                         mAnimationDuration = gSavedSettings.getF32("ZoomTime");
04222                 }
04223 
04224 
04225 
04226 
04227                 gAgent.setFocusGlobal(LLVector3d::zero);
04228         }
04229         else
04230         {
04231                 mCameraAnimating = FALSE;
04232                 endAnimationUpdateUI();
04233         }
04234 
04235 }
04236 
04237 
04238 //
04239 // Focus point management
04240 //
04241 
04242 //-----------------------------------------------------------------------------
04243 // startCameraAnimation()
04244 //-----------------------------------------------------------------------------
04245 void LLAgent::startCameraAnimation()
04246 {
04247         mAnimationCameraStartGlobal = getCameraPositionGlobal();
04248         mAnimationFocusStartGlobal = mFocusGlobal;
04249         mAnimationTimer.reset();
04250         mCameraAnimating = TRUE;
04251         mAnimationDuration = gSavedSettings.getF32("ZoomTime");
04252 }
04253 
04254 //-----------------------------------------------------------------------------
04255 // stopCameraAnimation()
04256 //-----------------------------------------------------------------------------
04257 void LLAgent::stopCameraAnimation()
04258 {
04259         mCameraAnimating = FALSE;
04260 }
04261 
04262 void LLAgent::clearFocusObject()
04263 {
04264         if (mFocusObject.notNull())
04265         {
04266                 startCameraAnimation();
04267 
04268                 setFocusObject(NULL);
04269                 mFocusObjectOffset.clearVec();
04270         }
04271 }
04272 
04273 void LLAgent::setFocusObject(LLViewerObject* object)
04274 {
04275         if (mFocusObject.notNull() && 
04276                 mFocusObject->mDrawable.notNull() && 
04277                 mFocusObject->getPCode() == LL_PCODE_VOLUME &&
04278                 mFocusObject != object)
04279         {
04280                 LLPointer<LLViewerObject> fade_object_ptr(mFocusObject);
04281 
04282                 if (fade_object_ptr.notNull() && mFadeObjects.find(fade_object_ptr) == mFadeObjects.end())
04283                 {
04284                         mFadeObjects.insert(fade_object_ptr);
04285                 }
04286         }
04287 
04288         mFocusObject = object;
04289 }
04290 
04291 // Focus on a point, but try to keep camera position stable.
04292 //-----------------------------------------------------------------------------
04293 // setFocusGlobal()
04294 //-----------------------------------------------------------------------------
04295 void LLAgent::setFocusGlobal(const LLVector3d& focus, const LLUUID &object_id)
04296 {
04297         setFocusObject(gObjectList.findObject(object_id));
04298         LLVector3d old_focus = mFocusTargetGlobal;
04299         LLViewerObject *focus_obj = mFocusObject;
04300 
04301         // if focus has changed
04302         if (old_focus != focus)
04303         {
04304                 if (focus.isExactlyZero())
04305                 {
04306                         if (!mAvatarObject.isNull())
04307                         {
04308                                 mFocusTargetGlobal = getPosGlobalFromAgent(mAvatarObject->mHeadp->getWorldPosition());
04309                         }
04310                         else
04311                         {
04312                                 mFocusTargetGlobal = getPositionGlobal();
04313                         }
04314                         mCameraFocusOffsetTarget = getCameraPositionGlobal() - mFocusTargetGlobal;
04315                         mCameraFocusOffset = mCameraFocusOffsetTarget;
04316                         setLookAt(LOOKAT_TARGET_CLEAR);
04317                 }
04318                 else
04319                 {
04320                         mFocusTargetGlobal = focus;
04321                         if (!focus_obj)
04322                         {
04323                                 mCameraFOVZoomFactor = 0.f;
04324                         }
04325 
04326                         mCameraFocusOffsetTarget = gAgent.getPosGlobalFromAgent(mCameraVirtualPositionAgent) - mFocusTargetGlobal;
04327 
04328                         startCameraAnimation();
04329 
04330                         if (focus_obj)
04331                         {
04332                                 if (focus_obj->isAvatar())
04333                                 {
04334                                         setLookAt(LOOKAT_TARGET_FOCUS, focus_obj);
04335                                 }
04336                                 else
04337                                 {
04338                                         setLookAt(LOOKAT_TARGET_FOCUS, focus_obj, (getPosAgentFromGlobal(focus) - focus_obj->getRenderPosition()) * ~focus_obj->getRenderRotation());
04339                                 }
04340                         }
04341                         else
04342                         {
04343                                 setLookAt(LOOKAT_TARGET_FOCUS, NULL, getPosAgentFromGlobal(mFocusTargetGlobal));
04344                         }
04345                 }
04346         }
04347         else // focus == mFocusTargetGlobal
04348         {
04349                 if (focus.isExactlyZero())
04350                 {
04351                         if (!mAvatarObject.isNull())
04352                         {
04353                                 mFocusTargetGlobal = getPosGlobalFromAgent(mAvatarObject->mHeadp->getWorldPosition());
04354                         }
04355                         else
04356                         {
04357                                 mFocusTargetGlobal = getPositionGlobal();
04358                         }
04359                 }
04360                 mCameraFocusOffsetTarget = (getCameraPositionGlobal() - mFocusTargetGlobal) / (1.f + mCameraFOVZoomFactor);;
04361                 mCameraFocusOffset = mCameraFocusOffsetTarget;
04362         }
04363 
04364         if (mFocusObject.notNull())
04365         {
04366                 // for attachments, make offset relative to avatar, not the attachment
04367                 if (mFocusObject->isAttachment())
04368                 {
04369                         while (!mFocusObject->isAvatar())
04370                         {
04371                                 mFocusObject = (LLViewerObject*) mFocusObject->getParent();
04372                         }
04373                         setFocusObject((LLViewerObject*)mFocusObject);
04374                 }
04375                 updateFocusOffset();
04376         }
04377 }
04378 
04379 // Used for avatar customization
04380 //-----------------------------------------------------------------------------
04381 // setCameraPosAndFocusGlobal()
04382 //-----------------------------------------------------------------------------
04383 void LLAgent::setCameraPosAndFocusGlobal(const LLVector3d& camera_pos, const LLVector3d& focus, const LLUUID &object_id)
04384 {
04385         LLVector3d old_focus = mFocusTargetGlobal;
04386 
04387         F64 focus_delta_squared = (old_focus - focus).magVecSquared();
04388         const F64 ANIM_EPSILON_SQUARED = 0.0001;
04389         if( focus_delta_squared > ANIM_EPSILON_SQUARED )
04390         {
04391                 startCameraAnimation();
04392 
04393                 if( CAMERA_MODE_CUSTOMIZE_AVATAR == mCameraMode ) 
04394                 {
04395                         // Compensate for the fact that the camera has already been offset to make room for LLFloaterCustomize.
04396                         mAnimationCameraStartGlobal -= LLVector3d(gCamera->getLeftAxis() * calcCustomizeAvatarUIOffset( mAnimationCameraStartGlobal ));
04397                 }
04398         }
04399         
04400         //gCamera->setOrigin( gAgent.getPosAgentFromGlobal( camera_pos ) );
04401         setFocusObject(gObjectList.findObject(object_id));
04402         mFocusTargetGlobal = focus;
04403         mCameraFocusOffsetTarget = camera_pos - focus;
04404         mCameraFocusOffset = mCameraFocusOffsetTarget;
04405 
04406         if (mFocusObject)
04407         {
04408                 if (mFocusObject->isAvatar())
04409                 {
04410                         setLookAt(LOOKAT_TARGET_FOCUS, mFocusObject);
04411                 }
04412                 else
04413                 {
04414                         setLookAt(LOOKAT_TARGET_FOCUS, mFocusObject, (getPosAgentFromGlobal(focus) - mFocusObject->getRenderPosition()) * ~mFocusObject->getRenderRotation());
04415                 }
04416         }
04417         else
04418         {
04419                 setLookAt(LOOKAT_TARGET_FOCUS, NULL, getPosAgentFromGlobal(mFocusTargetGlobal));
04420         }
04421 
04422         if( mCameraAnimating )
04423         {
04424                 const F64 ANIM_METERS_PER_SECOND = 10.0;
04425                 const F64 MIN_ANIM_SECONDS = 0.5;
04426                 F64 anim_duration = llmax( MIN_ANIM_SECONDS, sqrt(focus_delta_squared) / ANIM_METERS_PER_SECOND );
04427                 setAnimationDuration( (F32)anim_duration );
04428         }
04429 
04430         updateFocusOffset();
04431 }
04432 
04433 //-----------------------------------------------------------------------------
04434 // setSitCamera()
04435 //-----------------------------------------------------------------------------
04436 void LLAgent::setSitCamera(const LLUUID &object_id, const LLVector3 &camera_pos, const LLVector3 &camera_focus)
04437 {
04438         BOOL camera_enabled = !object_id.isNull();
04439 
04440         if (camera_enabled)
04441         {
04442                 LLViewerObject *reference_object = gObjectList.findObject(object_id);
04443                 if (reference_object)
04444                 {
04445                         //convert to root object relative?
04446                         mSitCameraPos = camera_pos;
04447                         mSitCameraFocus = camera_focus;
04448                         mSitCameraReferenceObject = reference_object;
04449                         mSitCameraEnabled = TRUE;
04450                 }
04451         }
04452         else
04453         {
04454                 mSitCameraPos.clearVec();
04455                 mSitCameraFocus.clearVec();
04456                 mSitCameraReferenceObject = NULL;
04457                 mSitCameraEnabled = FALSE;
04458         }
04459 }
04460 
04461 //-----------------------------------------------------------------------------
04462 // setFocusOnAvatar()
04463 //-----------------------------------------------------------------------------
04464 void LLAgent::setFocusOnAvatar(BOOL focus_on_avatar, BOOL animate)
04465 {
04466         if (focus_on_avatar != mFocusOnAvatar)
04467         {
04468                 if (animate)
04469                 {
04470                         startCameraAnimation();
04471                 }
04472                 else
04473                 {
04474                         stopCameraAnimation();
04475                 }
04476         }
04477         
04478         //RN: when focused on the avatar, we're not "looking" at it
04479         // looking implies intent while focusing on avatar means
04480         // you're just walking around with a camera on you...eesh.
04481         if (focus_on_avatar && !mFocusOnAvatar)
04482         {
04483                 setFocusGlobal(LLVector3d::zero);
04484                 mCameraFOVZoomFactor = 0.f;
04485                 if (mCameraMode == CAMERA_MODE_THIRD_PERSON)
04486                 {
04487                         LLVector3 at_axis;
04488                         if (!mAvatarObject.isNull() && mAvatarObject->getParent())
04489                         {
04490                                 LLQuaternion obj_rot = ((LLViewerObject*)mAvatarObject->getParent())->getRenderRotation();
04491                                 at_axis = gCamera->getAtAxis();
04492                                 at_axis.mV[VZ] = 0.f;
04493                                 at_axis.normVec();
04494                                 resetAxes(at_axis * ~obj_rot);
04495                         }
04496                         else
04497                         {
04498                                 at_axis = gCamera->getAtAxis();
04499                                 at_axis.mV[VZ] = 0.f;
04500                                 at_axis.normVec();
04501                                 resetAxes(at_axis);
04502                         }
04503                 }
04504         }
04505         
04506         mFocusOnAvatar = focus_on_avatar;
04507 }
04508 
04509 //-----------------------------------------------------------------------------
04510 // heardChat()
04511 //-----------------------------------------------------------------------------
04512 void LLAgent::heardChat(const LLUUID& id)
04513 {
04514         // log text and voice chat to speaker mgr
04515         // for keeping track of active speakers, etc.
04516         gLocalSpeakerMgr->speakerChatted(id);
04517 
04518         // don't respond to your own voice
04519         if (id == getID()) return;
04520         
04521         if (ll_rand(2) == 0) 
04522         {
04523                 LLViewerObject *chatter = gObjectList.findObject(mLastChatterID);
04524                 setLookAt(LOOKAT_TARGET_AUTO_LISTEN, chatter, LLVector3::zero);
04525         }                       
04526 
04527         mLastChatterID = id;
04528         mChatTimer.reset();
04529 }
04530 
04531 
04532 void LLAgent::lookAtLastChat()
04533 {
04534         lookAtObject(mLastChatterID, CAMERA_POSITION_SELF);
04535 }
04536 
04537 //-----------------------------------------------------------------------------
04538 // lookAtLastChat()
04539 //-----------------------------------------------------------------------------
04540 void LLAgent::lookAtObject(LLUUID object_id, ECameraPosition camera_pos)
04541 {
04542         // Block if camera is animating or not in normal third person camera mode
04543         if (mCameraAnimating || !cameraThirdPerson())
04544         {
04545                 return;
04546         }
04547 
04548         LLViewerObject *chatter = gObjectList.findObject(object_id);
04549         if (chatter)
04550         {
04551                 LLVector3 delta_pos;
04552                 if (chatter->isAvatar())
04553                 {
04554                         LLVOAvatar *chatter_av = (LLVOAvatar*)chatter;
04555                         if (!mAvatarObject.isNull() && chatter_av->mHeadp)
04556                         {
04557                                 delta_pos = chatter_av->mHeadp->getWorldPosition() - mAvatarObject->mHeadp->getWorldPosition();
04558                         }
04559                         else
04560                         {
04561                                 delta_pos = chatter->getPositionAgent() - getPositionAgent();
04562                         }
04563                         delta_pos.normVec();
04564 
04565                         setControlFlags(AGENT_CONTROL_STOP);
04566 
04567                         changeCameraToThirdPerson();
04568 
04569                         LLVector3 new_camera_pos = mAvatarObject->mHeadp->getWorldPosition();
04570                         LLVector3 left = delta_pos % LLVector3::z_axis;
04571                         left.normVec();
04572                         LLVector3 up = left % delta_pos;
04573                         up.normVec();
04574                         new_camera_pos -= delta_pos * 0.4f;
04575                         new_camera_pos += left * 0.3f;
04576                         new_camera_pos += up * 0.2f;
04577 
04578                         F32 radius = chatter_av->getVObjRadius();
04579                         LLVector3d view_dist(radius, radius, 0.0f);
04580 
04581                         if (chatter_av->mHeadp)
04582                         {
04583                                 setFocusGlobal(getPosGlobalFromAgent(chatter_av->mHeadp->getWorldPosition()), object_id);
04584                                 mCameraFocusOffsetTarget = getPosGlobalFromAgent(new_camera_pos) - gAgent.getPosGlobalFromAgent(chatter_av->mHeadp->getWorldPosition());
04585 
04586                                 switch(camera_pos)
04587                                 {
04588                                         case CAMERA_POSITION_SELF:
04589                                                 mCameraFocusOffsetTarget = getPosGlobalFromAgent(new_camera_pos) - gAgent.getPosGlobalFromAgent(chatter_av->mHeadp->getWorldPosition());
04590                                                 break;
04591                                         case CAMERA_POSITION_OBJECT:
04592                                                 mCameraFocusOffsetTarget =  view_dist;
04593                                                 break;
04594                                 }
04595                         }
04596                         else
04597                         {
04598                                 setFocusGlobal(chatter->getPositionGlobal(), object_id);
04599                                 mCameraFocusOffsetTarget = getPosGlobalFromAgent(new_camera_pos) - chatter->getPositionGlobal();
04600 
04601                                 switch(camera_pos)
04602                                 {
04603                                         case CAMERA_POSITION_SELF:
04604                                                 mCameraFocusOffsetTarget = getPosGlobalFromAgent(new_camera_pos) - chatter->getPositionGlobal();
04605                                                 break;
04606                                         case CAMERA_POSITION_OBJECT:
04607                                                 mCameraFocusOffsetTarget = view_dist;
04608                                                 break;
04609                                 }
04610                         }
04611                         setFocusOnAvatar(FALSE, TRUE);
04612                 }
04613                 else
04614                 {
04615                         delta_pos = chatter->getRenderPosition() - getPositionAgent();
04616                         delta_pos.normVec();
04617 
04618                         setControlFlags(AGENT_CONTROL_STOP);
04619 
04620                         changeCameraToThirdPerson();
04621 
04622                         LLVector3 new_camera_pos = mAvatarObject->mHeadp->getWorldPosition();
04623                         LLVector3 left = delta_pos % LLVector3::z_axis;
04624                         left.normVec();
04625                         LLVector3 up = left % delta_pos;
04626                         up.normVec();
04627                         new_camera_pos -= delta_pos * 0.4f;
04628                         new_camera_pos += left * 0.3f;
04629                         new_camera_pos += up * 0.2f;
04630 
04631                         setFocusGlobal(chatter->getPositionGlobal(), object_id);
04632 
04633                         switch(camera_pos)
04634                         {
04635                                 case CAMERA_POSITION_SELF:
04636                                         mCameraFocusOffsetTarget = getPosGlobalFromAgent(new_camera_pos) - chatter->getPositionGlobal();
04637                                         break;
04638                                 case CAMERA_POSITION_OBJECT:
04639                                         F32 radius = chatter->getVObjRadius();
04640                                         LLVector3d view_dist(radius, radius, 0.0f);
04641                                         mCameraFocusOffsetTarget = view_dist;
04642                                         break;
04643                         }
04644 
04645                         setFocusOnAvatar(FALSE, TRUE);
04646                 }
04647         }
04648 }
04649 
04650 const F32 SIT_POINT_EXTENTS = 0.2f;
04651 
04652 // Grabs current position
04653 void LLAgent::setStartPosition(U32 location_id)
04654 {
04655         LLViewerObject          *object;
04656 
04657         if ( !(gAgentID == LLUUID::null) )
04658         {
04659                 // we've got an ID for an agent viewerobject
04660                 object = gObjectList.findObject(gAgentID);
04661                 if (object)
04662                 {
04663                         // we've got the viewer object
04664                         // Sometimes the agent can be velocity interpolated off of
04665                         // this simulator.  Clamp it to the region the agent is
04666                         // in, a little bit in on each side.
04667                         const F32 INSET = 0.5f; //meters
04668                         const F32 REGION_WIDTH = gWorldPointer->getRegionWidthInMeters();
04669 
04670                         LLVector3 agent_pos = getPositionAgent();
04671 
04672                         if (mAvatarObject)
04673                         {
04674                                 // the z height is at the agent's feet
04675                                 agent_pos.mV[VZ] -= 0.5f * mAvatarObject->mBodySize.mV[VZ];
04676                         }
04677 
04678                         agent_pos.mV[VX] = llclamp( agent_pos.mV[VX], INSET, REGION_WIDTH - INSET );
04679                         agent_pos.mV[VY] = llclamp( agent_pos.mV[VY], INSET, REGION_WIDTH - INSET );
04680 
04681                         // Don't let them go below ground, or too high.
04682                         agent_pos.mV[VZ] = llclamp( agent_pos.mV[VZ], 
04683                                 mRegionp->getLandHeightRegion( agent_pos ), 
04684                                 gWorldPointer->getRegionMaxHeight() );
04685 
04686                         LLMessageSystem* msg = gMessageSystem;
04687                         msg->newMessageFast(_PREHASH_SetStartLocationRequest);
04688                         msg->nextBlockFast( _PREHASH_AgentData);
04689                         msg->addUUIDFast(_PREHASH_AgentID, getID());
04690                         msg->addUUIDFast(_PREHASH_SessionID, getSessionID());
04691                         msg->nextBlockFast( _PREHASH_StartLocationData);
04692                         // corrected by sim
04693                         msg->addStringFast(_PREHASH_SimName, "");
04694                         msg->addU32Fast(_PREHASH_LocationID, location_id);
04695                         msg->addVector3Fast(_PREHASH_LocationPos, agent_pos);
04696                         msg->addVector3Fast(_PREHASH_LocationLookAt,mFrameAgent.getAtAxis());
04697 
04698                         // Reliable only helps when setting home location.  Last
04699                         // location is sent on quit, and we don't have time to ack
04700                         // the packets.
04701                         msg->sendReliable(mRegionp->getHost());
04702 
04703                         const U32 HOME_INDEX = 1;
04704                         if( HOME_INDEX == location_id )
04705                         {
04706                                 setHomePosRegion( mRegionp->getHandle(), getPositionAgent() );
04707                         }
04708                 }
04709                 else
04710                 {
04711                         llinfos << "setStartPosition - Can't find agent viewerobject id " << gAgentID << llendl;
04712                 }
04713         }
04714 }
04715 
04716 void LLAgent::requestStopMotion( LLMotion* motion )
04717 {
04718         // Notify all avatars that a motion has stopped.
04719         // This is needed to clear the animation state bits
04720         LLUUID anim_state = motion->getID();
04721         onAnimStop(motion->getID());
04722 
04723         // if motion is not looping, it could have stopped by running out of time
04724         // so we need to tell the server this
04725 //      llinfos << "Sending stop for motion " << motion->getName() << llendl;
04726         sendAnimationRequest( anim_state, ANIM_REQUEST_STOP );
04727 }
04728 
04729 void LLAgent::onAnimStop(const LLUUID& id)
04730 {
04731         // handle automatic state transitions (based on completion of animation playback)
04732         if (id == ANIM_AGENT_STAND)
04733         {
04734                 stopFidget();
04735         }
04736         else if (id == ANIM_AGENT_AWAY)
04737         {
04738                 clearAFK();
04739         }
04740         else if (id == ANIM_AGENT_STANDUP)
04741         {
04742                 // send stand up command
04743                 setControlFlags(AGENT_CONTROL_FINISH_ANIM);
04744 
04745                 // now trigger dusting self off animation
04746                 if (mAvatarObject.notNull() && !mAvatarObject->mBelowWater && rand() % 3 == 0)
04747                         sendAnimationRequest( ANIM_AGENT_BRUSH, ANIM_REQUEST_START );
04748         }
04749         else if (id == ANIM_AGENT_PRE_JUMP || id == ANIM_AGENT_LAND || id == ANIM_AGENT_MEDIUM_LAND)
04750         {
04751                 setControlFlags(AGENT_CONTROL_FINISH_ANIM);
04752         }
04753 }
04754 
04755 BOOL LLAgent::isGodlike() const
04756 {
04757 #ifdef HACKED_GODLIKE_VIEWER
04758         return TRUE;
04759 #else
04760         if(mAdminOverride) return TRUE;
04761         return mGodLevel > GOD_NOT;
04762 #endif
04763 }
04764 
04765 U8 LLAgent::getGodLevel() const
04766 {
04767 #ifdef HACKED_GODLIKE_VIEWER
04768         return GOD_MAINTENANCE;
04769 #else
04770         if(mAdminOverride) return GOD_FULL;
04771         return mGodLevel;
04772 #endif
04773 }
04774 
04775 bool LLAgent::isTeen() const
04776 {
04777         return mAccess < SIM_ACCESS_MATURE;
04778 }
04779 
04780 void LLAgent::setTeen(bool teen)
04781 {
04782         if (teen)
04783         {
04784                 mAccess = SIM_ACCESS_PG;
04785         }
04786         else
04787         {
04788                 mAccess = SIM_ACCESS_MATURE;
04789         }
04790 }
04791 
04792 void LLAgent::buildFullname(std::string& name) const
04793 {
04794         if (mAvatarObject)
04795         {
04796                 name = mAvatarObject->getFullname();
04797         }
04798 }
04799 
04800 void LLAgent::buildFullnameAndTitle(std::string& name) const
04801 {
04802         if (isGroupMember())
04803         {
04804                 name = mGroupTitle;
04805                 name += ' ';
04806         }
04807         else
04808         {
04809                 name.erase(0, name.length());
04810         }
04811 
04812         if (mAvatarObject)
04813         {
04814                 name += mAvatarObject->getFullname();
04815         }
04816 }
04817 
04818 BOOL LLAgent::isInGroup(const LLUUID& group_id) const
04819 {
04820         S32 count = mGroups.count();
04821         for(S32 i = 0; i < count; ++i)
04822         {
04823                 if(mGroups.get(i).mID == group_id)
04824                 {
04825                         return TRUE;
04826                 }
04827         }
04828         return FALSE;
04829 }
04830 
04831 // This implementation should mirror LLAgentInfo::hasPowerInGroup
04832 BOOL LLAgent::hasPowerInGroup(const LLUUID& group_id, U64 power) const
04833 {
04834         // GP_NO_POWERS can also mean no power is enough to grant an ability.
04835         if (GP_NO_POWERS == power) return FALSE;
04836 
04837         S32 count = mGroups.count();
04838         for(S32 i = 0; i < count; ++i)
04839         {
04840                 if(mGroups.get(i).mID == group_id)
04841                 {
04842                         return (BOOL)((mGroups.get(i).mPowers & power) > 0);
04843                 }
04844         }
04845         return FALSE;
04846 }
04847 
04848 BOOL LLAgent::hasPowerInActiveGroup(U64 power) const
04849 {
04850         return (mGroupID.notNull() && (hasPowerInGroup(mGroupID, power)));
04851 }
04852 
04853 U64 LLAgent::getPowerInGroup(const LLUUID& group_id) const
04854 {
04855         S32 count = mGroups.count();
04856         for(S32 i = 0; i < count; ++i)
04857         {
04858                 if(mGroups.get(i).mID == group_id)
04859                 {
04860                         return (mGroups.get(i).mPowers);
04861                 }
04862         }
04863 
04864         return GP_NO_POWERS;
04865 }
04866 
04867 BOOL LLAgent::getGroupData(const LLUUID& group_id, LLGroupData& data) const
04868 {
04869         S32 count = mGroups.count();
04870         for(S32 i = 0; i < count; ++i)
04871         {
04872                 if(mGroups.get(i).mID == group_id)
04873                 {
04874                         data = mGroups.get(i);
04875                         return TRUE;
04876                 }
04877         }
04878         return FALSE;
04879 }
04880 
04881 S32 LLAgent::getGroupContribution(const LLUUID& group_id) const
04882 {
04883         S32 count = mGroups.count();
04884         for(S32 i = 0; i < count; ++i)
04885         {
04886                 if(mGroups.get(i).mID == group_id)
04887                 {
04888                         S32 contribution = mGroups.get(i).mContribution;
04889                         return contribution;
04890                 }
04891         }
04892         return 0;
04893 }
04894 
04895 BOOL LLAgent::setGroupContribution(const LLUUID& group_id, S32 contribution)
04896 {
04897         S32 count = mGroups.count();
04898         for(S32 i = 0; i < count; ++i)
04899         {
04900                 if(mGroups.get(i).mID == group_id)
04901                 {
04902                         mGroups.get(i).mContribution = contribution;
04903                         LLMessageSystem* msg = gMessageSystem;
04904                         msg->newMessage("SetGroupContribution");
04905                         msg->nextBlock("AgentData");
04906                         msg->addUUID("AgentID", gAgentID);
04907                         msg->addUUID("SessionID", gAgentSessionID);
04908                         msg->nextBlock("Data");
04909                         msg->addUUID("GroupID", group_id);
04910                         msg->addS32("Contribution", contribution);
04911                         sendReliableMessage();
04912                         return TRUE;
04913                 }
04914         }
04915         return FALSE;
04916 }
04917 
04918 BOOL LLAgent::setUserGroupFlags(const LLUUID& group_id, BOOL accept_notices, BOOL list_in_profile)
04919 {
04920         S32 count = mGroups.count();
04921         for(S32 i = 0; i < count; ++i)
04922         {
04923                 if(mGroups.get(i).mID == group_id)
04924                 {
04925                         mGroups.get(i).mAcceptNotices = accept_notices;
04926                         mGroups.get(i).mListInProfile = list_in_profile;
04927                         LLMessageSystem* msg = gMessageSystem;
04928                         msg->newMessage("SetGroupAcceptNotices");
04929                         msg->nextBlock("AgentData");
04930                         msg->addUUID("AgentID", gAgentID);
04931                         msg->addUUID("SessionID", gAgentSessionID);
04932                         msg->nextBlock("Data");
04933                         msg->addUUID("GroupID", group_id);
04934                         msg->addBOOL("AcceptNotices", accept_notices);
04935                         msg->nextBlock("NewData");
04936                         msg->addBOOL("ListInProfile", list_in_profile);
04937                         sendReliableMessage();
04938                         return TRUE;
04939                 }
04940         }
04941         return FALSE;
04942 }
04943 
04944 // utility to build a location string
04945 void LLAgent::buildLocationString(std::string& str)
04946 {
04947         const LLVector3& agent_pos_region = getPositionAgent();
04948         S32 pos_x = S32(agent_pos_region.mV[VX]);
04949         S32 pos_y = S32(agent_pos_region.mV[VY]);
04950         S32 pos_z = S32(agent_pos_region.mV[VZ]);
04951 
04952         // Round the numbers based on the velocity
04953         LLVector3 agent_velocity = getVelocity();
04954         F32 velocity_mag_sq = agent_velocity.magVecSquared();
04955 
04956         const F32 FLY_CUTOFF = 6.f;             // meters/sec
04957         const F32 FLY_CUTOFF_SQ = FLY_CUTOFF * FLY_CUTOFF;
04958         const F32 WALK_CUTOFF = 1.5f;   // meters/sec
04959         const F32 WALK_CUTOFF_SQ = WALK_CUTOFF * WALK_CUTOFF;
04960 
04961         if (velocity_mag_sq > FLY_CUTOFF_SQ)
04962         {
04963                 pos_x -= pos_x % 4;
04964                 pos_y -= pos_y % 4;
04965         }
04966         else if (velocity_mag_sq > WALK_CUTOFF_SQ)
04967         {
04968                 pos_x -= pos_x % 2;
04969                 pos_y -= pos_y % 2;
04970         }
04971 
04972         // create a defult name and description for the landmark
04973         std::string buffer;
04974         if( gParcelMgr->getAgentParcelName().empty() )
04975         {
04976                 // the parcel doesn't have a name
04977                 buffer = llformat("%.32s (%d, %d, %d)",
04978                                                   getRegion()->getName().c_str(),
04979                                                   pos_x, pos_y, pos_z);
04980         }
04981         else
04982         {
04983                 // the parcel has a name, so include it in the landmark name
04984                 buffer = llformat("%.32s, %.32s (%d, %d, %d)",
04985                                                   gParcelMgr->getAgentParcelName().c_str(),
04986                                                   getRegion()->getName().c_str(),
04987                                                   pos_x, pos_y, pos_z);
04988         }
04989         str = buffer;
04990 }
04991 
04992 LLQuaternion LLAgent::getHeadRotation()
04993 {
04994         if (mAvatarObject.isNull() || !mAvatarObject->mPelvisp || !mAvatarObject->mHeadp)
04995         {
04996                 return LLQuaternion::DEFAULT;
04997         }
04998 
04999         if (!gAgent.cameraMouselook())
05000         {
05001                 return mAvatarObject->getRotation();
05002         }
05003 
05004         // We must be in mouselook
05005         LLVector3 look_dir( gCamera->getAtAxis() );
05006         LLVector3 up = look_dir % mFrameAgent.getLeftAxis();
05007         LLVector3 left = up % look_dir;
05008 
05009         LLQuaternion rot(look_dir, left, up);
05010         if (mAvatarObject->getParent())
05011         {
05012                 rot = rot * ~mAvatarObject->getParent()->getRotation();
05013         }
05014 
05015         return rot;
05016 }
05017 
05018 void LLAgent::sendAnimationRequests(LLDynamicArray<LLUUID> &anim_ids, EAnimRequest request)
05019 {
05020         if (gAgentID.isNull())
05021         {
05022                 return;
05023         }
05024 
05025         S32 num_valid_anims = 0;
05026 
05027         LLMessageSystem* msg = gMessageSystem;
05028         msg->newMessageFast(_PREHASH_AgentAnimation);
05029         msg->nextBlockFast(_PREHASH_AgentData);
05030         msg->addUUIDFast(_PREHASH_AgentID, getID());
05031         msg->addUUIDFast(_PREHASH_SessionID, getSessionID());
05032 
05033         for (S32 i = 0; i < anim_ids.count(); i++)
05034         {
05035                 if (anim_ids[i].isNull())
05036                 {
05037                         continue;
05038                 }
05039                 msg->nextBlockFast(_PREHASH_AnimationList);
05040                 msg->addUUIDFast(_PREHASH_AnimID, (anim_ids[i]) );
05041                 msg->addBOOLFast(_PREHASH_StartAnim, (request == ANIM_REQUEST_START) ? TRUE : FALSE);
05042                 num_valid_anims++;
05043         }
05044 
05045         msg->nextBlockFast(_PREHASH_PhysicalAvatarEventList);
05046         msg->addBinaryDataFast(_PREHASH_TypeData, NULL, 0);
05047         if (num_valid_anims)
05048         {
05049                 sendReliableMessage();
05050         }
05051 }
05052 
05053 void LLAgent::sendAnimationRequest(const LLUUID &anim_id, EAnimRequest request)
05054 {
05055         if (gAgentID.isNull() || anim_id.isNull() || !mRegionp)
05056         {
05057                 return;
05058         }
05059 
05060         LLMessageSystem* msg = gMessageSystem;
05061         msg->newMessageFast(_PREHASH_AgentAnimation);
05062         msg->nextBlockFast(_PREHASH_AgentData);
05063         msg->addUUIDFast(_PREHASH_AgentID, getID());
05064         msg->addUUIDFast(_PREHASH_SessionID, getSessionID());
05065 
05066         msg->nextBlockFast(_PREHASH_AnimationList);
05067         msg->addUUIDFast(_PREHASH_AnimID, (anim_id) );
05068         msg->addBOOLFast(_PREHASH_StartAnim, (request == ANIM_REQUEST_START) ? TRUE : FALSE);
05069 
05070         msg->nextBlockFast(_PREHASH_PhysicalAvatarEventList);
05071         msg->addBinaryDataFast(_PREHASH_TypeData, NULL, 0);
05072         sendReliableMessage();
05073 }
05074 
05075 void LLAgent::friendsChanged()
05076 {
05077         LLCollectProxyBuddies collector;
05078         LLAvatarTracker::instance().applyFunctor(collector);
05079         mProxyForAgents = collector.mProxy;
05080 }
05081 
05082 BOOL LLAgent::isGrantedProxy(const LLPermissions& perm)
05083 {
05084         return (mProxyForAgents.count(perm.getOwner()) > 0);
05085 }
05086 
05087 BOOL LLAgent::allowOperation(PermissionBit op,
05088                                                          const LLPermissions& perm,
05089                                                          U64 group_proxy_power,
05090                                                          U8 god_minimum)
05091 {
05092         // Check god level.
05093         if (getGodLevel() >= god_minimum) return TRUE;
05094 
05095         if (!perm.isOwned()) return FALSE;
05096 
05097         // A group member with group_proxy_power can act as owner.
05098         BOOL is_group_owned;
05099         LLUUID owner_id;
05100         perm.getOwnership(owner_id, is_group_owned);
05101         LLUUID group_id(perm.getGroup());
05102         LLUUID agent_proxy(getID());
05103 
05104         if (is_group_owned)
05105         {
05106                 if (hasPowerInGroup(group_id, group_proxy_power))
05107                 {
05108                         // Let the member assume the group's id for permission requests.
05109                         agent_proxy = owner_id;
05110                 }
05111         }
05112         else
05113         {
05114                 // Check for granted mod permissions.
05115                 if ((PERM_OWNER != op) && isGrantedProxy(perm))
05116                 {
05117                         agent_proxy = owner_id;
05118                 }
05119         }
05120 
05121         // This is the group id to use for permission requests.
05122         // Only group members may use this field.
05123         LLUUID group_proxy = LLUUID::null;
05124         if (group_id.notNull() && isInGroup(group_id))
05125         {
05126                 group_proxy = group_id;
05127         }
05128 
05129         // We now have max ownership information.
05130         if (PERM_OWNER == op)
05131         {
05132                 // This this was just a check for ownership, we can now return the answer.
05133                 return (agent_proxy == owner_id);
05134         }
05135 
05136         return perm.allowOperationBy(op, agent_proxy, group_proxy);
05137 }
05138 
05139 
05140 void LLAgent::getName(LLString& name)
05141 {
05142         // Note: assumes that name points to a buffer of at least DB_FULL_NAME_BUF_SIZE bytes.
05143         name.clear();
05144 
05145         if (mAvatarObject)
05146         {
05147                 LLNameValue *first_nv = mAvatarObject->getNVPair("FirstName");
05148                 LLNameValue *last_nv = mAvatarObject->getNVPair("LastName");
05149                 if (first_nv && last_nv)
05150                 {
05151                         name = first_nv->printData() + " " + last_nv->printData();
05152                 }
05153                 else
05154                 {
05155                         llwarns << "Agent is missing FirstName and/or LastName nv pair." << llendl;
05156                 }
05157         }
05158         else
05159         {
05160                 name = gSavedSettings.getString("FirstName") + " " + gSavedSettings.getString("LastName");
05161         }
05162 }
05163 
05164 const LLColor4 &LLAgent::getEffectColor()
05165 {
05166         return mEffectColor;
05167 }
05168 
05169 void LLAgent::setEffectColor(const LLColor4 &color)
05170 {
05171         mEffectColor = color;
05172 }
05173 
05174 void LLAgent::initOriginGlobal(const LLVector3d &origin_global)
05175 {
05176         mAgentOriginGlobal = origin_global;
05177 }
05178 
05179 void update_group_floaters(const LLUUID& group_id)
05180 {
05181         LLFloaterGroupInfo::refreshGroup(group_id);
05182 
05183         // update avatar info
05184         LLFloaterAvatarInfo* fa = LLFloaterAvatarInfo::getInstance(gAgent.getID());
05185         if(fa)
05186         {
05187                 fa->resetGroupList();
05188         }
05189 
05190         if (gIMMgr)
05191         {
05192                 // update the talk view
05193                 gIMMgr->refresh();
05194         }
05195 
05196         gAgent.fireEvent(new LLEvent(&gAgent, "new group"), "");
05197 }
05198 
05199 // static
05200 void LLAgent::processAgentDropGroup(LLMessageSystem *msg, void **)
05201 {
05202         LLUUID  agent_id;
05203         msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id );
05204 
05205         if (agent_id != gAgentID)
05206         {
05207                 llwarns << "processAgentDropGroup for agent other than me" << llendl;
05208                 return;
05209         }
05210 
05211         LLUUID  group_id;
05212         msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_GroupID, group_id );
05213 
05214         // Remove the group if it already exists remove it and add the new data to pick up changes.
05215         LLGroupData gd;
05216         gd.mID = group_id;
05217         S32 index = gAgent.mGroups.find(gd);
05218         if (index != -1)
05219         {
05220                 gAgent.mGroups.remove(index);
05221                 if (gAgent.getGroupID() == group_id)
05222                 {
05223                         gAgent.mGroupID.setNull();
05224                         gAgent.mGroupPowers = 0;
05225                         gAgent.mGroupName[0] = '\0';
05226                         gAgent.mGroupTitle[0] = '\0';
05227                 }
05228                 
05229                 // refresh all group information
05230                 gAgent.sendAgentDataUpdateRequest();
05231 
05232                 gGroupMgr->clearGroupData(group_id);
05233                 // close the floater for this group, if any.
05234                 LLFloaterGroupInfo::closeGroup(group_id);
05235                 // refresh the group panel of the search window, if necessary.
05236                 LLFloaterDirectory::refreshGroup(group_id);
05237         }
05238         else
05239         {
05240                 llwarns << "processAgentDropGroup, agent is not part of group " << group_id << llendl;
05241         }
05242 }
05243 
05244 // static
05245 void LLAgent::processAgentGroupDataUpdate(LLMessageSystem *msg, void **)
05246 {
05247         LLUUID  agent_id;
05248 
05249         msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id );
05250 
05251         if (agent_id != gAgentID)
05252         {
05253                 llwarns << "processAgentGroupDataUpdate for agent other than me" << llendl;
05254                 return;
05255         }       
05256         
05257         S32 count = msg->getNumberOfBlocksFast(_PREHASH_GroupData);
05258         LLGroupData group;
05259         S32 index = -1;
05260         bool need_floater_update = false;
05261         char group_name[DB_GROUP_NAME_BUF_SIZE];                /*Flawfinder: ignore*/
05262         for(S32 i = 0; i < count; ++i)
05263         {
05264                 msg->getUUIDFast(_PREHASH_GroupData, _PREHASH_GroupID, group.mID, i);
05265                 msg->getUUIDFast(_PREHASH_GroupData, _PREHASH_GroupInsigniaID, group.mInsigniaID, i);
05266                 msg->getU64(_PREHASH_GroupData, "GroupPowers", group.mPowers, i);
05267                 msg->getBOOL(_PREHASH_GroupData, "AcceptNotices", group.mAcceptNotices, i);
05268                 msg->getS32(_PREHASH_GroupData, "Contribution", group.mContribution, i);
05269                 msg->getStringFast(_PREHASH_GroupData, _PREHASH_GroupName, DB_GROUP_NAME_BUF_SIZE, group_name, i);
05270                 group.mName.assign(group_name);
05271                 
05272                 if(group.mID.notNull())
05273                 {
05274                         need_floater_update = true;
05275                         // Remove the group if it already exists remove it and add the new data to pick up changes.
05276                         index = gAgent.mGroups.find(group);
05277                         if (index != -1)
05278                         {
05279                                 gAgent.mGroups.remove(index);
05280                         }
05281                         gAgent.mGroups.put(group);
05282                 }
05283                 if (need_floater_update)
05284                 {
05285                         update_group_floaters(group.mID);
05286                 }
05287         }
05288 
05289 }
05290 
05291 class LLAgentGroupDataUpdateViewerNode : public LLHTTPNode
05292 {
05293         virtual void post(
05294                 LLHTTPNode::ResponsePtr response,
05295                 const LLSD& context,
05296                 const LLSD& input) const
05297         {
05298                 LLSD body = input["body"];
05299                 if(body.has("body"))
05300                         body = body["body"];
05301                 LLUUID agent_id = body["AgentData"][0]["AgentID"].asUUID();
05302 
05303                 if (agent_id != gAgentID)
05304                 {
05305                         llwarns << "processAgentGroupDataUpdate for agent other than me" << llendl;
05306                         return;
05307                 }       
05308 
05309                 LLSD group_data = body["GroupData"];
05310 
05311                 LLSD::array_iterator iter_group =
05312                         group_data.beginArray();
05313                 LLSD::array_iterator end_group =
05314                         group_data.endArray();
05315                 int group_index = 0;
05316                 for(; iter_group != end_group; ++iter_group)
05317                 {
05318 
05319                         LLGroupData group;
05320                         S32 index = -1;
05321                         bool need_floater_update = false;
05322 
05323                         group.mID = (*iter_group)["GroupID"].asUUID();
05324                         group.mPowers = ll_U64_from_sd((*iter_group)["GroupPowers"]);
05325                         group.mAcceptNotices = (*iter_group)["AcceptNotices"].asBoolean();
05326                         group.mListInProfile = body["NewGroupData"][group_index]["ListInProfile"].asBoolean();
05327                         group.mInsigniaID = (*iter_group)["GroupInsigniaID"].asUUID();
05328                         group.mName = (*iter_group)["GroupName"].asString();
05329                         group.mContribution = (*iter_group)["Contribution"].asInteger();
05330 
05331                         group_index++;
05332 
05333                         if(group.mID.notNull())
05334                         {
05335                                 need_floater_update = true;
05336                                 // Remove the group if it already exists remove it and add the new data to pick up changes.
05337                                 index = gAgent.mGroups.find(group);
05338                                 if (index != -1)
05339                                 {
05340                                         gAgent.mGroups.remove(index);
05341                                 }
05342                                 gAgent.mGroups.put(group);
05343                         }
05344                         if (need_floater_update)
05345                         {
05346                                 update_group_floaters(group.mID);
05347                         }
05348                 }
05349         }
05350 };
05351 
05352 LLHTTPRegistration<LLAgentGroupDataUpdateViewerNode >
05353         gHTTPRegistrationAgentGroupDataUpdateViewerNode ("/message/AgentGroupDataUpdate"); 
05354 
05355 // static
05356 void LLAgent::processAgentDataUpdate(LLMessageSystem *msg, void **)
05357 {
05358         LLUUID  agent_id;
05359 
05360         msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id );
05361 
05362         if (agent_id != gAgentID)
05363         {
05364                 llwarns << "processAgentDataUpdate for agent other than me" << llendl;
05365                 return;
05366         }
05367 
05368         msg->getStringFast(_PREHASH_AgentData, _PREHASH_GroupTitle, DB_GROUP_TITLE_BUF_SIZE, gAgent.mGroupTitle);
05369         LLUUID active_id;
05370         msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_ActiveGroupID, active_id);
05371 
05372 
05373         if(active_id.notNull())
05374         {
05375                 gAgent.mGroupID = active_id;
05376                 msg->getU64(_PREHASH_AgentData, "GroupPowers", gAgent.mGroupPowers);
05377                 msg->getString(_PREHASH_AgentData, _PREHASH_GroupName, DB_GROUP_NAME_BUF_SIZE, gAgent.mGroupName);
05378         }
05379         else
05380         {
05381                 gAgent.mGroupID.setNull();
05382                 gAgent.mGroupPowers = 0;
05383                 gAgent.mGroupName[0] = '\0';
05384         }               
05385 
05386         update_group_floaters(active_id);
05387 }
05388 
05389 // static
05390 void LLAgent::processScriptControlChange(LLMessageSystem *msg, void **)
05391 {
05392         S32 block_count = msg->getNumberOfBlocks("Data");
05393         for (S32 block_index = 0; block_index < block_count; block_index++)
05394         {
05395                 BOOL take_controls;
05396                 U32     controls;
05397                 BOOL passon;
05398                 U32 i;
05399                 msg->getBOOL("Data", "TakeControls", take_controls, block_index);
05400                 if (take_controls)
05401                 {
05402                         // take controls
05403                         msg->getU32("Data", "Controls", controls, block_index );
05404                         msg->getBOOL("Data", "PassToAgent", passon, block_index );
05405                         U32 total_count = 0;
05406                         for (i = 0; i < TOTAL_CONTROLS; i++)
05407                         {
05408                                 if (controls & ( 1 << i))
05409                                 {
05410                                         if (passon)
05411                                         {
05412                                                 gAgent.mControlsTakenPassedOnCount[i]++;
05413                                         }
05414                                         else
05415                                         {
05416                                                 gAgent.mControlsTakenCount[i]++;
05417                                         }
05418                                         total_count++;
05419                                 }
05420                         }
05421                 
05422                         // Any control taken?  If so, might be first time.
05423                         if (total_count > 0)
05424                         {
05425                                 LLFirstUse::useOverrideKeys();
05426                         }
05427                 }
05428                 else
05429                 {
05430                         // release controls
05431                         msg->getU32("Data", "Controls", controls, block_index );
05432                         msg->getBOOL("Data", "PassToAgent", passon, block_index );
05433                         for (i = 0; i < TOTAL_CONTROLS; i++)
05434                         {
05435                                 if (controls & ( 1 << i))
05436                                 {
05437                                         if (passon)
05438                                         {
05439                                                 gAgent.mControlsTakenPassedOnCount[i]--;
05440                                                 if (gAgent.mControlsTakenPassedOnCount[i] < 0)
05441                                                 {
05442                                                         gAgent.mControlsTakenPassedOnCount[i] = 0;
05443                                                 }
05444                                         }
05445                                         else
05446                                         {
05447                                                 gAgent.mControlsTakenCount[i]--;
05448                                                 if (gAgent.mControlsTakenCount[i] < 0)
05449                                                 {
05450                                                         gAgent.mControlsTakenCount[i] = 0;
05451                                                 }
05452                                         }
05453                                 }
05454                         }
05455                 }
05456         }
05457 }
05458 
05459 /*
05460 // static
05461 void LLAgent::processControlTake(LLMessageSystem *msg, void **)
05462 {
05463         U32     controls;
05464         msg->getU32("Data", "Controls", controls );
05465         U32 passon;
05466         msg->getBOOL("Data", "PassToAgent", passon );
05467 
05468         S32 i;
05469         S32 total_count = 0;
05470         for (i = 0; i < TOTAL_CONTROLS; i++)
05471         {
05472                 if (controls & ( 1 << i))
05473                 {
05474                         if (passon)
05475                         {
05476                                 gAgent.mControlsTakenPassedOnCount[i]++;
05477                         }
05478                         else
05479                         {
05480                                 gAgent.mControlsTakenCount[i]++;
05481                         }
05482                         total_count++;
05483                 }
05484         }
05485 
05486         // Any control taken?  If so, might be first time.
05487         if (total_count > 0)
05488         {
05489                 LLFirstUse::useOverrideKeys();
05490         }
05491 }
05492 
05493 // static
05494 void LLAgent::processControlRelease(LLMessageSystem *msg, void **)
05495 {
05496         U32     controls;
05497         msg->getU32("Data", "Controls", controls );
05498         U32 passon;
05499         msg->getBOOL("Data", "PassToAgent", passon );
05500 
05501         S32 i;
05502         for (i = 0; i < TOTAL_CONTROLS; i++)
05503         {
05504                 if (controls & ( 1 << i))
05505                 {
05506                         if (passon)
05507                         {
05508                                 gAgent.mControlsTakenPassedOnCount[i]--;
05509                                 if (gAgent.mControlsTakenPassedOnCount[i] < 0)
05510                                 {
05511                                         gAgent.mControlsTakenPassedOnCount[i] = 0;
05512                                 }
05513                         }
05514                         else
05515                         {
05516                                 gAgent.mControlsTakenCount[i]--;
05517                                 if (gAgent.mControlsTakenCount[i] < 0)
05518                                 {
05519                                         gAgent.mControlsTakenCount[i] = 0;
05520                                 }
05521                         }
05522                 }
05523         }
05524 }
05525 */
05526 
05527 //static
05528 void LLAgent::processAgentCachedTextureResponse(LLMessageSystem *mesgsys, void **user_data)
05529 {
05530         gAgent.mNumPendingQueries--;
05531 
05532         LLVOAvatar* avatarp = gAgent.getAvatarObject();
05533         if (!avatarp || avatarp->isDead())
05534         {
05535                 llwarns << "No avatar for user in cached texture update!" << llendl;
05536                 return;
05537         }
05538 
05539         if (gAgent.cameraCustomizeAvatar())
05540         {
05541                 // ignore baked textures when in customize mode
05542                 return;
05543         }
05544 
05545         S32 query_id;
05546         mesgsys->getS32Fast(_PREHASH_AgentData, _PREHASH_SerialNum, query_id);
05547 
05548         S32 num_texture_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_WearableData);
05549 
05550 
05551         S32 num_results = 0;
05552         for (S32 texture_block = 0; texture_block < num_texture_blocks; texture_block++)
05553         {
05554                 LLUUID texture_id;
05555                 U8 texture_index;
05556 
05557                 mesgsys->getUUIDFast(_PREHASH_WearableData, _PREHASH_TextureID, texture_id, texture_block);
05558                 mesgsys->getU8Fast(_PREHASH_WearableData, _PREHASH_TextureIndex, texture_index, texture_block);
05559 
05560                 if (texture_id.notNull() 
05561                         && (S32)texture_index < BAKED_TEXTURE_COUNT 
05562                         && gAgent.mActiveCacheQueries[ texture_index ] == query_id)
05563                 {
05564                         //llinfos << "Received cached texture " << (U32)texture_index << ": " << texture_id << llendl;
05565                         avatarp->setCachedBakedTexture((LLVOAvatar::ETextureIndex)LLVOAvatar::sBakedTextureIndices[texture_index], texture_id);
05566                         //avatarp->setTETexture( LLVOAvatar::sBakedTextureIndices[texture_index], texture_id );
05567                         gAgent.mActiveCacheQueries[ texture_index ] = 0;
05568                         num_results++;
05569                 }
05570         }
05571 
05572         llinfos << "Received cached texture response for " << num_results << " textures." << llendl;
05573 
05574         avatarp->updateMeshTextures();
05575 
05576         if (gAgent.mNumPendingQueries == 0)
05577         {
05578                 // RN: not sure why composites are disabled at this point
05579                 avatarp->setCompositeUpdatesEnabled(TRUE);
05580                 gAgent.sendAgentSetAppearance();
05581         }
05582 }
05583 
05584 BOOL LLAgent::anyControlGrabbed() const
05585 {
05586         U32 i;
05587         for (i = 0; i < TOTAL_CONTROLS; i++)
05588         {
05589                 if (gAgent.mControlsTakenCount[i] > 0)
05590                         return TRUE;
05591                 if (gAgent.mControlsTakenPassedOnCount[i] > 0)
05592                         return TRUE;
05593         }
05594         return FALSE;
05595 }
05596 
05597 BOOL LLAgent::isControlGrabbed(S32 control_index) const
05598 {
05599         return mControlsTakenCount[control_index] > 0;
05600 }
05601 
05602 void LLAgent::forceReleaseControls()
05603 {
05604         gMessageSystem->newMessage("ForceScriptControlRelease");
05605         gMessageSystem->nextBlock("AgentData");
05606         gMessageSystem->addUUID("AgentID", getID());
05607         gMessageSystem->addUUID("SessionID", getSessionID());
05608         sendReliableMessage();
05609 }
05610 
05611 void LLAgent::setHomePosRegion( const U64& region_handle, const LLVector3& pos_region)
05612 {
05613         mHaveHomePosition = TRUE;
05614         mHomeRegionHandle = region_handle;
05615         mHomePosRegion = pos_region;
05616 }
05617 
05618 BOOL LLAgent::getHomePosGlobal( LLVector3d* pos_global )
05619 {
05620         if(!mHaveHomePosition)
05621         {
05622                 return FALSE;
05623         }
05624         F32 x = 0;
05625         F32 y = 0;
05626         from_region_handle( mHomeRegionHandle, &x, &y);
05627         pos_global->setVec( x + mHomePosRegion.mV[VX], y + mHomePosRegion.mV[VY], mHomePosRegion.mV[VZ] );
05628         return TRUE;
05629 }
05630 
05631 void LLAgent::clearVisualParams(void *data)
05632 {
05633         LLVOAvatar* avatarp = gAgent.getAvatarObject();
05634         if (avatarp)
05635         {
05636                 avatarp->clearVisualParamWeights();
05637                 avatarp->updateVisualParams();
05638         }
05639 }
05640 
05641 //---------------------------------------------------------------------------
05642 // Teleport
05643 //---------------------------------------------------------------------------
05644 
05645 // teleportCore() - stuff to do on any teleport
05646 // protected
05647 bool LLAgent::teleportCore(bool is_local)
05648 {
05649         if(TELEPORT_NONE != mTeleportState)
05650         {
05651                 llwarns << "Attempt to teleport when already teleporting." << llendl;
05652                 return false;
05653         }
05654 
05655         // Don't call LLFirstUse::useTeleport because we don't know
05656         // yet if the teleport will succeed.  Look in 
05657         // process_teleport_location_reply
05658 
05659         // close the map and find panels so we can see our destination
05660         LLFloaterWorldMap::hide(NULL);
05661         LLFloaterDirectory::hide(NULL);
05662 
05663         gParcelMgr->deselectLand();
05664 
05665         // Close all pie menus, deselect land, etc.
05666         // Don't change the camera until we know teleport succeeded. JC
05667         resetView(FALSE);
05668 
05669         // local logic
05670         gViewerStats->incStat(LLViewerStats::ST_TELEPORT_COUNT);
05671         if (!is_local)
05672         {
05673                 gTeleportDisplay = TRUE;
05674                 gAgent.setTeleportState( LLAgent::TELEPORT_START );
05675         }
05676         make_ui_sound("UISndTeleportOut");
05677         
05678         // MBW -- Let the voice client know a teleport has begun so it can leave the existing channel.
05679         // This was breaking the case of teleporting within a single sim.  Backing it out for now.
05680 //      gVoiceClient->leaveChannel();
05681         
05682         return true;
05683 }
05684 
05685 void LLAgent::teleportRequest(
05686         const U64& region_handle,
05687         const LLVector3& pos_local)
05688 {
05689         LLViewerRegion* regionp = getRegion();
05690         if(regionp && teleportCore())
05691         {
05692                 llinfos << "TeleportRequest: '" << region_handle << "':" << pos_local
05693                                 << llendl;
05694                 LLMessageSystem* msg = gMessageSystem;
05695                 msg->newMessage("TeleportLocationRequest");
05696                 msg->nextBlockFast(_PREHASH_AgentData);
05697                 msg->addUUIDFast(_PREHASH_AgentID, getID());
05698                 msg->addUUIDFast(_PREHASH_SessionID, getSessionID());
05699                 msg->nextBlockFast(_PREHASH_Info);
05700                 msg->addU64("RegionHandle", region_handle);
05701                 msg->addVector3("Position", pos_local);
05702                 LLVector3 look_at(0,1,0);
05703                 msg->addVector3("LookAt", look_at);
05704                 sendReliableMessage();
05705         }
05706 }
05707 
05708 // Landmark ID = LLUUID::null means teleport home
05709 void LLAgent::teleportViaLandmark(const LLUUID& landmark_asset_id)
05710 {
05711         LLViewerRegion *regionp = getRegion();
05712         if(regionp && teleportCore())
05713         {
05714                 LLMessageSystem* msg = gMessageSystem;
05715                 msg->newMessageFast(_PREHASH_TeleportLandmarkRequest);
05716                 msg->nextBlockFast(_PREHASH_Info);
05717                 msg->addUUIDFast(_PREHASH_AgentID, getID());
05718                 msg->addUUIDFast(_PREHASH_SessionID, getSessionID());
05719                 msg->addUUIDFast(_PREHASH_LandmarkID, landmark_asset_id);
05720                 sendReliableMessage();
05721         }
05722 }
05723 
05724 void LLAgent::teleportViaLure(const LLUUID& lure_id, BOOL godlike)
05725 {
05726         LLViewerRegion* regionp = getRegion();
05727         if(regionp && teleportCore())
05728         {
05729                 U32 teleport_flags = 0x0;
05730                 if (godlike)
05731                 {
05732                         teleport_flags |= TELEPORT_FLAGS_VIA_GODLIKE_LURE;
05733                         teleport_flags |= TELEPORT_FLAGS_DISABLE_CANCEL;
05734                 }
05735                 else
05736                 {
05737                         teleport_flags |= TELEPORT_FLAGS_VIA_LURE;
05738                 }
05739 
05740                 // send the message
05741                 LLMessageSystem* msg = gMessageSystem;
05742                 msg->newMessageFast(_PREHASH_TeleportLureRequest);
05743                 msg->nextBlockFast(_PREHASH_Info);
05744                 msg->addUUIDFast(_PREHASH_AgentID, getID());
05745                 msg->addUUIDFast(_PREHASH_SessionID, getSessionID());
05746                 msg->addUUIDFast(_PREHASH_LureID, lure_id);
05747                 msg->addU32("TeleportFlags", teleport_flags);
05748                 sendReliableMessage();
05749         }       
05750 }
05751 
05752 
05753 // James Cook, July 28, 2005
05754 void LLAgent::teleportCancel()
05755 {
05756         LLViewerRegion* regionp = getRegion();
05757         if(regionp)
05758         {
05759                 // send the message
05760                 LLMessageSystem* msg = gMessageSystem;
05761                 msg->newMessage("TeleportCancel");
05762                 msg->nextBlockFast(_PREHASH_Info);
05763                 msg->addUUIDFast(_PREHASH_AgentID, getID());
05764                 msg->addUUIDFast(_PREHASH_SessionID, getSessionID());
05765                 sendReliableMessage();
05766         }       
05767         gTeleportDisplay = FALSE;
05768         gAgent.setTeleportState( LLAgent::TELEPORT_NONE );
05769 }
05770 
05771 
05772 void LLAgent::teleportViaLocation(const LLVector3d& pos_global)
05773 {
05774         LLViewerRegion* regionp = getRegion();
05775         LLSimInfo* info = gWorldMap->simInfoFromPosGlobal(pos_global);
05776         if(regionp && info)
05777         {
05778                 U32 x_pos;
05779                 U32 y_pos;
05780                 from_region_handle(info->mHandle, &x_pos, &y_pos);
05781                 LLVector3 pos_local(
05782                         (F32)(pos_global.mdV[VX] - x_pos),
05783                         (F32)(pos_global.mdV[VY] - y_pos),
05784                         (F32)(pos_global.mdV[VZ]));
05785                 teleportRequest(info->mHandle, pos_local);
05786         }
05787         else if(regionp && 
05788                 teleportCore(regionp->getHandle() == to_region_handle_global((F32)pos_global.mdV[VX], (F32)pos_global.mdV[VY])))
05789         {
05790                 llwarns << "Using deprecated teleportlocationrequest." << llendl; 
05791                 // send the message
05792                 LLMessageSystem* msg = gMessageSystem;
05793                 msg->newMessageFast(_PREHASH_TeleportLocationRequest);
05794                 msg->nextBlockFast(_PREHASH_AgentData);
05795                 msg->addUUIDFast(_PREHASH_AgentID, getID());
05796                 msg->addUUIDFast(_PREHASH_SessionID, getSessionID());
05797 
05798                 msg->nextBlockFast(_PREHASH_Info);
05799                 F32 width = regionp->getWidth();
05800                 LLVector3 pos(fmod((F32)pos_global.mdV[VX], width),
05801                                           fmod((F32)pos_global.mdV[VY], width),
05802                                           (F32)pos_global.mdV[VZ]);
05803                 F32 region_x = (F32)(pos_global.mdV[VX]);
05804                 F32 region_y = (F32)(pos_global.mdV[VY]);
05805                 U64 region_handle = to_region_handle_global(region_x, region_y);
05806                 msg->addU64Fast(_PREHASH_RegionHandle, region_handle);
05807                 msg->addVector3Fast(_PREHASH_Position, pos);
05808                 pos.mV[VX] += 1;
05809                 msg->addVector3Fast(_PREHASH_LookAt, pos);
05810                 sendReliableMessage();
05811         }
05812 }
05813 
05814 void LLAgent::setTeleportState(ETeleportState state)
05815 {
05816         mTeleportState = state;
05817         if (mTeleportState > TELEPORT_NONE && gSavedSettings.getBOOL("FreezeTime"))
05818         {
05819                 LLFloaterSnapshot::hide(0);
05820         }
05821 }
05822 
05823 void LLAgent::sendChat(const LLString &text, S32 channel, EChatType type, bool animate)
05824 {
05825 
05826         // Don't animate for chats people can't hear (chat to scripts)
05827         if (animate && (channel == 0))
05828         {
05829                 if (type == CHAT_TYPE_WHISPER)
05830                 {
05831                         lldebugs << "You whisper " << text << llendl;
05832                         sendAnimationRequest(ANIM_AGENT_WHISPER, ANIM_REQUEST_START);
05833                 }
05834                 else if (type == CHAT_TYPE_NORMAL)
05835                 {
05836                         lldebugs << "You say " << text << llendl;
05837                         sendAnimationRequest(ANIM_AGENT_TALK, ANIM_REQUEST_START);
05838                 }
05839                 else if (type == CHAT_TYPE_SHOUT)
05840                 {
05841                         lldebugs << "You shout " << text << llendl;
05842                         sendAnimationRequest(ANIM_AGENT_SHOUT, ANIM_REQUEST_START);
05843                 }
05844                 else
05845                 {
05846                         llinfos << "send_chat_from_viewer() - invalid volume" << llendl;
05847                         return;
05848                 }
05849         }
05850         else
05851         {
05852                 if (type != CHAT_TYPE_START && type != CHAT_TYPE_STOP)
05853                 {
05854                         lldebugs << "Channel chat: " << text << llendl;
05855                 }
05856         }
05857 
05858         LLMessageSystem* msg = gMessageSystem;
05859 
05860         msg->newMessageFast(_PREHASH_ChatFromViewer);
05861         msg->nextBlockFast(_PREHASH_AgentData);
05862         msg->addUUIDFast(_PREHASH_AgentID, getID());
05863         msg->addUUIDFast(_PREHASH_SessionID, getSessionID());
05864         msg->nextBlockFast(_PREHASH_ChatData);
05865         msg->addStringFast(_PREHASH_Message, text);
05866         msg->addU8Fast(_PREHASH_Type, type);
05867         msg->addS32("Channel", channel);
05868 
05869         gAgent.sendReliableMessage();
05870 
05871         gViewerStats->incStat(LLViewerStats::ST_CHAT_COUNT);
05872 }
05873 
05874 void LLAgent::fidget()
05875 {
05876         if (!getAFK())
05877         {
05878                 F32 curTime = mFidgetTimer.getElapsedTimeF32();
05879                 if (curTime > mNextFidgetTime)
05880                 {
05881                         // pick a random fidget anim here
05882                         S32 oldFidget = mCurrentFidget;
05883 
05884                         mCurrentFidget = ll_rand(NUM_AGENT_STAND_ANIMS);
05885 
05886                         if (mCurrentFidget != oldFidget)
05887                         {
05888                                 LLAgent::stopFidget();
05889 
05890                                 
05891                                 switch(mCurrentFidget)
05892                                 {
05893                                 case 0:
05894                                         mCurrentFidget = 0;
05895                                         break;
05896                                 case 1:
05897                                         sendAnimationRequest(ANIM_AGENT_STAND_1, ANIM_REQUEST_START);
05898                                         mCurrentFidget = 1;
05899                                         break;
05900                                 case 2:
05901                                         sendAnimationRequest(ANIM_AGENT_STAND_2, ANIM_REQUEST_START);
05902                                         mCurrentFidget = 2;
05903                                         break;
05904                                 case 3:
05905                                         sendAnimationRequest(ANIM_AGENT_STAND_3, ANIM_REQUEST_START);
05906                                         mCurrentFidget = 3;
05907                                         break;
05908                                 case 4:
05909                                         sendAnimationRequest(ANIM_AGENT_STAND_4, ANIM_REQUEST_START);
05910                                         mCurrentFidget = 4;
05911                                         break;
05912                                 }
05913                         }
05914 
05915                         // calculate next fidget time
05916                         mNextFidgetTime = curTime + ll_frand(MAX_FIDGET_TIME - MIN_FIDGET_TIME) + MIN_FIDGET_TIME;
05917                 }
05918         }
05919 }
05920 
05921 void LLAgent::stopFidget()
05922 {
05923         LLDynamicArray<LLUUID> anims;
05924         anims.put(ANIM_AGENT_STAND_1);
05925         anims.put(ANIM_AGENT_STAND_2);
05926         anims.put(ANIM_AGENT_STAND_3);
05927         anims.put(ANIM_AGENT_STAND_4);
05928 
05929         gAgent.sendAnimationRequests(anims, ANIM_REQUEST_STOP);
05930 }
05931 
05932 
05933 void LLAgent::requestEnterGodMode()
05934 {
05935         LLMessageSystem* msg = gMessageSystem;
05936         msg->newMessageFast(_PREHASH_RequestGodlikePowers);
05937         msg->nextBlockFast(_PREHASH_AgentData);
05938         msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
05939         msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
05940         msg->nextBlockFast(_PREHASH_RequestBlock);
05941         msg->addBOOLFast(_PREHASH_Godlike, TRUE);
05942         msg->addUUIDFast(_PREHASH_Token, LLUUID::null);
05943 
05944         // simulator and userserver need to know about your request
05945         sendReliableMessage();
05946 }
05947 
05948 void LLAgent::requestLeaveGodMode()
05949 {
05950         LLMessageSystem* msg = gMessageSystem;
05951         msg->newMessageFast(_PREHASH_RequestGodlikePowers);
05952         msg->nextBlockFast(_PREHASH_AgentData);
05953         msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
05954         msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
05955         msg->nextBlockFast(_PREHASH_RequestBlock);
05956         msg->addBOOLFast(_PREHASH_Godlike, FALSE);
05957         msg->addUUIDFast(_PREHASH_Token, LLUUID::null);
05958 
05959         // simulator and userserver need to know about your request
05960         sendReliableMessage();
05961 }
05962 
05963 // wearables
05964 LLAgent::createStandardWearablesAllDoneCallback::~createStandardWearablesAllDoneCallback()
05965 {
05966         gAgent.createStandardWearablesAllDone();
05967 }
05968 
05969 LLAgent::sendAgentWearablesUpdateCallback::~sendAgentWearablesUpdateCallback()
05970 {
05971         gAgent.sendAgentWearablesUpdate();
05972 }
05973 
05974 LLAgent::addWearableToAgentInventoryCallback::addWearableToAgentInventoryCallback(
05975         LLPointer<LLRefCount> cb, S32 index, LLWearable* wearable, U32 todo) :
05976         mIndex(index),
05977         mWearable(wearable),
05978         mTodo(todo),
05979         mCB(cb)
05980 {
05981 }
05982 
05983 void LLAgent::addWearableToAgentInventoryCallback::fire(const LLUUID& inv_item)
05984 {
05985         if (inv_item.isNull())
05986                 return;
05987 
05988         gAgent.addWearabletoAgentInventoryDone(mIndex, inv_item, mWearable);
05989 
05990         if (mTodo & CALL_UPDATE)
05991         {
05992                 gAgent.sendAgentWearablesUpdate();
05993         }
05994         if (mTodo & CALL_RECOVERDONE)
05995         {
05996                 gAgent.recoverMissingWearableDone();
05997         }
05998         /*
05999          * Do this for every one in the loop
06000          */
06001         if (mTodo & CALL_CREATESTANDARDDONE)
06002         {
06003                 gAgent.createStandardWearablesDone(mIndex);
06004         }
06005         if (mTodo & CALL_MAKENEWOUTFITDONE)
06006         {
06007                 gAgent.makeNewOutfitDone(mIndex);
06008         }
06009 }
06010 
06011 void LLAgent::addWearabletoAgentInventoryDone(
06012         S32 index,
06013         const LLUUID& item_id,
06014         LLWearable* wearable)
06015 {
06016         if (item_id.isNull())
06017                 return;
06018 
06019         LLUUID old_item_id = mWearableEntry[index].mItemID;
06020         mWearableEntry[index].mItemID = item_id;
06021         mWearableEntry[index].mWearable = wearable;
06022         if (old_item_id.notNull())
06023                 gInventory.addChangedMask(LLInventoryObserver::LABEL, old_item_id);
06024         gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id);
06025         LLViewerInventoryItem* item = gInventory.getItem(item_id);
06026         if(item && wearable)
06027         {
06028                 // We're changing the asset id, so we both need to set it
06029                 // locally via setAssetUUID() and via setTransactionID() which
06030                 // will be decoded on the server. JC
06031                 item->setAssetUUID(wearable->getID());
06032                 item->setTransactionID(wearable->getTransactionID());
06033                 gInventory.addChangedMask(LLInventoryObserver::INTERNAL, item_id);
06034                 item->updateServer(FALSE);
06035         }
06036         gInventory.notifyObservers();
06037 }
06038 
06039 void LLAgent::sendAgentWearablesUpdate()
06040 {
06041         // First make sure that we have inventory items for each wearable
06042         S32 i;
06043         for(i=0; i < WT_COUNT; ++i)
06044         {
06045                 LLWearable* wearable = mWearableEntry[ i ].mWearable;
06046                 if (wearable)
06047                 {
06048                         if( mWearableEntry[ i ].mItemID.isNull() )
06049                         {
06050                                 LLPointer<LLInventoryCallback> cb =
06051                                         new addWearableToAgentInventoryCallback(
06052                                                 LLPointer<LLRefCount>(NULL),
06053                                                 i,
06054                                                 wearable,
06055                                                 addWearableToAgentInventoryCallback::CALL_NONE);
06056                                 addWearableToAgentInventory(cb, wearable);
06057                         }
06058                         else
06059                         {
06060                                 gInventory.addChangedMask( LLInventoryObserver::LABEL,
06061                                                 mWearableEntry[i].mItemID );
06062                         }
06063                 }
06064         }
06065 
06066         // Then make sure the inventory is in sync with the avatar.
06067         gInventory.notifyObservers();
06068 
06069         // Send the AgentIsNowWearing 
06070         gMessageSystem->newMessageFast(_PREHASH_AgentIsNowWearing);
06071 
06072         gMessageSystem->nextBlockFast(_PREHASH_AgentData);
06073         gMessageSystem->addUUIDFast(_PREHASH_AgentID, getID());
06074         gMessageSystem->addUUIDFast(_PREHASH_SessionID, getSessionID());
06075 
06076         lldebugs << "sendAgentWearablesUpdate()" << llendl;
06077         for(i=0; i < WT_COUNT; ++i)
06078         {
06079                 gMessageSystem->nextBlockFast(_PREHASH_WearableData);
06080 
06081                 U8 type_u8 = (U8)i;
06082                 gMessageSystem->addU8Fast(_PREHASH_WearableType, type_u8 );
06083 
06084                 LLWearable* wearable = mWearableEntry[ i ].mWearable;
06085                 if( wearable )
06086                 {
06087                         //llinfos << "Sending wearable " << wearable->getName() << llendl;
06088                         gMessageSystem->addUUIDFast(_PREHASH_ItemID, mWearableEntry[ i ].mItemID );
06089                 }
06090                 else
06091                 {
06092                         //llinfos << "Not wearing wearable type " << LLWearable::typeToTypeName((EWearableType)i) << llendl;
06093                         gMessageSystem->addUUIDFast(_PREHASH_ItemID, LLUUID::null );
06094                 }
06095 
06096                 lldebugs << "       " << LLWearable::typeToTypeLabel((EWearableType)i) << ": " << (wearable ? wearable->getID() : LLUUID::null) << llendl;
06097         }
06098         gAgent.sendReliableMessage();
06099 }
06100 
06101 void LLAgent::saveWearable( EWearableType type, BOOL send_update )
06102 {
06103         LLWearable* old_wearable = mWearableEntry[(S32)type].mWearable;
06104         if( old_wearable && (old_wearable->isDirty() || old_wearable->isOldVersion()) )
06105         {
06106                 LLWearable* new_wearable = gWearableList.createCopyFromAvatar( old_wearable );
06107                 mWearableEntry[(S32)type].mWearable = new_wearable;
06108 
06109                 LLInventoryItem* item = gInventory.getItem(mWearableEntry[(S32)type].mItemID);
06110                 if( item )
06111                 {
06112                         // Update existing inventory item
06113                         LLPointer<LLViewerInventoryItem> template_item =
06114                                 new LLViewerInventoryItem(item->getUUID(),
06115                                                                                   item->getParentUUID(),
06116                                                                                   item->getPermissions(),
06117                                                                                   new_wearable->getID(),
06118                                                                                   new_wearable->getAssetType(),
06119                                                                                   item->getInventoryType(),
06120                                                                                   item->getName(),
06121                                                                                   item->getDescription(),
06122                                                                                   item->getSaleInfo(),
06123                                                                                   item->getFlags(),
06124                                                                                   item->getCreationDate());
06125                         template_item->setTransactionID(new_wearable->getTransactionID());
06126                         template_item->updateServer(FALSE);
06127                         gInventory.updateItem(template_item);
06128                 }
06129                 else
06130                 {
06131                         // Add a new inventory item (shouldn't ever happen here)
06132                         U32 todo = addWearableToAgentInventoryCallback::CALL_NONE;
06133                         if (send_update)
06134                         {
06135                                 todo |= addWearableToAgentInventoryCallback::CALL_UPDATE;
06136                         }
06137                         LLPointer<LLInventoryCallback> cb =
06138                                 new addWearableToAgentInventoryCallback(
06139                                         LLPointer<LLRefCount>(NULL),
06140                                         (S32)type,
06141                                         new_wearable,
06142                                         todo);
06143                         addWearableToAgentInventory(cb, new_wearable);
06144                         return;
06145                 }
06146 
06147                 if( send_update )
06148                 {
06149                         sendAgentWearablesUpdate();
06150                 }
06151         }
06152 }
06153 
06154 void LLAgent::saveWearableAs(
06155         EWearableType type,
06156         const std::string& new_name,
06157         BOOL save_in_lost_and_found)
06158 {
06159         if(!isWearableCopyable(type))
06160         {
06161                 llwarns << "LLAgent::saveWearableAs() not copyable." << llendl;
06162                 return;
06163         }
06164         LLWearable* old_wearable = getWearable(type);
06165         if(!old_wearable)
06166         {
06167                 llwarns << "LLAgent::saveWearableAs() no old wearable." << llendl;
06168                 return;
06169         }
06170         LLInventoryItem* item = gInventory.getItem(mWearableEntry[type].mItemID);
06171         if(!item)
06172         {
06173                 llwarns << "LLAgent::saveWearableAs() no inventory item." << llendl;
06174                 return;
06175         }
06176         std::string trunc_name(new_name);
06177         LLString::truncate(trunc_name, DB_INV_ITEM_NAME_STR_LEN);
06178         LLWearable* new_wearable = gWearableList.createCopyFromAvatar(
06179                 old_wearable,
06180                 trunc_name);
06181         LLPointer<LLInventoryCallback> cb =
06182                 new addWearableToAgentInventoryCallback(
06183                         LLPointer<LLRefCount>(NULL),
06184                         type,
06185                         new_wearable,
06186                         addWearableToAgentInventoryCallback::CALL_UPDATE);
06187         LLUUID category_id;
06188         if (save_in_lost_and_found)
06189         {
06190                 category_id = gInventory.findCategoryUUIDForType(
06191                         LLAssetType::AT_LOST_AND_FOUND);
06192         }
06193         else
06194         {
06195                 // put in same folder as original
06196                 category_id = item->getParentUUID();
06197         }
06198 
06199         copy_inventory_item(
06200                 gAgent.getID(),
06201                 item->getPermissions().getOwner(),
06202                 item->getUUID(),
06203                 category_id,
06204                 new_name,
06205                 cb);
06206 
06207 /*
06208         LLWearable* old_wearable = getWearable( type );
06209         if( old_wearable )
06210         {
06211                 LLString old_name = old_wearable->getName();
06212                 old_wearable->setName( new_name );
06213                 LLWearable* new_wearable = gWearableList.createCopyFromAvatar( old_wearable );
06214                 old_wearable->setName( old_name );
06215                         
06216                 LLUUID category_id;
06217                 LLInventoryItem* item = gInventory.getItem( mWearableEntry[ type ].mItemID );
06218                 if( item )
06219                 {
06220                         new_wearable->setPermissions(item->getPermissions());
06221                         if (save_in_lost_and_found)
06222                         {
06223                                 category_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_LOST_AND_FOUND);
06224                         }
06225                         else
06226                         {
06227                                 // put in same folder as original
06228                                 category_id = item->getParentUUID();
06229                         }
06230                         LLInventoryView* view = LLInventoryView::getActiveInventory();
06231                         if(view)
06232                         {
06233                                 view->getPanel()->setSelection(item->getUUID(), TAKE_FOCUS_NO);
06234                         }
06235                 }
06236 
06237                 mWearableEntry[ type ].mWearable = new_wearable;
06238                 LLPointer<LLInventoryCallback> cb =
06239                         new addWearableToAgentInventoryCallback(
06240                                 LLPointer<LLRefCount>(NULL),
06241                                 type,
06242                                 addWearableToAgentInventoryCallback::CALL_UPDATE);
06243                 addWearableToAgentInventory(cb, new_wearable, category_id);
06244         }
06245 */
06246 }
06247 
06248 void LLAgent::revertWearable( EWearableType type )
06249 {
06250         LLWearable* wearable = mWearableEntry[(S32)type].mWearable;
06251         if( wearable )
06252         {
06253                 wearable->writeToAvatar( TRUE );
06254         }
06255         sendAgentSetAppearance();
06256 }
06257 
06258 void LLAgent::revertAllWearables()
06259 {
06260         for( S32 i=0; i < WT_COUNT; i++ )
06261         {
06262                 revertWearable( (EWearableType)i );
06263         }
06264 }
06265 
06266 void LLAgent::saveAllWearables()
06267 {
06268         //if(!gInventory.isLoaded())
06269         //{
06270         //      return;
06271         //}
06272 
06273         for( S32 i=0; i < WT_COUNT; i++ )
06274         {
06275                 saveWearable( (EWearableType)i, FALSE );
06276         }
06277         sendAgentWearablesUpdate();
06278 }
06279 
06280 // Called when the user changes the name of a wearable inventory item that is currenlty being worn.
06281 void LLAgent::setWearableName( const LLUUID& item_id, const std::string& new_name )
06282 {
06283         for( S32 i=0; i < WT_COUNT; i++ )
06284         {
06285                 if( mWearableEntry[i].mItemID == item_id )
06286                 {
06287                         LLWearable* old_wearable = mWearableEntry[i].mWearable;
06288                         llassert( old_wearable );
06289 
06290                         LLString old_name = old_wearable->getName();
06291                         old_wearable->setName( new_name );
06292                         LLWearable* new_wearable = gWearableList.createCopy( old_wearable );
06293                         LLInventoryItem* item = gInventory.getItem(item_id);
06294                         if(item)
06295                         {
06296                                 new_wearable->setPermissions(item->getPermissions());
06297                         }
06298                         old_wearable->setName( old_name );
06299 
06300                         mWearableEntry[i].mWearable = new_wearable;
06301                         sendAgentWearablesUpdate();
06302                         break;
06303                 }
06304         }
06305 }
06306 
06307 
06308 BOOL LLAgent::isWearableModifiable(EWearableType type)
06309 {
06310         LLUUID item_id = getWearableItem(type);
06311         if(!item_id.isNull())
06312         {
06313                 LLInventoryItem* item = gInventory.getItem(item_id);
06314                 if(item && item->getPermissions().allowModifyBy(gAgent.getID(),
06315                                                                                                                 gAgent.getGroupID()))
06316                 {
06317                         return TRUE;
06318                 }
06319         }
06320         return FALSE;
06321 }
06322 
06323 BOOL LLAgent::isWearableCopyable(EWearableType type)
06324 {
06325         LLUUID item_id = getWearableItem(type);
06326         if(!item_id.isNull())
06327         {
06328                 LLInventoryItem* item = gInventory.getItem(item_id);
06329                 if(item && item->getPermissions().allowCopyBy(gAgent.getID(),
06330                                                                                                           gAgent.getGroupID()))
06331                 {
06332                         return TRUE;
06333                 }
06334         }
06335         return FALSE;
06336 }
06337 
06338 U32 LLAgent::getWearablePermMask(EWearableType type)
06339 {
06340         LLUUID item_id = getWearableItem(type);
06341         if(!item_id.isNull())
06342         {
06343                 LLInventoryItem* item = gInventory.getItem(item_id);
06344                 if(item)
06345                 {
06346                         return item->getPermissions().getMaskOwner();
06347                 }
06348         }
06349         return PERM_NONE;
06350 }
06351 
06352 LLInventoryItem* LLAgent::getWearableInventoryItem(EWearableType type)
06353 {
06354         LLUUID item_id = getWearableItem(type);
06355         LLInventoryItem* item = NULL;
06356         if(item_id.notNull())
06357         {
06358                  item = gInventory.getItem(item_id);
06359         }
06360         return item;
06361 }
06362 
06363 LLWearable* LLAgent::getWearableFromWearableItem( const LLUUID& item_id )
06364 {
06365         for( S32 i=0; i < WT_COUNT; i++ )
06366         {
06367                 if( mWearableEntry[i].mItemID == item_id )
06368                 {
06369                         return mWearableEntry[i].mWearable;
06370                 }
06371         }
06372         return NULL;
06373 }
06374 
06375 
06376 void LLAgent::sendAgentWearablesRequest()
06377 {
06378         gMessageSystem->newMessageFast(_PREHASH_AgentWearablesRequest);
06379         gMessageSystem->nextBlockFast(_PREHASH_AgentData);
06380         gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
06381         gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID() );
06382         sendReliableMessage();
06383 }
06384 
06385 // Used to enable/disable menu items.
06386 // static
06387 BOOL LLAgent::selfHasWearable( void* userdata )
06388 {
06389         EWearableType type = (EWearableType)(intptr_t)userdata;
06390         return gAgent.getWearable( type ) != NULL;
06391 }
06392 
06393 BOOL LLAgent::isWearingItem( const LLUUID& item_id )
06394 {
06395         return (getWearableFromWearableItem( item_id ) != NULL);
06396 }
06397 
06398 
06399 // static
06400 void LLAgent::processAgentInitialWearablesUpdate( LLMessageSystem* mesgsys, void** user_data )
06401 {
06402         // We should only receive this message a single time.  Ignore subsequent AgentWearablesUpdates
06403         // that may result from AgentWearablesRequest having been sent more than once. 
06404         static BOOL first = TRUE;
06405         if( first )
06406         {
06407                 first = FALSE;
06408         }
06409         else
06410         {
06411                 return;
06412         }
06413         
06414         if (gNoRender)
06415         {
06416                 return;
06417         }
06418 
06419         LLUUID agent_id;
06420         gMessageSystem->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id );
06421 
06422         LLVOAvatar* avatar = gAgent.getAvatarObject();
06423         if( avatar && (agent_id == avatar->getID()) )
06424         {
06425                 gMessageSystem->getU32Fast(_PREHASH_AgentData, _PREHASH_SerialNum, gAgent.mAgentWearablesUpdateSerialNum );
06426                 
06427                 S32 num_wearables = gMessageSystem->getNumberOfBlocksFast(_PREHASH_WearableData);
06428                 if( num_wearables < 4 )
06429                 {
06430                         // Transitional state.  Avatars should always have at least their body parts (hair, eyes, shape and skin).
06431                         // The fact that they don't have any here (only a dummy is sent) implies that this account existed
06432                         // before we had wearables, or that the database has gotten messed up.
06433                         // Deal with this by creating new body parts.
06434                         //avatar->createStandardWearables();
06435 
06436                         // no, deal with it by noting that we need to choose a
06437                         // gender.
06438                         gAgent.setGenderChosen(FALSE);
06439                         return;
06440                 }
06441 
06442                 //lldebugs << "processAgentInitialWearablesUpdate()" << llendl;
06443                 // Add wearables
06444                 LLUUID asset_id_array[ WT_COUNT ];
06445                 S32 i;
06446                 for( i=0; i < num_wearables; i++ )
06447                 {
06448                         U8 type_u8 = 0;
06449                         gMessageSystem->getU8Fast(_PREHASH_WearableData, _PREHASH_WearableType, type_u8, i );
06450                         if( type_u8 >= WT_COUNT )
06451                         {
06452                                 continue;
06453                         }
06454                         EWearableType type = (EWearableType) type_u8;
06455 
06456                         LLUUID item_id;
06457                         gMessageSystem->getUUIDFast(_PREHASH_WearableData, _PREHASH_ItemID, item_id, i );
06458 
06459                         LLUUID asset_id;
06460                         gMessageSystem->getUUIDFast(_PREHASH_WearableData, _PREHASH_AssetID, asset_id, i );
06461                         if( asset_id.isNull() )
06462                         {
06463                                 LLWearable::removeFromAvatar( type, FALSE );
06464                         }
06465                         else
06466                         {
06467                                 LLAssetType::EType asset_type = LLWearable::typeToAssetType( type );
06468                                 if( asset_type == LLAssetType::AT_NONE )
06469                                 {
06470                                         continue;
06471                                 }
06472 
06473                                 gAgent.mWearableEntry[type].mItemID = item_id;
06474                                 asset_id_array[type] = asset_id;
06475                         }
06476 
06477                         lldebugs << "       " << LLWearable::typeToTypeLabel(type) << llendl;
06478                 }
06479 
06480                 // now that we have the asset ids...request the wearable assets
06481                 for( i = 0; i < WT_COUNT; i++ )
06482                 {
06483                         if( !gAgent.mWearableEntry[i].mItemID.isNull() )
06484                         {
06485                                 gWearableList.getAsset( 
06486                                         asset_id_array[i],
06487                                         LLString::null,
06488                                         LLWearable::typeToAssetType( (EWearableType) i ), 
06489                                         LLAgent::onInitialWearableAssetArrived, (void*)(intptr_t)i );
06490                         }
06491                 }
06492         }
06493 }
06494 
06495 // A single wearable that the avatar was wearing on start-up has arrived from the database.
06496 // static
06497 void LLAgent::onInitialWearableAssetArrived( LLWearable* wearable, void* userdata )
06498 {
06499         EWearableType type = (EWearableType)(intptr_t)userdata;
06500 
06501         LLVOAvatar* avatar = gAgent.getAvatarObject();
06502         if( !avatar )
06503         {
06504                 return;
06505         }
06506 
06507         if( wearable )
06508         {
06509                 llassert( type == wearable->getType() );
06510                 gAgent.mWearableEntry[ type ].mWearable = wearable;
06511 
06512                 // disable composites if initial textures are baked
06513                 avatar->setupComposites();
06514                 gAgent.queryWearableCache();
06515 
06516                 wearable->writeToAvatar( FALSE );
06517                 avatar->setCompositeUpdatesEnabled(TRUE);
06518                 gInventory.addChangedMask( LLInventoryObserver::LABEL, gAgent.mWearableEntry[type].mItemID );
06519         }
06520         else
06521         {
06522                 // Somehow the asset doesn't exist in the database.
06523                 gAgent.recoverMissingWearable( type );
06524         }
06525 
06526         gInventory.notifyObservers();
06527 
06528         // Have all the wearables that the avatar was wearing at log-in arrived?
06529         if( !gAgent.mWearablesLoaded )
06530         {
06531                 gAgent.mWearablesLoaded = TRUE;
06532                 for( S32 i = 0; i < WT_COUNT; i++ )
06533                 {
06534                         if( !gAgent.mWearableEntry[i].mItemID.isNull() && !gAgent.mWearableEntry[i].mWearable )
06535                         {
06536                                 gAgent.mWearablesLoaded = FALSE;
06537                                 break;
06538                         }
06539                 }
06540         }
06541 
06542         if( gAgent.mWearablesLoaded )
06543         {
06544                 // Make sure that the server's idea of the avatar's wearables actually match the wearables.
06545                 gAgent.sendAgentSetAppearance();
06546 
06547                 // Check to see if there are any baked textures that we hadn't uploaded before we logged off last time.
06548                 // If there are any, schedule them to be uploaded as soon as the layer textures they depend on arrive.
06549                 if( !gAgent.cameraCustomizeAvatar() )
06550                 {
06551                         avatar->requestLayerSetUploads();
06552                 }
06553         }
06554 }
06555 
06556 // Normally, all wearables referred to "AgentWearablesUpdate" will correspond to actual assets in the
06557 // database.  If for some reason, we can't load one of those assets, we can try to reconstruct it so that
06558 // the user isn't left without a shape, for example.  (We can do that only after the inventory has loaded.)
06559 void LLAgent::recoverMissingWearable( EWearableType type )
06560 {
06561         // Try to recover by replacing missing wearable with a new one.
06562         LLNotifyBox::showXml("ReplacedMissingWearable");
06563         lldebugs << "Wearable " << LLWearable::typeToTypeLabel( type ) << " could not be downloaded.  Replaced inventory item with default wearable." << llendl;
06564         LLWearable* new_wearable = gWearableList.createNewWearable(type);
06565 
06566         S32 type_s32 = (S32) type;
06567         mWearableEntry[type_s32].mWearable = new_wearable;
06568         new_wearable->writeToAvatar( TRUE );
06569 
06570         // Add a new one in the lost and found folder.
06571         // (We used to overwrite the "not found" one, but that could potentially
06572         // destory content.) JC
06573         LLUUID lost_and_found_id = 
06574                 gInventory.findCategoryUUIDForType(LLAssetType::AT_LOST_AND_FOUND);
06575         LLPointer<LLInventoryCallback> cb =
06576                 new addWearableToAgentInventoryCallback(
06577                         LLPointer<LLRefCount>(NULL),
06578                         type_s32,
06579                         new_wearable,
06580                         addWearableToAgentInventoryCallback::CALL_RECOVERDONE);
06581         addWearableToAgentInventory( cb, new_wearable, lost_and_found_id, TRUE);
06582 }
06583 
06584 void LLAgent::recoverMissingWearableDone()
06585 {
06586         // Have all the wearables that the avatar was wearing at log-in arrived or been fabricated?
06587         mWearablesLoaded = TRUE;
06588         for( S32 i = 0; i < WT_COUNT; i++ )
06589         {
06590                 if( !mWearableEntry[i].mItemID.isNull() && !mWearableEntry[i].mWearable )
06591                 {
06592                         mWearablesLoaded = FALSE;
06593                         break;
06594                 }
06595         }
06596 
06597         if( mWearablesLoaded )
06598         {
06599                 // Make sure that the server's idea of the avatar's wearables actually match the wearables.
06600                 sendAgentSetAppearance();
06601         }
06602         else
06603         {
06604                 gInventory.addChangedMask( LLInventoryObserver::LABEL, LLUUID::null );
06605                 gInventory.notifyObservers();
06606         }
06607 }
06608 
06609 void LLAgent::createStandardWearables(BOOL female)
06610 {
06611         llwarns << "Creating Standard " << (female ? "female" : "male" )
06612                         << " Wearables" << llendl;
06613 
06614         if (mAvatarObject.isNull())
06615         {
06616                 return;
06617         }
06618 
06619         if(female) mAvatarObject->setSex(SEX_FEMALE);
06620         else mAvatarObject->setSex(SEX_MALE);
06621 
06622         BOOL create[WT_COUNT] = 
06623         {
06624                 TRUE,  //WT_SHAPE
06625                 TRUE,  //WT_SKIN
06626                 TRUE,  //WT_HAIR
06627                 TRUE,  //WT_EYES
06628                 TRUE,  //WT_SHIRT
06629                 TRUE,  //WT_PANTS
06630                 TRUE,  //WT_SHOES
06631                 TRUE,  //WT_SOCKS
06632                 FALSE, //WT_JACKET
06633                 FALSE, //WT_GLOVES
06634                 TRUE,  //WT_UNDERSHIRT
06635                 TRUE,  //WT_UNDERPANTS
06636                 FALSE  //WT_SKIRT
06637         };
06638 
06639         for( S32 i=0; i < WT_COUNT; i++ )
06640         {
06641                 bool once = false;
06642                 LLPointer<LLRefCount> donecb = NULL;
06643                 if( create[i] )
06644                 {
06645                         if (!once)
06646                         {
06647                                 once = true;
06648                                 donecb = new createStandardWearablesAllDoneCallback;
06649                         }
06650                         llassert( mWearableEntry[i].mWearable == NULL );
06651                         LLWearable* wearable = gWearableList.createNewWearable((EWearableType)i);
06652                         mWearableEntry[i].mWearable = wearable;
06653                         // no need to update here...
06654                         LLPointer<LLInventoryCallback> cb =
06655                                 new addWearableToAgentInventoryCallback(
06656                                         donecb,
06657                                         i,
06658                                         wearable,
06659                                         addWearableToAgentInventoryCallback::CALL_CREATESTANDARDDONE);
06660                         addWearableToAgentInventory(cb, wearable, LLUUID::null, FALSE);
06661                 }
06662         }
06663 }
06664 void LLAgent::createStandardWearablesDone(S32 index)
06665 {
06666         LLWearable* wearable = mWearableEntry[index].mWearable;
06667 
06668         if (wearable)
06669         {
06670                 wearable->writeToAvatar(TRUE);
06671         }
06672 }
06673 
06674 void LLAgent::createStandardWearablesAllDone()
06675 {
06676         // ... because sendAgentWearablesUpdate will notify inventory
06677         // observers.
06678         mWearablesLoaded = TRUE; 
06679         sendAgentWearablesUpdate();
06680         sendAgentSetAppearance();
06681 
06682         // Treat this as the first texture entry message, if none received yet
06683         mAvatarObject->onFirstTEMessageReceived();
06684 }
06685 
06686 void LLAgent::makeNewOutfit( 
06687         const std::string& new_folder_name,
06688         const LLDynamicArray<S32>& wearables_to_include,
06689         const LLDynamicArray<S32>& attachments_to_include,
06690         BOOL rename_clothing)
06691 {
06692         if (mAvatarObject.isNull())
06693         {
06694                 return;
06695         }
06696 
06697         // First, make a folder in the Clothes directory.
06698         LLUUID folder_id = gInventory.createNewCategory(
06699                 gInventory.findCategoryUUIDForType(LLAssetType::AT_CLOTHING),
06700                 LLAssetType::AT_NONE,
06701                 new_folder_name);
06702 
06703         bool found_first_item = false;
06704 
06706         // Wearables
06707 
06708         if( wearables_to_include.count() )
06709         {
06710                 // Then, iterate though each of the wearables and save copies of them in the folder.
06711                 S32 i;
06712                 S32 count = wearables_to_include.count();
06713                 LLDynamicArray<LLUUID> delete_items;
06714                 LLPointer<LLRefCount> cbdone = NULL;
06715                 for( i = 0; i < count; ++i )
06716                 {
06717                         S32 index = wearables_to_include[i];
06718                         LLWearable* old_wearable = mWearableEntry[ index ].mWearable;
06719                         if( old_wearable )
06720                         {
06721                                 std::string new_name;
06722                                 LLWearable* new_wearable;
06723                                 new_wearable = gWearableList.createCopy(old_wearable);
06724                                 if (rename_clothing)
06725                                 {
06726                                         new_name = new_folder_name;
06727                                         new_name.append(" ");
06728                                         new_name.append(old_wearable->getTypeLabel());
06729                                         LLString::truncate(new_name, DB_INV_ITEM_NAME_STR_LEN);
06730                                         new_wearable->setName(new_name);
06731                                 }
06732 
06733                                 LLViewerInventoryItem* item = gInventory.getItem(mWearableEntry[index].mItemID);
06734                                 S32 todo = addWearableToAgentInventoryCallback::CALL_NONE;
06735                                 if (!found_first_item)
06736                                 {
06737                                         found_first_item = true;
06738                                         /* set the focus to the first item */
06739                                         todo |= addWearableToAgentInventoryCallback::CALL_MAKENEWOUTFITDONE;
06740                                         /* send the agent wearables update when done */
06741                                         cbdone = new sendAgentWearablesUpdateCallback;
06742                                 }
06743                                 LLPointer<LLInventoryCallback> cb =
06744                                         new addWearableToAgentInventoryCallback(
06745                                                 cbdone,
06746                                                 index,
06747                                                 new_wearable,
06748                                                 todo);
06749                                 if (isWearableCopyable((EWearableType)index))
06750                                 {
06751                                         copy_inventory_item(
06752                                                 gAgent.getID(),
06753                                                 item->getPermissions().getOwner(),
06754                                                 item->getUUID(),
06755                                                 folder_id,
06756                                                 new_name,
06757                                                 cb);
06758                                 }
06759                                 else
06760                                 {
06761                                         move_inventory_item(
06762                                                 gAgent.getID(),
06763                                                 gAgent.getSessionID(),
06764                                                 item->getUUID(),
06765                                                 folder_id,
06766                                                 new_name,
06767                                                 cb);
06768                                 }
06769                         }
06770                 }
06771                 gInventory.notifyObservers();
06772         }
06773 
06774 
06776         // Attachments
06777 
06778         if( attachments_to_include.count() )
06779         {
06780                 BOOL msg_started = FALSE;
06781                 LLMessageSystem* msg = gMessageSystem;
06782                 S32 i;
06783                 for( i = 0; i < attachments_to_include.count(); i++ )
06784                 {
06785                         S32 attachment_pt = attachments_to_include[i];
06786                         LLViewerJointAttachment* attachment = mAvatarObject->mAttachmentPoints.getIfThere( attachment_pt );
06787                         if(!attachment) continue;
06788                         LLViewerObject* attached_object = attachment->getObject();
06789                         if(!attached_object) continue;
06790                         const LLUUID& item_id = attachment->getItemID();
06791                         if(item_id.isNull()) continue;
06792                         LLInventoryItem* item = gInventory.getItem(item_id);
06793                         if(!item) continue;
06794                         if(!msg_started)
06795                         {
06796                                 msg_started = TRUE;
06797                                 msg->newMessage("CreateNewOutfitAttachments");
06798                                 msg->nextBlock("AgentData");
06799                                 msg->addUUID("AgentID", getID());
06800                                 msg->addUUID("SessionID", getSessionID());
06801                                 msg->nextBlock("HeaderData");
06802                                 msg->addUUID("NewFolderID", folder_id);
06803                         }
06804                         msg->nextBlock("ObjectData");
06805                         msg->addUUID("OldItemID", item_id);
06806                         msg->addUUID("OldFolderID", item->getParentUUID());
06807                 }
06808 
06809                 if( msg_started )
06810                 {
06811                         sendReliableMessage();
06812                 }
06813 
06814         } 
06815 }
06816 
06817 void LLAgent::makeNewOutfitDone(S32 index)
06818 {
06819         LLUUID first_item_id = mWearableEntry[index].mItemID;
06820         // Open the inventory and select the first item we added.
06821         if( first_item_id.notNull() )
06822         {
06823                 LLInventoryView* view = LLInventoryView::getActiveInventory();
06824                 if(view)
06825                 {
06826                         view->getPanel()->setSelection(first_item_id, TAKE_FOCUS_NO);
06827                 }
06828         }
06829 }
06830 
06831 
06832 void LLAgent::addWearableToAgentInventory(
06833         LLPointer<LLInventoryCallback> cb,
06834         LLWearable* wearable,
06835         const LLUUID& category_id,
06836         BOOL notify)
06837 {
06838         create_inventory_item(
06839                 gAgent.getID(),
06840                 gAgent.getSessionID(),
06841                 category_id,
06842                 wearable->getTransactionID(),
06843                 wearable->getName(),
06844                 wearable->getDescription(),
06845                 wearable->getAssetType(),
06846                 LLInventoryType::IT_WEARABLE,
06847                 wearable->getType(),
06848                 wearable->getPermissions().getMaskNextOwner(),
06849                 cb);
06850 }
06851 
06852 //-----------------------------------------------------------------------------
06853 // sendAgentSetAppearance()
06854 //-----------------------------------------------------------------------------
06855 void LLAgent::sendAgentSetAppearance()
06856 {
06857         if (mAvatarObject.isNull()) return;
06858 
06859         if (mNumPendingQueries > 0 && !gAgent.cameraCustomizeAvatar()) 
06860         {
06861                 return;
06862         }
06863 
06864         llinfos << "TAT: Sent AgentSetAppearance: " <<
06865                 (( mAvatarObject->getTEImage( LLVOAvatar::TEX_HEAD_BAKED )->getID() != IMG_DEFAULT_AVATAR )  ? "HEAD " : "head " ) <<
06866                 (( mAvatarObject->getTEImage( LLVOAvatar::TEX_UPPER_BAKED )->getID() != IMG_DEFAULT_AVATAR ) ? "UPPER " : "upper " ) <<
06867                 (( mAvatarObject->getTEImage( LLVOAvatar::TEX_LOWER_BAKED )->getID() != IMG_DEFAULT_AVATAR ) ? "LOWER " : "lower " ) <<
06868                 (( mAvatarObject->getTEImage( LLVOAvatar::TEX_EYES_BAKED )->getID() != IMG_DEFAULT_AVATAR )  ? "EYES" : "eyes" ) << llendl;
06869         //dumpAvatarTEs( "sendAgentSetAppearance()" );
06870 
06871         LLMessageSystem* msg = gMessageSystem;
06872         msg->newMessageFast(_PREHASH_AgentSetAppearance);
06873         msg->nextBlockFast(_PREHASH_AgentData);
06874         msg->addUUIDFast(_PREHASH_AgentID, getID());
06875         msg->addUUIDFast(_PREHASH_SessionID, getSessionID());
06876 
06877         // correct for the collisiton tolerance (to make it look like the 
06878         // agent is actually walking on the ground/object)
06879         // NOTE -- when we start correcting all of the other Havok geometry 
06880         // to compensate for the COLLISION_TOLERANCE ugliness we will have 
06881         // to tweak this number again
06882         LLVector3 body_size = mAvatarObject->mBodySize;
06883         msg->addVector3Fast(_PREHASH_Size, body_size);  
06884 
06885         // To guard against out of order packets
06886         // Note: always start by sending 1.  This resets the server's count. 0 on the server means "uninitialized"
06887         mAppearanceSerialNum++;
06888         msg->addU32Fast(_PREHASH_SerialNum, mAppearanceSerialNum );
06889 
06890         // is texture data current relative to wearables?
06891         // KLW - TAT this will probably need to check the local queue.
06892         BOOL textures_current = !mAvatarObject->hasPendingBakedUploads() && mWearablesLoaded;
06893 
06894         S32 baked_texture_index;
06895         for( baked_texture_index = 0; baked_texture_index < BAKED_TEXTURE_COUNT; baked_texture_index++ )
06896         {
06897                 S32 tex_index = LLVOAvatar::sBakedTextureIndices[baked_texture_index];
06898 
06899                 // if we're not wearing a skirt, we don't need the texture to be baked
06900                 if (tex_index == LLVOAvatar::TEX_SKIRT_BAKED && !mAvatarObject->isWearingWearableType(WT_SKIRT))
06901                 {
06902                         continue;
06903                 }
06904 
06905                 // IMG_DEFAULT_AVATAR means not baked
06906                 if (mAvatarObject->getTEImage( tex_index)->getID() == IMG_DEFAULT_AVATAR)
06907                 {
06908                         textures_current = FALSE;
06909                         break;
06910                 }
06911         }
06912 
06913         // only update cache entries if we have all our baked textures
06914         if (textures_current)
06915         {
06916                 llinfos << "TAT: Sending cached texture data" << llendl;
06917                 for (baked_texture_index = 0; baked_texture_index < BAKED_TEXTURE_COUNT; baked_texture_index++)
06918                 {
06919                         LLUUID hash;
06920 
06921                         for( S32 wearable_num = 0; wearable_num < MAX_WEARABLES_PER_LAYERSET; wearable_num++ )
06922                         {
06923                                 EWearableType wearable_type = WEARABLE_BAKE_TEXTURE_MAP[baked_texture_index][wearable_num];
06924 
06925                                 LLWearable* wearable = getWearable( wearable_type );
06926                                 if (wearable)
06927                                 {
06928                                         hash ^= wearable->getID();
06929                                 }
06930                         }
06931 
06932                         if (hash.notNull())
06933                         {
06934                                 hash ^= BAKED_TEXTURE_HASH[baked_texture_index];
06935                         }
06936 
06937                         S32 tex_index = LLVOAvatar::sBakedTextureIndices[baked_texture_index];
06938 
06939                         msg->nextBlockFast(_PREHASH_WearableData);
06940                         msg->addUUIDFast(_PREHASH_CacheID, hash);
06941                         msg->addU8Fast(_PREHASH_TextureIndex, (U8)tex_index);
06942                 }
06943         }
06944 
06945         msg->nextBlockFast(_PREHASH_ObjectData);
06946         mAvatarObject->packTEMessage( gMessageSystem );
06947 
06948         S32 transmitted_params = 0;
06949         for (LLViewerVisualParam* param = (LLViewerVisualParam*)mAvatarObject->getFirstVisualParam();
06950                  param;
06951                  param = (LLViewerVisualParam*)mAvatarObject->getNextVisualParam())
06952         {
06953                 F32 param_value = param->getWeight();
06954         
06955                 if (param->getGroup() == VISUAL_PARAM_GROUP_TWEAKABLE)
06956                 {
06957                         msg->nextBlockFast(_PREHASH_VisualParam );
06958                         
06959                         // We don't send the param ids.  Instead, we assume that the receiver has the same params in the same sequence.
06960                         U8 new_weight = F32_to_U8(param_value, param->getMinWeight(), param->getMaxWeight());
06961                         msg->addU8Fast(_PREHASH_ParamValue, new_weight );
06962                         transmitted_params++;
06963                 }
06964         }
06965 
06966 //      llinfos << "Avatar XML num VisualParams transmitted = " << transmitted_params << llendl;
06967         sendReliableMessage();
06968 }
06969 
06970 void LLAgent::sendAgentDataUpdateRequest()
06971 {
06972         gMessageSystem->newMessageFast(_PREHASH_AgentDataUpdateRequest);
06973         gMessageSystem->nextBlockFast(_PREHASH_AgentData);
06974         gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
06975         gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
06976         sendReliableMessage();
06977 }
06978 
06979 void LLAgent::removeWearable( EWearableType type )
06980 {
06981         LLWearable* old_wearable = mWearableEntry[ type ].mWearable;
06982 
06983         if ( (gAgent.isTeen())
06984                  && (type == WT_UNDERSHIRT || type == WT_UNDERPANTS))
06985         {
06986                 // Can't take off underclothing in simple UI mode or on PG accounts
06987                 return;
06988         }
06989 
06990         if( old_wearable )
06991         {
06992                 if( old_wearable->isDirty() )
06993                 {
06994                         // Bring up view-modal dialog: Save changes? Yes, No, Cancel
06995                         gViewerWindow->alertXml("WearableSave", LLAgent::onRemoveWearableDialog, (void*)type );
06996                         return;
06997                 }
06998                 else
06999                 {
07000                         removeWearableFinal( type );
07001                 }
07002         }
07003 }
07004 
07005 // static 
07006 void LLAgent::onRemoveWearableDialog( S32 option, void* userdata )
07007 {
07008         EWearableType type = (EWearableType)(intptr_t)userdata;
07009         switch( option )
07010         {
07011         case 0:  // "Save"
07012                 gAgent.saveWearable( type );
07013                 gAgent.removeWearableFinal( type );
07014                 break;
07015 
07016         case 1:  // "Don't Save"
07017                 gAgent.removeWearableFinal( type );
07018                 break;
07019 
07020         case 2: // "Cancel"
07021                 break;
07022 
07023         default:
07024                 llassert(0);
07025                 break;
07026         }
07027 }
07028 
07029 // Called by removeWearable() and onRemoveWearableDialog() to actually do the removal.
07030 void LLAgent::removeWearableFinal( EWearableType type )
07031 {
07032         LLWearable* old_wearable = mWearableEntry[ type ].mWearable;
07033 
07034         gInventory.addChangedMask( LLInventoryObserver::LABEL, mWearableEntry[type].mItemID );
07035 
07036         mWearableEntry[ type ].mWearable = NULL;
07037         mWearableEntry[ type ].mItemID.setNull();
07038 
07039         queryWearableCache();
07040 
07041         if( old_wearable )
07042         {
07043                 old_wearable->removeFromAvatar( TRUE );
07044         }
07045 
07046         // Update the server
07047         sendAgentWearablesUpdate(); 
07048         sendAgentSetAppearance();
07049         gInventory.notifyObservers();
07050 }
07051 
07052 void LLAgent::copyWearableToInventory( EWearableType type )
07053 {
07054         LLWearable* wearable = mWearableEntry[ type ].mWearable;
07055         if( wearable )
07056         {
07057                 // Save the old wearable if it has changed.
07058                 if( wearable->isDirty() )
07059                 {
07060                         wearable = gWearableList.createCopyFromAvatar( wearable );
07061                         mWearableEntry[ type ].mWearable = wearable;
07062                 }
07063 
07064                 // Make a new entry in the inventory.  (Put it in the same folder as the original item if possible.)
07065                 LLUUID category_id;
07066                 LLInventoryItem* item = gInventory.getItem( mWearableEntry[ type ].mItemID );
07067                 if( item )
07068                 {
07069                         category_id = item->getParentUUID();
07070                         wearable->setPermissions(item->getPermissions());
07071                 }
07072                 LLPointer<LLInventoryCallback> cb =
07073                         new addWearableToAgentInventoryCallback(
07074                                 LLPointer<LLRefCount>(NULL),
07075                                 type,
07076                                 wearable);
07077                 addWearableToAgentInventory(cb, wearable, category_id);
07078         }
07079 }
07080 
07081 
07082 // A little struct to let setWearable() communicate more than one value with onSetWearableDialog().
07083 struct LLSetWearableData
07084 {
07085         LLSetWearableData( const LLUUID& new_item_id, LLWearable* new_wearable ) :
07086                 mNewItemID( new_item_id ), mNewWearable( new_wearable ) {}
07087         LLUUID                          mNewItemID;
07088         LLWearable*                     mNewWearable;
07089 };
07090 
07091 BOOL LLAgent::needsReplacement(EWearableType  wearableType, S32 remove)
07092 {
07093         return TRUE;
07094         /*if (remove) return TRUE;
07095         
07096         return getWearable(wearableType) ? TRUE : FALSE;*/
07097 }
07098 
07099 // Assumes existing wearables are not dirty.
07100 void LLAgent::setWearableOutfit( 
07101         const LLInventoryItem::item_array_t& items,
07102         const LLDynamicArray< LLWearable* >& wearables,
07103         BOOL remove )
07104 {
07105         lldebugs << "setWearableOutfit() start" << llendl;
07106 
07107         BOOL wearables_to_remove[WT_COUNT];
07108         wearables_to_remove[WT_SHAPE]           = FALSE;
07109         wearables_to_remove[WT_SKIN]            = FALSE;
07110         wearables_to_remove[WT_HAIR]            = FALSE;
07111         wearables_to_remove[WT_EYES]            = FALSE;
07112         wearables_to_remove[WT_SHIRT]           = remove;
07113         wearables_to_remove[WT_PANTS]           = remove;
07114         wearables_to_remove[WT_SHOES]           = remove;
07115         wearables_to_remove[WT_SOCKS]           = remove;
07116         wearables_to_remove[WT_JACKET]          = remove;
07117         wearables_to_remove[WT_GLOVES]          = remove;
07118         wearables_to_remove[WT_UNDERSHIRT]      = (!gAgent.isTeen()) & remove;
07119         wearables_to_remove[WT_UNDERPANTS]      = (!gAgent.isTeen()) & remove;
07120         wearables_to_remove[WT_SKIRT]           = remove;
07121 
07122         S32 count = wearables.count();
07123         llassert( items.count() == count );
07124 
07125         S32 i;
07126         for( i = 0; i < count; i++ )
07127         {
07128                 LLWearable* new_wearable = wearables[i];
07129                 LLPointer<LLInventoryItem> new_item = items[i];
07130 
07131                 EWearableType type = new_wearable->getType();
07132                 wearables_to_remove[type] = FALSE;
07133 
07134                 LLWearable* old_wearable = mWearableEntry[ type ].mWearable;
07135                 if( old_wearable )
07136                 {
07137                         const LLUUID& old_item_id = mWearableEntry[ type ].mItemID;
07138                         if( (old_wearable->getID() == new_wearable->getID()) &&
07139                                 (old_item_id == new_item->getUUID()) )
07140                         {
07141                                 lldebugs << "No change to wearable asset and item: " << LLWearable::typeToTypeName( type ) << llendl;
07142                                 continue;
07143                         }
07144 
07145                         gInventory.addChangedMask(LLInventoryObserver::LABEL, old_item_id);
07146 
07147                         // Assumes existing wearables are not dirty.
07148                         if( old_wearable->isDirty() )
07149                         {
07150                                 llassert(0);
07151                                 continue;
07152                         }
07153                 }
07154 
07155                 mWearableEntry[ type ].mItemID = new_item->getUUID();
07156                 mWearableEntry[ type ].mWearable = new_wearable;
07157         }
07158 
07159         std::vector<LLWearable*> wearables_being_removed;
07160 
07161         for( i = 0; i < WT_COUNT; i++ )
07162         {
07163                 if( wearables_to_remove[i] )
07164                 {
07165                         wearables_being_removed.push_back(mWearableEntry[ i ].mWearable);
07166                         mWearableEntry[ i ].mWearable = NULL;
07167                         
07168                         gInventory.addChangedMask(LLInventoryObserver::LABEL, mWearableEntry[ i ].mItemID);
07169                         mWearableEntry[ i ].mItemID.setNull();
07170                 }
07171         }
07172 
07173         gInventory.notifyObservers();
07174 
07175         queryWearableCache();
07176 
07177         std::vector<LLWearable*>::iterator wearable_iter;
07178 
07179         for( wearable_iter = wearables_being_removed.begin(); 
07180                 wearable_iter != wearables_being_removed.end();
07181                 ++wearable_iter)
07182         {
07183                 LLWearable* wearablep = *wearable_iter;
07184                 if (wearablep)
07185                 {
07186                         wearablep->removeFromAvatar( TRUE );
07187                 }
07188         }
07189 
07190         for( i = 0; i < count; i++ )
07191         {
07192                 wearables[i]->writeToAvatar( TRUE );
07193         }
07194 
07195         LLFloaterCustomize::setCurrentWearableType( WT_SHAPE );
07196 
07197         // Start rendering & update the server
07198         mWearablesLoaded = TRUE; 
07199         sendAgentWearablesUpdate();
07200         sendAgentSetAppearance();
07201 
07202         lldebugs << "setWearableOutfit() end" << llendl;
07203 }
07204 
07205 
07206 // User has picked "wear on avatar" from a menu.
07207 void LLAgent::setWearable( LLInventoryItem* new_item, LLWearable* new_wearable )
07208 {
07209         EWearableType type = new_wearable->getType();
07210 
07211         LLWearable* old_wearable = mWearableEntry[ type ].mWearable;
07212         if( old_wearable )
07213         {
07214                 const LLUUID& old_item_id = mWearableEntry[ type ].mItemID;
07215                 if( (old_wearable->getID() == new_wearable->getID()) &&
07216                         (old_item_id == new_item->getUUID()) )
07217                 {
07218                         lldebugs << "No change to wearable asset and item: " << LLWearable::typeToTypeName( type ) << llendl;
07219                         return;
07220                 }
07221 
07222                 if( old_wearable->isDirty() )
07223                 {
07224                         // Bring up modal dialog: Save changes? Yes, No, Cancel
07225                         gViewerWindow->alertXml( "WearableSave", LLAgent::onSetWearableDialog,
07226                                 new LLSetWearableData( new_item->getUUID(), new_wearable ));
07227                         return;
07228                 }
07229         }
07230 
07231         setWearableFinal( new_item, new_wearable );
07232 }
07233 
07234 // static 
07235 void LLAgent::onSetWearableDialog( S32 option, void* userdata )
07236 {
07237         LLSetWearableData* data = (LLSetWearableData*)userdata;
07238         LLInventoryItem* new_item = gInventory.getItem( data->mNewItemID );
07239         if( !new_item )
07240         {
07241                 delete data;
07242                 return;
07243         }
07244 
07245         switch( option )
07246         {
07247         case 0:  // "Save"
07248                 gAgent.saveWearable( data->mNewWearable->getType() );
07249                 gAgent.setWearableFinal( new_item, data->mNewWearable );
07250                 break;
07251 
07252         case 1:  // "Don't Save"
07253                 gAgent.setWearableFinal( new_item, data->mNewWearable );
07254                 break;
07255 
07256         case 2: // "Cancel"
07257                 break;
07258 
07259         default:
07260                 llassert(0);
07261                 break;
07262         }
07263 
07264         delete data;
07265 }
07266 
07267 // Called from setWearable() and onSetWearableDialog() to actually set the wearable.
07268 void LLAgent::setWearableFinal( LLInventoryItem* new_item, LLWearable* new_wearable )
07269 {
07270         EWearableType type = new_wearable->getType();
07271 
07272         // Replace the old wearable with a new one.
07273         llassert( new_item->getAssetUUID() == new_wearable->getID() );
07274         LLUUID old_item_id = mWearableEntry[ type ].mItemID;
07275         mWearableEntry[ type ].mItemID = new_item->getUUID();
07276         mWearableEntry[ type ].mWearable = new_wearable;
07277 
07278         if (old_item_id.notNull())
07279         {
07280                 gInventory.addChangedMask( LLInventoryObserver::LABEL, old_item_id );
07281                 gInventory.notifyObservers();
07282         }
07283 
07284         //llinfos << "LLVOAvatar::setWearable()" << llendl;
07285         queryWearableCache();
07286         new_wearable->writeToAvatar( TRUE );
07287 
07288         // Update the server
07289         sendAgentWearablesUpdate();
07290         sendAgentSetAppearance();
07291 }
07292 
07293 void LLAgent::queryWearableCache()
07294 {
07295         if (!mWearablesLoaded)
07296         {
07297                 return;
07298         }
07299 
07300         // Look up affected baked textures.
07301         // If they exist:
07302         //              disallow updates for affected layersets (until dataserver responds with cache request.)
07303         //              If cache miss, turn updates back on and invalidate composite.
07304         //              If cache hit, modify baked texture entries.
07305         //
07306         // Cache requests contain list of hashes for each baked texture entry.
07307         // Response is list of valid baked texture assets. (same message)
07308 
07309         gMessageSystem->newMessageFast(_PREHASH_AgentCachedTexture);
07310         gMessageSystem->nextBlockFast(_PREHASH_AgentData);
07311         gMessageSystem->addUUIDFast(_PREHASH_AgentID, getID());
07312         gMessageSystem->addUUIDFast(_PREHASH_SessionID, getSessionID());
07313         gMessageSystem->addS32Fast(_PREHASH_SerialNum, mTextureCacheQueryID);
07314 
07315         S32 num_queries = 0;
07316         for (S32 baked_texture_index = 0; baked_texture_index < BAKED_TEXTURE_COUNT; baked_texture_index++)
07317         {
07318                 LLUUID hash;
07319                 for (S32 wearable_num = 0; wearable_num < MAX_WEARABLES_PER_LAYERSET; wearable_num++)
07320                 {
07321                         EWearableType wearable_type = WEARABLE_BAKE_TEXTURE_MAP[baked_texture_index][wearable_num];
07322                                 
07323                         LLWearable* wearable = getWearable( wearable_type );
07324                         if (wearable)
07325                         {
07326                                 hash ^= wearable->getID();
07327                         }
07328                 }
07329                 if (hash.notNull())
07330                 {
07331                         hash ^= BAKED_TEXTURE_HASH[baked_texture_index];
07332                         num_queries++;
07333                         // *NOTE: make sure at least one request gets packed
07334 
07335                         //llinfos << "Requesting texture for hash " << hash << " in baked texture slot " << baked_texture_index << llendl;
07336                         gMessageSystem->nextBlockFast(_PREHASH_WearableData);
07337                         gMessageSystem->addUUIDFast(_PREHASH_ID, hash);
07338                         gMessageSystem->addU8Fast(_PREHASH_TextureIndex, (U8)baked_texture_index);
07339                 }
07340 
07341                 mActiveCacheQueries[ baked_texture_index ] = mTextureCacheQueryID;
07342         }
07343 
07344         llinfos << "Requesting texture cache entry for " << num_queries << " baked textures" << llendl;
07345         gMessageSystem->sendReliable(getRegion()->getHost());
07346         mNumPendingQueries++;
07347         mTextureCacheQueryID++;
07348 }
07349 
07350 // User has picked "remove from avatar" from a menu.
07351 // static
07352 void LLAgent::userRemoveWearable( void* userdata )
07353 {
07354         EWearableType type = (EWearableType)(intptr_t)userdata;
07355         
07356         if( !(type==WT_SHAPE || type==WT_SKIN || type==WT_HAIR ) ) //&&
07358         {
07359                 gAgent.removeWearable( type );
07360         }
07361 }
07362 
07363 void LLAgent::userRemoveAllClothes( void* userdata )
07364 {
07365         // We have to do this up front to avoid having to deal with the case of multiple wearables being dirty.
07366         if( gFloaterCustomize )
07367         {
07368                 gFloaterCustomize->askToSaveAllIfDirty( LLAgent::userRemoveAllClothesStep2, NULL );
07369         }
07370         else
07371         {
07372                 LLAgent::userRemoveAllClothesStep2( TRUE, NULL );
07373         }
07374 }
07375 
07376 void LLAgent::userRemoveAllClothesStep2( BOOL proceed, void* userdata )
07377 {
07378         if( proceed )
07379         {
07380                 gAgent.removeWearable( WT_SHIRT );
07381                 gAgent.removeWearable( WT_PANTS );
07382                 gAgent.removeWearable( WT_SHOES );
07383                 gAgent.removeWearable( WT_SOCKS );
07384                 gAgent.removeWearable( WT_JACKET );
07385                 gAgent.removeWearable( WT_GLOVES );
07386                 gAgent.removeWearable( WT_UNDERSHIRT );
07387                 gAgent.removeWearable( WT_UNDERPANTS );
07388                 gAgent.removeWearable( WT_SKIRT );
07389         }
07390 }
07391 
07392 void LLAgent::userRemoveAllAttachments( void* userdata )
07393 {
07394         LLVOAvatar* avatarp = gAgent.getAvatarObject();
07395         if(!avatarp)
07396         {
07397                 llwarns << "No avatar found." << llendl;
07398                 return;
07399         }
07400 
07401         gMessageSystem->newMessage("ObjectDetach");
07402         gMessageSystem->nextBlockFast(_PREHASH_AgentData);
07403         gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
07404         gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
07405 
07406         LLViewerJointAttachment* attachment;
07407         for (attachment = avatarp->mAttachmentPoints.getFirstData();
07408                  attachment;
07409                  attachment = avatarp->mAttachmentPoints.getNextData())
07410         {
07411                 LLViewerObject* objectp = attachment->getObject();
07412                 if (objectp)
07413                 {
07414                         gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
07415                         gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, objectp->getLocalID());
07416                 }
07417         }
07418         gMessageSystem->sendReliable( gAgent.getRegionHost() );
07419 }
07420 
07421 bool LLAgent::LLHideGroupTitleListener::handleEvent(LLPointer<LLEvent> event, const LLSD &userdata)
07422 {
07423         gAgent.setHideGroupTitle(event->getValue());
07424         return true;
07425 
07426 }
07427 
07428 bool LLAgent::LLEffectColorListener::handleEvent(LLPointer<LLEvent> event, const LLSD &userdata)
07429 {
07430         gAgent.setEffectColor(LLColor4(event->getValue()));
07431         return true;
07432 }
07433 
07434 void LLAgent::observeFriends()
07435 {
07436         if(!mFriendObserver)
07437         {
07438                 mFriendObserver = new LLAgentFriendObserver;
07439                 LLAvatarTracker::instance().addObserver(mFriendObserver);
07440                 friendsChanged();
07441         }
07442 }
07443 
07444 void LLAgent::parseTeleportMessages(const LLString& xml_filename)
07445 {
07446         LLXMLNodePtr root;
07447         BOOL success = LLUICtrlFactory::getLayeredXMLNode(xml_filename, root);
07448 
07449         if (!success || !root || !root->hasName( "teleport_messages" ))
07450         {
07451                 llerrs << "Problem reading teleport string XML file: " 
07452                            << xml_filename << llendl;
07453                 return;
07454         }
07455 
07456         for (LLXMLNode* message_set = root->getFirstChild();
07457                  message_set != NULL;
07458                  message_set = message_set->getNextSibling())
07459         {
07460                 if ( !message_set->hasName("message_set") ) continue;
07461 
07462                 std::map<LLString, LLString> *teleport_msg_map = NULL;
07463                 LLString message_set_name;
07464 
07465                 if ( message_set->getAttributeString("name", message_set_name) )
07466                 {
07467                         //now we loop over all the string in the set and add them
07468                         //to the appropriate set
07469                         if ( message_set_name == "errors" )
07470                         {
07471                                 teleport_msg_map = &sTeleportErrorMessages;
07472                         }
07473                         else if ( message_set_name == "progress" )
07474                         {
07475                                 teleport_msg_map = &sTeleportProgressMessages;
07476                         }
07477                 }
07478 
07479                 if ( !teleport_msg_map ) continue;
07480 
07481                 LLString message_name;
07482                 for (LLXMLNode* message_node = message_set->getFirstChild();
07483                          message_node != NULL;
07484                          message_node = message_node->getNextSibling())
07485                 {
07486                         if ( message_node->hasName("message") && 
07487                                  message_node->getAttributeString("name", message_name) )
07488                         {
07489                                 (*teleport_msg_map)[message_name] =
07490                                         message_node->getTextContents();
07491                         } //end if ( message exists and has a name)
07492                 } //end for (all message in set)
07493         }//end for (all message sets in xml file)
07494 }
07495 
07496 // EOF

Generated on Thu Jul 1 06:08:18 2010 for Second Life Viewer by  doxygen 1.4.7