aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/newview/llagent.cpp
diff options
context:
space:
mode:
authorJacek Antonelli2008-08-15 23:44:46 -0500
committerJacek Antonelli2008-08-15 23:44:46 -0500
commit38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch)
treeadca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/newview/llagent.cpp
parentREADME.txt (diff)
downloadmeta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.zip
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.gz
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.bz2
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.xz
Second Life viewer sources 1.13.2.12
Diffstat (limited to 'linden/indra/newview/llagent.cpp')
-rw-r--r--linden/indra/newview/llagent.cpp7252
1 files changed, 7252 insertions, 0 deletions
diff --git a/linden/indra/newview/llagent.cpp b/linden/indra/newview/llagent.cpp
new file mode 100644
index 0000000..26ef1b0
--- /dev/null
+++ b/linden/indra/newview/llagent.cpp
@@ -0,0 +1,7252 @@
1/**
2 * @file llagent.cpp
3 * @brief LLAgent class implementation
4 *
5 * Copyright (c) 2001-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#include "llviewerprecompiledheaders.h"
29
30#include "stdtypes.h"
31#include "stdenums.h"
32
33#include "llagent.h"
34
35#include "llcoordframe.h"
36#include "indra_constants.h"
37#include "llmath.h"
38#include "llcriticaldamp.h"
39#include "llfocusmgr.h"
40#include "llglheaders.h"
41#include "llparcel.h"
42#include "llpermissions.h"
43#include "llregionhandle.h"
44#include "m3math.h"
45#include "m4math.h"
46#include "message.h"
47#include "llquaternion.h"
48#include "v3math.h"
49#include "v4math.h"
50//#include "vmath.h"
51
52#include "imageids.h"
53#include "llbox.h"
54#include "llbutton.h"
55#include "llcameraview.h"
56#include "llcallingcard.h"
57#include "llchatbar.h"
58#include "llconsole.h"
59#include "lldrawable.h"
60#include "llface.h"
61#include "llfirstuse.h"
62#include "llfloater.h"
63#include "llfloateravatarinfo.h"
64#include "llfloaterbuildoptions.h"
65#include "llfloaterchat.h"
66#include "llfloatercustomize.h"
67#include "llfloaterdirectory.h"
68#include "llfloatergroupinfo.h"
69#include "llfloatergroups.h"
70#include "llfloatermap.h"
71#include "llfloatermute.h"
72#include "llfloatersnapshot.h"
73#include "llfloatertools.h"
74#include "llfloaterworldmap.h"
75#include "llgroupmgr.h"
76#include "llhudeffectlookat.h"
77#include "llhudmanager.h"
78#include "llinventorymodel.h"
79#include "llinventoryview.h"
80#include "lljoystickbutton.h"
81#include "llmenugl.h"
82#include "llmorphview.h"
83#include "llmoveview.h"
84#include "llnotify.h"
85#include "llquantize.h"
86#include "llselectmgr.h"
87#include "llsky.h"
88#include "llsphere.h"
89#include "llstatusbar.h"
90#include "llimview.h"
91#include "lltool.h"
92#include "lltoolcomp.h" // for gToolGun
93#include "lltoolfocus.h"
94#include "lltoolgrab.h"
95#include "lltoolmgr.h"
96#include "lltoolpie.h"
97#include "lltoolview.h"
98#include "llui.h" // for make_ui_sound
99#include "llviewercamera.h"
100#include "llviewerinventory.h"
101#include "llviewermenu.h"
102#include "llviewernetwork.h"
103#include "llviewerobjectlist.h"
104#include "llviewerparcelmgr.h"
105#include "llviewerparceloverlay.h"
106#include "llviewerregion.h"
107#include "llviewerstats.h"
108#include "llviewerwindow.h"
109#include "llvoavatar.h"
110#include "llvoground.h"
111#include "llvosky.h"
112#include "llwearable.h"
113#include "llwearablelist.h"
114#include "llworld.h"
115#include "llworldmap.h"
116#include "pipeline.h"
117#include "roles_constants.h"
118#include "viewer.h"
119
120// Ventrella
121#include "llfollowcam.h"
122// end Ventrella
123
124extern LLMenuBarGL* gMenuBarView;
125extern F32 gMinObjectDistance;
126extern U8 gLastPickAlpha;
127extern F32 gFrameDTClamped;
128
129//drone wandering constants
130const F32 MAX_WANDER_TIME = 20.f; // seconds
131const F32 MAX_HEADING_HALF_ERROR = 0.2f; // radians
132const F32 WANDER_MAX_SLEW_RATE = 2.f * DEG_TO_RAD; // radians / frame
133const F32 WANDER_TARGET_MIN_DISTANCE = 10.f; // meters
134
135// Autopilot constants
136const F32 AUTOPILOT_HEADING_HALF_ERROR = 10.f * DEG_TO_RAD; // radians
137const F32 AUTOPILOT_MAX_SLEW_RATE = 1.f * DEG_TO_RAD; // radians / frame
138const F32 AUTOPILOT_STOP_DISTANCE = 2.f; // meters
139const F32 AUTOPILOT_HEIGHT_ADJUST_DISTANCE = 8.f; // meters
140const F32 AUTOPILOT_MIN_TARGET_HEIGHT_OFF_GROUND = 1.f; // meters
141const F32 AUTOPILOT_MAX_TIME_NO_PROGRESS = 1.5f; // seconds
142
143// face editing constants
144const LLVector3d FACE_EDIT_CAMERA_OFFSET(0.4f, -0.05f, 0.07f);
145const LLVector3d FACE_EDIT_TARGET_OFFSET(0.f, 0.f, 0.05f);
146
147// Mousewheel camera zoom
148const F32 MIN_ZOOM_FRACTION = 0.25f;
149const F32 INITIAL_ZOOM_FRACTION = 1.f;
150const F32 MAX_ZOOM_FRACTION = 8.f;
151const F32 METERS_PER_WHEEL_CLICK = 1.f;
152
153const F32 MAX_TIME_DELTA = 1.f;
154
155const F32 CAMERA_ZOOM_HALF_LIFE = 0.07f; // seconds
156const F32 FOV_ZOOM_HALF_LIFE = 0.07f; // seconds
157
158const F32 CAMERA_FOCUS_HALF_LIFE = 0.f;//0.02f;
159const F32 CAMERA_LAG_HALF_LIFE = 0.25f;
160const F32 MIN_CAMERA_LAG = 0.5f;
161const F32 MAX_CAMERA_LAG = 5.f;
162
163const F32 CAMERA_COLLIDE_EPSILON = 0.1f;
164const F32 MIN_CAMERA_DISTANCE = 0.1f;
165const F32 AVATAR_ZOOM_MIN_X_FACTOR = 0.55f;
166const F32 AVATAR_ZOOM_MIN_Y_FACTOR = 0.7f;
167const F32 AVATAR_ZOOM_MIN_Z_FACTOR = 1.15f;
168
169const F32 MAX_CAMERA_DISTANCE_FROM_AGENT = 50.f;
170
171const F32 HEAD_BUFFER_SIZE = 0.3f;
172const F32 CUSTOMIZE_AVATAR_CAMERA_ANIM_SLOP = 0.2f;
173
174const F32 LAND_MIN_ZOOM = 0.15f;
175const F32 AVATAR_MIN_ZOOM = 0.5f;
176const F32 OBJECT_MIN_ZOOM = 0.02f;
177
178const F32 APPEARANCE_MIN_ZOOM = 0.39f;
179const F32 APPEARANCE_MAX_ZOOM = 8.f;
180
181// fidget constants
182const F32 MIN_FIDGET_TIME = 8.f; // seconds
183const F32 MAX_FIDGET_TIME = 20.f; // seconds
184
185const S32 MAX_NUM_CHAT_POSITIONS = 10;
186const F32 GROUND_TO_AIR_CAMERA_TRANSITION_TIME = 0.5f;
187const F32 GROUND_TO_AIR_CAMERA_TRANSITION_START_TIME = 0.5f;
188
189const F32 MAX_VELOCITY_AUTO_LAND_SQUARED = 4.f * 4.f;
190
191const F32 MAX_FOCUS_OFFSET = 20.f;
192
193const F32 OBJECT_EXTENTS_PADDING = 0.5f;
194
195const F32 MIN_RADIUS_ALPHA_SIZZLE = 0.5f;
196
197const F64 CHAT_AGE_FAST_RATE = 3.0;
198
199const S32 MAX_WEARABLES_PER_LAYERSET = 7;
200
201const EWearableType WEARABLE_BAKE_TEXTURE_MAP[BAKED_TEXTURE_COUNT][MAX_WEARABLES_PER_LAYERSET] =
202{
203 { WT_SHAPE, WT_SKIN, WT_HAIR, WT_INVALID, WT_INVALID, WT_INVALID, WT_INVALID }, // TEX_HEAD_BAKED
204 { WT_SHAPE, WT_SKIN, WT_SHIRT, WT_JACKET, WT_GLOVES, WT_UNDERSHIRT, WT_INVALID }, // TEX_UPPER_BAKED
205 { WT_SHAPE, WT_SKIN, WT_PANTS, WT_SHOES, WT_SOCKS, WT_JACKET, WT_UNDERPANTS }, // TEX_LOWER_BAKED
206 { WT_EYES, WT_INVALID, WT_INVALID, WT_INVALID, WT_INVALID, WT_INVALID, WT_INVALID }, // TEX_EYES_BAKED
207 { WT_SKIRT, WT_INVALID, WT_INVALID, WT_INVALID, WT_INVALID, WT_INVALID, WT_INVALID } // TEX_SKIRT_BAKED
208};
209
210const LLUUID BAKED_TEXTURE_HASH[BAKED_TEXTURE_COUNT] =
211{
212 LLUUID("18ded8d6-bcfc-e415-8539-944c0f5ea7a6"),
213 LLUUID("338c29e3-3024-4dbb-998d-7c04cf4fa88f"),
214 LLUUID("91b4a2c7-1b1a-ba16-9a16-1f8f8dcc1c3f"),
215 LLUUID("b2cf28af-b840-1071-3c6a-78085d8128b5"),
216 LLUUID("ea800387-ea1a-14e0-56cb-24f2022f969a")
217};
218
219//
220// Statics
221//
222BOOL LLAgent::sDebugDisplayTarget = FALSE;
223
224const F32 LLAgent::TYPING_TIMEOUT_SECS = 5.f;
225
226class LLAgentFriendObserver : public LLFriendObserver
227{
228public:
229 LLAgentFriendObserver() {}
230 virtual ~LLAgentFriendObserver() {}
231 virtual void changed(U32 mask);
232};
233
234void LLAgentFriendObserver::changed(U32 mask)
235{
236 // if there's a change we're interested in.
237 if((mask & (LLFriendObserver::POWERS)) != 0)
238 {
239 gAgent.friendsChanged();
240 }
241}
242
243// ************************************************************
244// Enabled this definition to compile a 'hacked' viewer that
245// locally believes the end user has godlike powers.
246// #define HACKED_GODLIKE_VIEWER
247// For a toggled version, see viewer.h for the
248// TOGGLE_HACKED_GODLIKE_VIEWER define, instead.
249// ************************************************************
250
251// Constructors and Destructors
252
253// JC - Please try to make this order match the order in the header
254// file. Otherwise it's hard to find variables that aren't initialized.
255//-----------------------------------------------------------------------------
256// LLAgent()
257//-----------------------------------------------------------------------------
258LLAgent::LLAgent()
259: mViewerPort(NET_USE_OS_ASSIGNED_PORT),
260 mDrawDistance( DEFAULT_FAR_PLANE ),
261 mAccess(SIM_ACCESS_PG),
262 mGroupPowers(0),
263 mGroupID(),
264 //mGroupInsigniaID(),
265 mMapOriginX(0),
266 mMapOriginY(0),
267 mMapWidth(0),
268 mMapHeight(0),
269 mLookAt(NULL),
270 mPointAt(NULL),
271 mInitialized(FALSE),
272 mNumPendingQueries(0),
273 mForceMouselook(FALSE),
274 mTeleportState( TELEPORT_NONE ),
275 mRegionp(NULL),
276
277 mAgentOriginGlobal(),
278 mPositionGlobal(),
279
280 mDistanceTraveled(0),
281 mLastPositionGlobal(LLVector3d::zero),
282
283 mAvatarObject(NULL),
284
285 mRenderState(0),
286 mTypingTimer(),
287
288 mCameraMode( CAMERA_MODE_THIRD_PERSON ),
289 mLastCameraMode( CAMERA_MODE_THIRD_PERSON ),
290 mViewsPushed(FALSE),
291
292 mbAlwaysRun(FALSE),
293 mShowAvatar(TRUE),
294
295 mCameraAnimating( FALSE ),
296 mAnimationCameraStartGlobal(),
297 mAnimationFocusStartGlobal(),
298 mAnimationTimer(),
299 mAnimationDuration(0.33f),
300 mCameraFOVZoomFactor(0.f),
301 mCameraCurrentFOVZoomFactor(0.f),
302 mCameraFocusOffset(),
303 mCameraOffsetDefault(),
304// mCameraOffsetNorm(),
305 mCameraCollidePlane(),
306 mCurrentCameraDistance(2.f), // meters, set in init()
307 mTargetCameraDistance(2.f),
308 mCameraZoomFraction(1.f), // deprecated
309 mThirdPersonHeadOffset(0.f, 0.f, 1.f),
310 mSitCameraEnabled(FALSE),
311 mFocusOnAvatar(TRUE),
312 mFocusGlobal(),
313 mFocusTargetGlobal(),
314 mFocusObject(NULL),
315 mFocusObjectOffset(),
316 mFocusDotRadius( 0.1f ), // meters
317 mTrackFocusObject(TRUE),
318
319 mFrameAgent(),
320
321 mCrouching(FALSE),
322 mIsBusy(FALSE),
323
324 // movement keys below
325
326 mControlFlags(0x00000000),
327 mbFlagsDirty(FALSE),
328 mbFlagsNeedReset(FALSE),
329
330 mbJump(FALSE),
331
332 mWanderTimer(),
333 mWanderTargetGlobal( LLVector3d::zero ),
334
335 mAutoPilot(FALSE),
336 mAutoPilotFlyOnStop(FALSE),
337 mAutoPilotTargetGlobal(),
338 mAutoPilotStopDistance(1.f),
339 mAutoPilotUseRotation(FALSE),
340 mAutoPilotTargetFacing(LLVector3::zero),
341 mAutoPilotTargetDist(0.f),
342 mAutoPilotFinishedCallback(NULL),
343 mAutoPilotCallbackData(NULL),
344
345
346 mEffectColor(0.f, 1.f, 1.f, 1.f),
347 mHaveHomePosition(FALSE),
348 mHomeRegionHandle( 0 ),
349 mNearChatRadius(10.f),
350 mGodLevel( GOD_NOT ),
351
352
353 mNextFidgetTime(0.f),
354 mCurrentFidget(0),
355 mFirstLogin(FALSE),
356 mGenderChosen(FALSE),
357 mAgentWearablesUpdateSerialNum(0),
358 mWearablesLoaded(FALSE),
359 mTextureCacheQueryID(0),
360 mAppearanceSerialNum(0)
361{
362
363 U32 i;
364 for (i = 0; i < TOTAL_CONTROLS; i++)
365 {
366 mControlsTakenCount[i] = 0;
367 mControlsTakenPassedOnCount[i] = 0;
368 }
369
370 // Initialize movement keys
371 mAtKey = 0; // Either 1, 0, or -1... indicates that movement-key is pressed
372 mWalkKey = 0; // like AtKey, but causes less forward thrust
373 mLeftKey = 0;
374 mUpKey = 0;
375 mYawKey = 0.f;
376 mPitchKey = 0;
377
378 mOrbitLeftKey = 0.f;
379 mOrbitRightKey = 0.f;
380 mOrbitUpKey = 0.f;
381 mOrbitDownKey = 0.f;
382 mOrbitInKey = 0.f;
383 mOrbitOutKey = 0.f;
384
385 mPanUpKey = 0.f;
386 mPanDownKey = 0.f;
387 mPanLeftKey = 0.f;
388 mPanRightKey = 0.f;
389 mPanInKey = 0.f;
390 mPanOutKey = 0.f;
391
392 mActiveCacheQueries = new S32[BAKED_TEXTURE_COUNT];
393 for (i = 0; i < (U32)BAKED_TEXTURE_COUNT; i++)
394 {
395 mActiveCacheQueries[i] = 0;
396 }
397
398 //Ventrella
399 mCameraUpVector = LLVector3::z_axis;// default is straight up
400 mFollowCam.setMaxCameraDistantFromSubject( MAX_CAMERA_DISTANCE_FROM_AGENT );
401 //end ventrella
402}
403
404// Requires gSavedSettings to be initialized.
405//-----------------------------------------------------------------------------
406// init()
407//-----------------------------------------------------------------------------
408void LLAgent::init()
409{
410 mDrawDistance = gSavedSettings.getF32("RenderFarClip");
411
412 gCamera = new LLViewerCamera();
413
414 gCamera->setView(DEFAULT_FIELD_OF_VIEW);
415 // Leave at 0.1 meters until we have real near clip management
416 gCamera->setNear(0.1f);
417 gCamera->setFar(mDrawDistance); // if you want to change camera settings, do so in camera.h
418 gCamera->setAspect( gViewerWindow->getDisplayAspectRatio() ); // default, overridden in LLViewerWindow::reshape
419 gCamera->setViewHeightInPixels(768); // default, overridden in LLViewerWindow::reshape
420
421 setFlying( gSavedSettings.getBOOL("FlyingAtExit") );
422
423 mCameraFocusOffsetTarget = LLVector4(gSavedSettings.getVector3("CameraOffsetBuild"));
424 mCameraOffsetDefault = gSavedSettings.getVector3("CameraOffsetDefault");
425// mCameraOffsetNorm = mCameraOffsetDefault;
426// mCameraOffsetNorm.normVec();
427 mCameraCollidePlane.clearVec();
428 mCurrentCameraDistance = mCameraOffsetDefault.magVec();
429 mTargetCameraDistance = mCurrentCameraDistance;
430 mCameraZoomFraction = 1.f;
431 mTrackFocusObject = gSavedSettings.getBOOL("TrackFocusObject");
432
433// LLDebugVarMessageBox::show("Camera Lag", &CAMERA_FOCUS_HALF_LIFE, 0.5f, 0.01f);
434 gSavedSettings.getControl("RenderHideGroupTitle")->addListener(&mHideGroupTitleListener);
435 gSavedSettings.getControl("EffectColor")->addListener(&mEffectColorListener);
436
437 mEffectColor = gSavedSettings.getColor4("EffectColor");
438
439 mInitialized = TRUE;
440}
441
442//-----------------------------------------------------------------------------
443// cleanup()
444//-----------------------------------------------------------------------------
445void LLAgent::cleanup()
446{
447 setSitCamera(LLUUID::null);
448 mAvatarObject = NULL;
449 mLookAt = NULL;
450 mPointAt = NULL;
451 mRegionp = NULL;
452 setFocusObject(NULL);
453 mFadeObjects.clear();
454}
455
456//-----------------------------------------------------------------------------
457// LLAgent()
458//-----------------------------------------------------------------------------
459LLAgent::~LLAgent()
460{
461 cleanup();
462
463 delete [] mActiveCacheQueries;
464 mActiveCacheQueries = NULL;
465
466 delete gCamera;
467 gCamera = NULL;
468}
469
470// Change camera back to third person, stop the autopilot,
471// deselect stuff, etc.
472//-----------------------------------------------------------------------------
473// resetView()
474//-----------------------------------------------------------------------------
475void LLAgent::resetView(BOOL reset_camera)
476{
477 if (mAutoPilot)
478 {
479 stopAutoPilot(TRUE);
480 }
481
482 if (!gNoRender)
483 {
484 gSelectMgr->deselectAll();
485 gSelectMgr->unhighlightAll();
486
487 // By popular request, keep land selection while walking around. JC
488 // gParcelMgr->deselectLand();
489
490 // Hide all popup menus
491 gPieSelf->hide(FALSE);
492 gPieAvatar->hide(FALSE);
493 gPieObject->hide(FALSE);
494 gPieLand->hide(FALSE);
495 }
496
497 if (reset_camera && !gSavedSettings.getBOOL("FreezeTime"))
498 {
499 if (!gViewerWindow->getLeftMouseDown() && cameraThirdPerson())
500 {
501 // leaving mouse-steer mode
502 LLVector3 agent_at_axis = getAtAxis();
503 agent_at_axis -= projected_vec(agent_at_axis, getReferenceUpVector());
504 agent_at_axis.normVec();
505 gAgent.resetAxes(lerp(getAtAxis(), agent_at_axis, LLCriticalDamp::getInterpolant(0.3f)));
506 }
507
508 setFocusOnAvatar(TRUE, ANIMATE);
509 }
510
511 if (mAvatarObject.notNull())
512 {
513 mAvatarObject->mHUDTargetZoom = 1.f;
514 }
515}
516
517void LLAgent::ageChat()
518{
519 if (mAvatarObject)
520 {
521 // get amount of time since I last chatted
522 F64 elapsed_time = (F64)mAvatarObject->mChatTimer.getElapsedTimeF32();
523 // add in frame time * 3 (so it ages 4x)
524 mAvatarObject->mChatTimer.setAge(elapsed_time + (F64)gFrameDTClamped * (CHAT_AGE_FAST_RATE - 1.0));
525 }
526}
527
528// Allow camera to be moved somewhere other than behind avatar.
529//-----------------------------------------------------------------------------
530// unlockView()
531//-----------------------------------------------------------------------------
532void LLAgent::unlockView()
533{
534 if (getFocusOnAvatar())
535 {
536 if (mAvatarObject)
537 {
538 setFocusGlobal( LLVector3d::zero, mAvatarObject->mID );
539 }
540 setFocusOnAvatar(FALSE, FALSE); // no animation
541 }
542}
543
544
545//-----------------------------------------------------------------------------
546// moveAt()
547//-----------------------------------------------------------------------------
548void LLAgent::moveAt(S32 direction)
549{
550 // age chat timer so it fades more quickly when you are intentionally moving
551 ageChat();
552
553 setKey(direction, mAtKey);
554
555 if (direction > 0)
556 {
557 setControlFlags(AGENT_CONTROL_AT_POS | AGENT_CONTROL_FAST_AT);
558 }
559 else if (direction < 0)
560 {
561 setControlFlags(AGENT_CONTROL_AT_NEG | AGENT_CONTROL_FAST_AT);
562 }
563
564 resetView();
565}
566
567//-----------------------------------------------------------------------------
568// moveAtNudge()
569//-----------------------------------------------------------------------------
570void LLAgent::moveAtNudge(S32 direction)
571{
572 // age chat timer so it fades more quickly when you are intentionally moving
573 ageChat();
574
575 setKey(direction, mWalkKey);
576
577 if (direction > 0)
578 {
579 setControlFlags(AGENT_CONTROL_NUDGE_AT_POS);
580 }
581 else if (direction < 0)
582 {
583 setControlFlags(AGENT_CONTROL_NUDGE_AT_NEG);
584 }
585
586 resetView();
587}
588
589//-----------------------------------------------------------------------------
590// moveLeft()
591//-----------------------------------------------------------------------------
592void LLAgent::moveLeft(S32 direction)
593{
594 // age chat timer so it fades more quickly when you are intentionally moving
595 ageChat();
596
597 setKey(direction, mLeftKey);
598
599 if (direction > 0)
600 {
601 setControlFlags(AGENT_CONTROL_LEFT_POS | AGENT_CONTROL_FAST_LEFT);
602 }
603 else if (direction < 0)
604 {
605 setControlFlags(AGENT_CONTROL_LEFT_NEG | AGENT_CONTROL_FAST_LEFT);
606 }
607
608 resetView();
609}
610
611//-----------------------------------------------------------------------------
612// moveLeftNudge()
613//-----------------------------------------------------------------------------
614void LLAgent::moveLeftNudge(S32 direction)
615{
616 // age chat timer so it fades more quickly when you are intentionally moving
617 ageChat();
618
619 setKey(direction, mLeftKey);
620
621 if (direction > 0)
622 {
623 setControlFlags(AGENT_CONTROL_NUDGE_LEFT_POS);
624 }
625 else if (direction < 0)
626 {
627 setControlFlags(AGENT_CONTROL_NUDGE_LEFT_NEG);
628 }
629
630 resetView();
631}
632
633//-----------------------------------------------------------------------------
634// moveUp()
635//-----------------------------------------------------------------------------
636void LLAgent::moveUp(S32 direction)
637{
638 // age chat timer so it fades more quickly when you are intentionally moving
639 ageChat();
640
641 setKey(direction, mUpKey);
642
643 if (direction > 0)
644 {
645 setControlFlags(AGENT_CONTROL_UP_POS | AGENT_CONTROL_FAST_UP);
646 }
647 else if (direction < 0)
648 {
649 setControlFlags(AGENT_CONTROL_UP_NEG | AGENT_CONTROL_FAST_UP);
650 }
651
652 resetView();
653}
654
655//-----------------------------------------------------------------------------
656// moveYaw()
657//-----------------------------------------------------------------------------
658void LLAgent::moveYaw(F32 mag)
659{
660 mYawKey = mag;
661
662 if (mag > 0)
663 {
664 setControlFlags(AGENT_CONTROL_YAW_POS);
665 }
666 else if (mag < 0)
667 {
668 setControlFlags(AGENT_CONTROL_YAW_NEG);
669 }
670
671 resetView();
672}
673
674//-----------------------------------------------------------------------------
675// movePitch()
676//-----------------------------------------------------------------------------
677void LLAgent::movePitch(S32 direction)
678{
679 setKey(direction, mPitchKey);
680
681 if (direction > 0)
682 {
683 setControlFlags(AGENT_CONTROL_PITCH_POS );
684 }
685 else if (direction < 0)
686 {
687 setControlFlags(AGENT_CONTROL_PITCH_NEG);
688 }
689}
690
691
692// Does this parcel allow you to fly?
693BOOL LLAgent::canFly()
694{
695 if (isGodlike()) return TRUE;
696
697 if (!gParcelMgr) return FALSE;
698
699 LLViewerRegion* regionp = getRegion();
700 if (regionp && regionp->getBlockFly()) return FALSE;
701
702 LLParcel* parcel = gParcelMgr->getAgentParcel();
703 if (!parcel) return FALSE;
704
705 // Allow owners to fly on their own land.
706 if (LLViewerParcelMgr::isParcelOwnedByAgent(parcel, GP_LAND_ALLOW_FLY))
707 {
708 return TRUE;
709 }
710
711 return parcel->getAllowFly();
712}
713
714
715//-----------------------------------------------------------------------------
716// setFlying()
717//-----------------------------------------------------------------------------
718void LLAgent::setFlying(BOOL fly)
719{
720 if (mAvatarObject.notNull())
721 {
722 if(mAvatarObject->mSignaledAnimations.find(ANIM_AGENT_STANDUP) != mAvatarObject->mSignaledAnimations.end())
723 {
724 return;
725 }
726
727 // don't allow taking off while sitting
728 if (fly && mAvatarObject->mIsSitting)
729 {
730 return;
731 }
732 }
733
734 if (fly)
735 {
736 BOOL was_flying = getFlying();
737 if (gParcelMgr)
738 {
739 if (!canFly() && !was_flying)
740 {
741 // parcel doesn't let you start fly
742 // gods can always fly
743 // and it's OK if you're already flying
744 make_ui_sound("UISndBadKeystroke");
745 return;
746 }
747 }
748 if( !was_flying )
749 {
750 gViewerStats->incStat(LLViewerStats::ST_FLY_COUNT);
751 }
752 setControlFlags(AGENT_CONTROL_FLY);
753 gSavedSettings.setBOOL("FlyBtnState", TRUE);
754 }
755 else
756 {
757 clearControlFlags(AGENT_CONTROL_FLY);
758 gSavedSettings.setBOOL("FlyBtnState", FALSE);
759 }
760 mbFlagsDirty = TRUE;
761}
762
763
764// UI based mechanism of setting fly state
765//-----------------------------------------------------------------------------
766// toggleFlying()
767//-----------------------------------------------------------------------------
768void LLAgent::toggleFlying()
769{
770 BOOL fly = !(mControlFlags & AGENT_CONTROL_FLY);
771
772 setFlying( fly );
773 resetView();
774}
775
776
777//-----------------------------------------------------------------------------
778// setRegion()
779//-----------------------------------------------------------------------------
780void LLAgent::setRegion(LLViewerRegion *regionp)
781{
782 llassert(regionp);
783 if (mRegionp != regionp)
784 {
785 // JC - Avoid this, causes out-of-bounds array write deep within
786 // Windows.
787 // char host_name[MAX_STRING];
788 // regionp->getHost().getHostName(host_name, MAX_STRING);
789
790 char ip[MAX_STRING];
791 regionp->getHost().getString(ip, MAX_STRING);
792 llinfos << "Moving agent into region: " << regionp->getName()
793 << " located at " << ip << llendl;
794 if (mRegionp)
795 {
796 // We've changed regions, we're now going to change our agent coordinate frame.
797 mAgentOriginGlobal = regionp->getOriginGlobal();
798 LLVector3d agent_offset_global = mRegionp->getOriginGlobal();
799
800 LLVector3 delta;
801 delta.setVec(regionp->getOriginGlobal() - mRegionp->getOriginGlobal());
802
803 setPositionAgent(getPositionAgent() - delta);
804 LLVector3 camera_position_agent = gCamera->getOrigin();
805 gCamera->setOrigin(camera_position_agent - delta);
806
807 // Update all of the regions.
808 gWorldPointer->updateAgentOffset(agent_offset_global);
809
810 // Hack to keep sky in the agent's region, otherwise it may get deleted - DJS 08/02/02
811 if (gSky.mVOSkyp)
812 {
813 gSky.mVOSkyp->setRegion(regionp);
814 }
815 if (gSky.mVOStarsp)
816 {
817 gSky.mVOStarsp->setRegion(regionp);
818 }
819 if (gSky.mVOGroundp)
820 {
821 gSky.mVOGroundp->setRegion(regionp);
822 }
823
824 }
825 else
826 {
827 // First time initialization.
828 // We've changed regions, we're now going to change our agent coordinate frame.
829 mAgentOriginGlobal = regionp->getOriginGlobal();
830
831 LLVector3 delta;
832 delta.setVec(regionp->getOriginGlobal());
833
834 setPositionAgent(getPositionAgent() - delta);
835 LLVector3 camera_position_agent = gCamera->getOrigin();
836 gCamera->setOrigin(camera_position_agent - delta);
837
838 // Update all of the regions.
839 gWorldPointer->updateAgentOffset(mAgentOriginGlobal);
840 }
841 }
842 mRegionp = regionp;
843
844 // Must shift hole-covering water object locations because local
845 // coordinate frame changed.
846 gWorldPointer->updateWaterObjects();
847
848 // keep a list of regions we've been too
849 // this is just an interesting stat, logged at the dataserver
850 // we could trake this at the dataserver side, but that's harder
851 U64 handle = regionp->getHandle();
852 mRegionsVisited.insert(handle);
853}
854
855
856//-----------------------------------------------------------------------------
857// getRegion()
858//-----------------------------------------------------------------------------
859LLViewerRegion *LLAgent::getRegion() const
860{
861 return mRegionp;
862}
863
864
865const LLHost& LLAgent::getRegionHost() const
866{
867 if (mRegionp)
868 {
869 return mRegionp->getHost();
870 }
871 else
872 {
873 return LLHost::invalid;
874 }
875}
876
877
878//-----------------------------------------------------------------------------
879// inPrelude()
880//-----------------------------------------------------------------------------
881BOOL LLAgent::inPrelude()
882{
883 return mRegionp && mRegionp->isPrelude();
884}
885
886
887//-----------------------------------------------------------------------------
888// canManageEstate()
889//-----------------------------------------------------------------------------
890
891BOOL LLAgent::canManageEstate() const
892{
893 return mRegionp && mRegionp->canManageEstate();
894}
895//-----------------------------------------------------------------------------
896// sendMessage()
897//-----------------------------------------------------------------------------
898void LLAgent::sendMessage()
899{
900 if (gDisconnected)
901 {
902 llwarns << "Trying to send message when disconnected!" << llendl;
903 return;
904 }
905 if (!mRegionp)
906 {
907 llerrs << "No region for agent yet!" << llendl;
908 }
909 gMessageSystem->sendMessage(mRegionp->getHost());
910}
911
912
913//-----------------------------------------------------------------------------
914// sendReliableMessage()
915//-----------------------------------------------------------------------------
916void LLAgent::sendReliableMessage()
917{
918 if (gDisconnected)
919 {
920 llwarns << "Trying to send message when disconnected!" << llendl;
921 return;
922 }
923 if (!mRegionp)
924 {
925 llwarns << "LLAgent::sendReliableMessage No region for agent yet, not sending message!" << llendl;
926 return;
927 }
928 gMessageSystem->sendReliable(mRegionp->getHost());
929}
930
931//-----------------------------------------------------------------------------
932// getVelocity()
933//-----------------------------------------------------------------------------
934LLVector3 LLAgent::getVelocity() const
935{
936 if (mAvatarObject)
937 {
938 return mAvatarObject->getVelocity();
939 }
940 else
941 {
942 return LLVector3::zero;
943 }
944}
945
946
947//-----------------------------------------------------------------------------
948// setPositionAgent()
949//-----------------------------------------------------------------------------
950void LLAgent::setPositionAgent(const LLVector3 &pos_agent)
951{
952 if (!pos_agent.isFinite())
953 {
954 llerrs << "setPositionAgent is not a number" << llendl;
955 }
956
957 if (!mAvatarObject.isNull() && mAvatarObject->getParent())
958 {
959 LLVector3 pos_agent_sitting;
960 LLVector3d pos_agent_d;
961 LLViewerObject *parent = (LLViewerObject*)mAvatarObject->getParent();
962
963 pos_agent_sitting = mAvatarObject->getPosition() * parent->getRotation() + parent->getPositionAgent();
964 pos_agent_d.setVec(pos_agent_sitting);
965
966 mFrameAgent.setOrigin(pos_agent_sitting);
967 mPositionGlobal = pos_agent_d + mAgentOriginGlobal;
968 }
969 else
970 {
971 mFrameAgent.setOrigin(pos_agent);
972
973 LLVector3d pos_agent_d;
974 pos_agent_d.setVec(pos_agent);
975 mPositionGlobal = pos_agent_d + mAgentOriginGlobal;
976 }
977}
978
979//-----------------------------------------------------------------------------
980// slamLookAt()
981//-----------------------------------------------------------------------------
982void LLAgent::slamLookAt(const LLVector3 &look_at)
983{
984 LLVector3 look_at_norm = look_at;
985 look_at_norm.mV[VZ] = 0.f;
986 look_at_norm.normVec();
987 resetAxes(look_at_norm);
988}
989
990//-----------------------------------------------------------------------------
991// getPositionGlobal()
992//-----------------------------------------------------------------------------
993const LLVector3d &LLAgent::getPositionGlobal()
994{
995 if (!mAvatarObject.isNull() && !mAvatarObject->mDrawable.isNull())
996 {
997 mPositionGlobal = getPosGlobalFromAgent(mAvatarObject->getRenderPosition());
998 }
999 else
1000 {
1001 mPositionGlobal = getPosGlobalFromAgent(mFrameAgent.getOrigin());
1002 }
1003
1004 return mPositionGlobal;
1005}
1006
1007//-----------------------------------------------------------------------------
1008// getPositionAgent()
1009//-----------------------------------------------------------------------------
1010const LLVector3 &LLAgent::getPositionAgent()
1011{
1012 if(!mAvatarObject.isNull() && !mAvatarObject->mDrawable.isNull())
1013 {
1014 mFrameAgent.setOrigin(mAvatarObject->getRenderPosition());
1015 }
1016
1017 return mFrameAgent.getOrigin();
1018}
1019
1020//-----------------------------------------------------------------------------
1021// getRegionsVisited()
1022//-----------------------------------------------------------------------------
1023const S32 LLAgent::getRegionsVisited() const
1024{
1025 return mRegionsVisited.size();
1026}
1027
1028//-----------------------------------------------------------------------------
1029// getDistanceTraveled()
1030//-----------------------------------------------------------------------------
1031const F64 LLAgent::getDistanceTraveled() const
1032{
1033 return mDistanceTraveled;
1034}
1035
1036
1037//-----------------------------------------------------------------------------
1038// getPosAgentFromGlobal()
1039//-----------------------------------------------------------------------------
1040LLVector3 LLAgent::getPosAgentFromGlobal(const LLVector3d &pos_global) const
1041{
1042 LLVector3 pos_agent;
1043 pos_agent.setVec(pos_global - mAgentOriginGlobal);
1044 return pos_agent;
1045}
1046
1047
1048//-----------------------------------------------------------------------------
1049// getPosGlobalFromAgent()
1050//-----------------------------------------------------------------------------
1051LLVector3d LLAgent::getPosGlobalFromAgent(const LLVector3 &pos_agent) const
1052{
1053 LLVector3d pos_agent_d;
1054 pos_agent_d.setVec(pos_agent);
1055 return pos_agent_d + mAgentOriginGlobal;
1056}
1057
1058
1059//-----------------------------------------------------------------------------
1060// resetAxes()
1061//-----------------------------------------------------------------------------
1062void LLAgent::resetAxes()
1063{
1064 mFrameAgent.resetAxes();
1065}
1066
1067
1068// Copied from LLCamera::setOriginAndLookAt
1069// Look_at must be unit vector
1070//-----------------------------------------------------------------------------
1071// resetAxes()
1072//-----------------------------------------------------------------------------
1073void LLAgent::resetAxes(const LLVector3 &look_at)
1074{
1075 LLVector3 skyward = getReferenceUpVector();
1076
1077 // if look_at has zero length, fail
1078 // if look_at and skyward are parallel, fail
1079 //
1080 // Test both of these conditions with a cross product.
1081 LLVector3 cross(look_at % skyward);
1082 if (cross.isNull())
1083 {
1084 llinfos << "LLAgent::resetAxes cross-product is zero" << llendl;
1085 return;
1086 }
1087
1088 // Make sure look_at and skyward are not parallel
1089 // and neither are zero length
1090 LLVector3 left(skyward % look_at);
1091 LLVector3 up(look_at % left);
1092
1093 mFrameAgent.setAxes(look_at, left, up);
1094}
1095
1096
1097//-----------------------------------------------------------------------------
1098// rotate()
1099//-----------------------------------------------------------------------------
1100void LLAgent::rotate(F32 angle, const LLVector3 &axis)
1101{
1102 mFrameAgent.rotate(angle, axis);
1103}
1104
1105
1106//-----------------------------------------------------------------------------
1107// rotate()
1108//-----------------------------------------------------------------------------
1109void LLAgent::rotate(F32 angle, F32 x, F32 y, F32 z)
1110{
1111 mFrameAgent.rotate(angle, x, y, z);
1112}
1113
1114
1115//-----------------------------------------------------------------------------
1116// rotate()
1117//-----------------------------------------------------------------------------
1118void LLAgent::rotate(const LLMatrix3 &matrix)
1119{
1120 mFrameAgent.rotate(matrix);
1121}
1122
1123
1124//-----------------------------------------------------------------------------
1125// rotate()
1126//-----------------------------------------------------------------------------
1127void LLAgent::rotate(const LLQuaternion &quaternion)
1128{
1129 mFrameAgent.rotate(quaternion);
1130}
1131
1132
1133//-----------------------------------------------------------------------------
1134// getReferenceUpVector()
1135//-----------------------------------------------------------------------------
1136LLVector3 LLAgent::getReferenceUpVector()
1137{
1138 // this vector is in the coordinate frame of the avatar's parent object, or the world if none
1139 LLVector3 up_vector = LLVector3::z_axis;
1140 if (mAvatarObject.notNull() &&
1141 mAvatarObject->getParent() &&
1142 mAvatarObject->mDrawable.notNull())
1143 {
1144 U32 camera_mode = mCameraAnimating ? mLastCameraMode : mCameraMode;
1145 // and in third person...
1146 if (camera_mode == CAMERA_MODE_THIRD_PERSON)
1147 {
1148 // make the up vector point to the absolute +z axis
1149 up_vector = up_vector * ~((LLViewerObject*)mAvatarObject->getParent())->getRenderRotation();
1150 }
1151 else if (camera_mode == CAMERA_MODE_MOUSELOOK)
1152 {
1153 // make the up vector point to the avatar's +z axis
1154 up_vector = up_vector * mAvatarObject->mDrawable->getRotation();
1155 }
1156 }
1157
1158 return up_vector;
1159}
1160
1161
1162// Radians, positive is forward into ground
1163//-----------------------------------------------------------------------------
1164// pitch()
1165//-----------------------------------------------------------------------------
1166void LLAgent::pitch(F32 angle)
1167{
1168 // don't let user pitch if pointed almost all the way down or up
1169
1170 // A dot B = mag(A) * mag(B) * cos(angle between A and B)
1171 // so... cos(angle between A and B) = A dot B / mag(A) / mag(B)
1172 // = A dot B for unit vectors
1173
1174 LLVector3 skyward = getReferenceUpVector();
1175
1176 F32 look_down_limit;
1177 F32 look_up_limit = 10.f * DEG_TO_RAD;
1178
1179 F32 angle_from_skyward = acos( mFrameAgent.getAtAxis() * skyward );
1180
1181 if (mAvatarObject.notNull() && mAvatarObject->mIsSitting)
1182 {
1183 look_down_limit = 130.f * DEG_TO_RAD;
1184 }
1185 else
1186 {
1187 look_down_limit = 170.f * DEG_TO_RAD;
1188 }
1189
1190 // clamp pitch to limits
1191 if ((angle >= 0.f) && (angle_from_skyward + angle > look_down_limit))
1192 {
1193 angle = look_down_limit - angle_from_skyward;
1194 }
1195 else if ((angle < 0.f) && (angle_from_skyward + angle < look_up_limit))
1196 {
1197 angle = look_up_limit - angle_from_skyward;
1198 }
1199
1200 mFrameAgent.pitch(angle);
1201}
1202
1203
1204//-----------------------------------------------------------------------------
1205// roll()
1206//-----------------------------------------------------------------------------
1207void LLAgent::roll(F32 angle)
1208{
1209 mFrameAgent.roll(angle);
1210}
1211
1212
1213//-----------------------------------------------------------------------------
1214// yaw()
1215//-----------------------------------------------------------------------------
1216void LLAgent::yaw(F32 angle)
1217{
1218 if (!rotateGrabbed())
1219 {
1220 mFrameAgent.rotate(angle, getReferenceUpVector());
1221 }
1222}
1223
1224
1225// Returns a quat that represents the rotation of the agent in the absolute frame
1226//-----------------------------------------------------------------------------
1227// getQuat()
1228//-----------------------------------------------------------------------------
1229LLQuaternion LLAgent::getQuat() const
1230{
1231 return mFrameAgent.getQuaternion();
1232}
1233
1234
1235//-----------------------------------------------------------------------------
1236// calcFocusOffset()
1237//-----------------------------------------------------------------------------
1238LLVector3d LLAgent::calcFocusOffset(LLViewerObject *object, S32 x, S32 y)
1239{
1240 // calculate offset based on view direction
1241 BOOL is_avatar = object->isAvatar();
1242 LLMatrix4 obj_matrix = is_avatar ? ((LLVOAvatar*)object)->mPelvisp->getWorldMatrix() : object->getRenderMatrix();
1243 LLQuaternion obj_rot = is_avatar ? ((LLVOAvatar*)object)->mPelvisp->getWorldRotation() : object->getRenderRotation();
1244 LLVector3 obj_pos = is_avatar ? ((LLVOAvatar*)object)->mPelvisp->getWorldPosition() : object->getRenderPosition();
1245 LLQuaternion inv_obj_rot = ~obj_rot;
1246
1247 LLVector3 obj_dir_abs = obj_pos - gCamera->getOrigin();
1248 obj_dir_abs.rotVec(inv_obj_rot);
1249 obj_dir_abs.normVec();
1250 obj_dir_abs.abs();
1251
1252 LLVector3 object_extents = object->getScale();
1253 // make sure they object extents are non-zero
1254 object_extents.clamp(0.001f, F32_MAX);
1255 LLVector3 object_half_extents = object_extents * 0.5f;
1256
1257 obj_dir_abs.mV[VX] = obj_dir_abs.mV[VX] / object_extents.mV[VX];
1258 obj_dir_abs.mV[VY] = obj_dir_abs.mV[VY] / object_extents.mV[VY];
1259 obj_dir_abs.mV[VZ] = obj_dir_abs.mV[VZ] / object_extents.mV[VZ];
1260
1261 LLVector3 normal;
1262 if (obj_dir_abs.mV[VX] > obj_dir_abs.mV[VY] && obj_dir_abs.mV[VX] > obj_dir_abs.mV[VZ])
1263 {
1264 normal.setVec(obj_matrix.getFwdRow4());
1265 }
1266 else if (obj_dir_abs.mV[VY] > obj_dir_abs.mV[VZ])
1267 {
1268 normal.setVec(obj_matrix.getLeftRow4());
1269 }
1270 else
1271 {
1272 normal.setVec(obj_matrix.getUpRow4());
1273 }
1274 normal.normVec();
1275
1276 LLVector3d focus_pt_global;
1277 // RN: should we check return value for valid pick?
1278 gViewerWindow->mousePointOnPlaneGlobal(focus_pt_global, x, y, gAgent.getPosGlobalFromAgent(obj_pos), normal);
1279 LLVector3 focus_pt = gAgent.getPosAgentFromGlobal(focus_pt_global);
1280 // find vector from camera to focus point in object coordinates
1281 LLVector3 camera_focus_vec = focus_pt - gCamera->getOrigin();
1282 // convert to object-local space
1283 camera_focus_vec.rotVec(inv_obj_rot);
1284
1285 // find vector from object origin to focus point in object coordinates
1286 LLVector3 focus_delta = focus_pt - obj_pos;
1287 // convert to object-local space
1288 focus_delta.rotVec(inv_obj_rot);
1289
1290 // calculate clip percentage needed to get focus offset back in bounds along the camera_focus axis
1291 LLVector3 clip_fraction;
1292
1293 for (U32 axis = VX; axis <= VZ; axis++)
1294 {
1295 F32 clip_amt;
1296 if (focus_delta.mV[axis] > 0.f)
1297 {
1298 clip_amt = llmax(0.f, focus_delta.mV[axis] - object_half_extents.mV[axis]);
1299 }
1300 else
1301 {
1302 clip_amt = llmin(0.f, focus_delta.mV[axis] + object_half_extents.mV[axis]);
1303 }
1304
1305 // don't divide by very small nunber
1306 if (llabs(camera_focus_vec.mV[axis]) < 0.0001f)
1307 {
1308 clip_fraction.mV[axis] = 0.f;
1309 }
1310 else
1311 {
1312 clip_fraction.mV[axis] = clip_amt / camera_focus_vec.mV[axis];
1313 }
1314 }
1315
1316 LLVector3 abs_clip_fraction = clip_fraction;
1317 abs_clip_fraction.abs();
1318
1319 // find greatest shrinkage factor and
1320 // rescale focus offset to inside object extents
1321 if (abs_clip_fraction.mV[VX] > abs_clip_fraction.mV[VY] &&
1322 abs_clip_fraction.mV[VX] > abs_clip_fraction.mV[VZ])
1323 {
1324 focus_delta -= clip_fraction.mV[VX] * camera_focus_vec;
1325 }
1326 else if (abs_clip_fraction.mV[VY] > abs_clip_fraction.mV[VZ])
1327 {
1328 focus_delta -= clip_fraction.mV[VY] * camera_focus_vec;
1329 }
1330 else
1331 {
1332 focus_delta -= clip_fraction.mV[VZ] * camera_focus_vec;
1333 }
1334
1335 // convert back to world space
1336 focus_delta.rotVec(obj_rot);
1337
1338 if (!is_avatar)
1339 {
1340 //unproject relative clicked coordinate from window coordinate using GL
1341 glPushMatrix();
1342 glMatrixMode(GL_PROJECTION);
1343 glLoadMatrixf((const GLfloat*) gCamera->getProjection().mMatrix);
1344 glMatrixMode(GL_MODELVIEW);
1345 glLoadMatrixf((const GLfloat*) gCamera->getModelview().mMatrix);
1346 glMultMatrixf((const GLfloat*) obj_matrix.mMatrix);
1347
1348 GLint viewport[4];
1349 GLdouble modelview[16];
1350 GLdouble projection[16];
1351 GLfloat winX, winY, winZ;
1352 GLdouble posX, posY, posZ;
1353
1354 glGetDoublev( GL_MODELVIEW_MATRIX, modelview );
1355 glGetDoublev( GL_PROJECTION_MATRIX, projection );
1356 glGetIntegerv( GL_VIEWPORT, viewport );
1357
1358 winX = ((F32)x) * gViewerWindow->getDisplayScale().mV[VX];
1359 winY = ((F32)y) * gViewerWindow->getDisplayScale().mV[VY];
1360 glReadPixels( llfloor(winX), llfloor(winY), 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &winZ );
1361
1362 gluUnProject( winX, winY, winZ, modelview, projection, viewport, &posX, &posY, &posZ);
1363
1364 glPopMatrix();
1365
1366 LLVector3 obj_rel = LLVector3((F32)posX, (F32)posY, (F32)posZ);
1367 LLVector3 obj_center = LLVector3(0, 0, 0);
1368 obj_rel = obj_rel * object->getRenderMatrix(); //mDrawable->getWorldMatrix();
1369 obj_center = obj_center * object->getRenderMatrix();//mDrawable->getWorldMatrix();
1370 obj_rel -= object->getRenderPosition();//mDrawable->getWorldPosition();
1371
1372 //now that we have the object relative position, we should bias toward the center of the object
1373 //based on the distance of the camera to the focus point vs. the distance of the camera to the focus
1374
1375 F32 relDist = llabs(obj_rel * gCamera->getAtAxis());
1376 F32 viewDist = dist_vec(obj_center + obj_rel, gCamera->getOrigin());
1377
1378
1379 LLBBox obj_bbox = object->getBoundingBoxAgent();
1380 F32 bias = 0.f;
1381
1382 LLVector3 virtual_camera_pos = gAgent.getPosAgentFromGlobal(mFocusTargetGlobal + (getCameraPositionGlobal() - mFocusTargetGlobal) / (1.f + mCameraFOVZoomFactor));
1383
1384 if(obj_bbox.containsPointAgent(virtual_camera_pos))
1385 {
1386 // if the camera is inside the object (large, hollow objects, for example)
1387 // force focus point all the way to destination depth, away from object center
1388 bias = 1.f;
1389 }
1390 else
1391 {
1392 // perform magic number biasing of focus point towards surface vs. planar center
1393 bias = clamp_rescale(relDist/viewDist, 0.1f, 0.7f, 0.0f, 1.0f);
1394 }
1395
1396 obj_rel = lerp(focus_delta, obj_rel, bias);
1397
1398 return LLVector3d(obj_rel);
1399 }
1400
1401 return LLVector3d(focus_delta.mV[VX], focus_delta.mV[VY], focus_delta.mV[VZ]);
1402}
1403
1404//-----------------------------------------------------------------------------
1405// calcCameraMinDistance()
1406//-----------------------------------------------------------------------------
1407BOOL LLAgent::calcCameraMinDistance(F32 &obj_min_distance)
1408{
1409 BOOL soft_limit = FALSE; // is the bounding box to be treated literally (volumes) or as an approximation (avatars)
1410
1411 if (!mFocusObject || mFocusObject->isDead())
1412 {
1413 obj_min_distance = 0.f;
1414 return TRUE;
1415 }
1416
1417 if (mFocusObject->mDrawable.isNull())
1418 {
1419#ifdef LL_RELEASE_FOR_DOWNLOAD
1420 llwarns << "Focus object with no drawable!" << llendl;
1421#else
1422 mFocusObject->dump();
1423 llerrs << "Focus object with no drawable!" << llendl;
1424#endif
1425 obj_min_distance = 0.f;
1426 return TRUE;
1427 }
1428
1429 LLQuaternion inv_object_rot = ~mFocusObject->getRenderRotation();
1430 LLVector3 target_offset_origin = mFocusObjectOffset;
1431 LLVector3 camera_offset_target(getCameraPositionAgent() - getPosAgentFromGlobal(mFocusTargetGlobal));
1432
1433 // convert offsets into object local space
1434 camera_offset_target.rotVec(inv_object_rot);
1435 target_offset_origin.rotVec(inv_object_rot);
1436
1437 // push around object extents based on target offset
1438 LLVector3 object_extents = mFocusObject->getScale();
1439 if (mFocusObject->isAvatar())
1440 {
1441 // fudge factors that lets you zoom in on avatars a bit more (which don't do FOV zoom)
1442 object_extents.mV[VX] *= AVATAR_ZOOM_MIN_X_FACTOR;
1443 object_extents.mV[VY] *= AVATAR_ZOOM_MIN_Y_FACTOR;
1444 object_extents.mV[VZ] *= AVATAR_ZOOM_MIN_Z_FACTOR;
1445 soft_limit = TRUE;
1446 }
1447 LLVector3 abs_target_offset = target_offset_origin;
1448 abs_target_offset.abs();
1449
1450 LLVector3 target_offset_dir = target_offset_origin;
1451 F32 object_radius = mFocusObject->getVObjRadius();
1452
1453 BOOL target_outside_object_extents = FALSE;
1454
1455 for (U32 i = VX; i <= VZ; i++)
1456 {
1457 if (abs_target_offset.mV[i] * 2.f > object_extents.mV[i] + OBJECT_EXTENTS_PADDING)
1458 {
1459 target_outside_object_extents = TRUE;
1460 }
1461 if (camera_offset_target.mV[i] > 0.f)
1462 {
1463 object_extents.mV[i] -= target_offset_origin.mV[i] * 2.f;
1464 }
1465 else
1466 {
1467 object_extents.mV[i] += target_offset_origin.mV[i] * 2.f;
1468 }
1469 }
1470
1471 // don't shrink the object extents so far that the object inverts
1472 object_extents.clamp(0.001f, F32_MAX);
1473
1474 // move into first octant
1475 LLVector3 camera_offset_target_abs_norm = camera_offset_target;
1476 camera_offset_target_abs_norm.abs();
1477 // make sure offset is non-zero
1478 camera_offset_target_abs_norm.clamp(0.001f, F32_MAX);
1479 camera_offset_target_abs_norm.normVec();
1480
1481 // find camera position relative to normalized object extents
1482 LLVector3 camera_offset_target_scaled = camera_offset_target_abs_norm;
1483 camera_offset_target_scaled.mV[VX] /= object_extents.mV[VX];
1484 camera_offset_target_scaled.mV[VY] /= object_extents.mV[VY];
1485 camera_offset_target_scaled.mV[VZ] /= object_extents.mV[VZ];
1486
1487 if (camera_offset_target_scaled.mV[VX] > camera_offset_target_scaled.mV[VY] &&
1488 camera_offset_target_scaled.mV[VX] > camera_offset_target_scaled.mV[VZ])
1489 {
1490 if (camera_offset_target_abs_norm.mV[VX] < 0.001f)
1491 {
1492 obj_min_distance = object_extents.mV[VX] * 0.5f;
1493 }
1494 else
1495 {
1496 obj_min_distance = object_extents.mV[VX] * 0.5f / camera_offset_target_abs_norm.mV[VX];
1497 }
1498 }
1499 else if (camera_offset_target_scaled.mV[VY] > camera_offset_target_scaled.mV[VZ])
1500 {
1501 if (camera_offset_target_abs_norm.mV[VY] < 0.001f)
1502 {
1503 obj_min_distance = object_extents.mV[VY] * 0.5f;
1504 }
1505 else
1506 {
1507 obj_min_distance = object_extents.mV[VY] * 0.5f / camera_offset_target_abs_norm.mV[VY];
1508 }
1509 }
1510 else
1511 {
1512 if (camera_offset_target_abs_norm.mV[VZ] < 0.001f)
1513 {
1514 obj_min_distance = object_extents.mV[VZ] * 0.5f;
1515 }
1516 else
1517 {
1518 obj_min_distance = object_extents.mV[VZ] * 0.5f / camera_offset_target_abs_norm.mV[VZ];
1519 }
1520 }
1521
1522 LLVector3 object_split_axis;
1523 LLVector3 target_offset_scaled = target_offset_origin;
1524 target_offset_scaled.abs();
1525 target_offset_scaled.normVec();
1526 target_offset_scaled.mV[VX] /= object_extents.mV[VX];
1527 target_offset_scaled.mV[VY] /= object_extents.mV[VY];
1528 target_offset_scaled.mV[VZ] /= object_extents.mV[VZ];
1529
1530 if (target_offset_scaled.mV[VX] > target_offset_scaled.mV[VY] &&
1531 target_offset_scaled.mV[VX] > target_offset_scaled.mV[VZ])
1532 {
1533 object_split_axis = LLVector3::x_axis;
1534 }
1535 else if (target_offset_scaled.mV[VY] > target_offset_scaled.mV[VZ])
1536 {
1537 object_split_axis = LLVector3::y_axis;
1538 }
1539 else
1540 {
1541 object_split_axis = LLVector3::z_axis;
1542 }
1543
1544 LLVector3 camera_offset_object(getCameraPositionAgent() - mFocusObject->getPositionAgent());
1545
1546 // length projected orthogonal to target offset
1547 F32 camera_offset_dist = (camera_offset_object - target_offset_dir * (camera_offset_object * target_offset_dir)).magVec();
1548
1549 // calculate whether the target point would be "visible" if it were outside the bounding box
1550 // on the opposite of the splitting plane defined by object_split_axis;
1551 BOOL exterior_target_visible = FALSE;
1552 if (camera_offset_dist > object_radius)
1553 {
1554 // target is visible from camera, so turn off fov zoom
1555 exterior_target_visible = TRUE;
1556 }
1557
1558 F32 camera_offset_clip = camera_offset_object * object_split_axis;
1559 F32 target_offset_clip = target_offset_dir * object_split_axis;
1560
1561 // target has moved outside of object extents
1562 // check to see if camera and target are on same side
1563 if (target_outside_object_extents)
1564 {
1565 if (camera_offset_clip > 0.f && target_offset_clip > 0.f)
1566 {
1567 return FALSE;
1568 }
1569 else if (camera_offset_clip < 0.f && target_offset_clip < 0.f)
1570 {
1571 return FALSE;
1572 }
1573 }
1574
1575 // clamp obj distance to diagonal of 10 by 10 cube
1576 obj_min_distance = llmin(obj_min_distance, 10.f * F_SQRT3);
1577
1578 obj_min_distance += gCamera->getNear() + (soft_limit ? 0.1f : 0.2f);
1579
1580 return TRUE;
1581}
1582
1583F32 LLAgent::getCameraZoomFraction()
1584{
1585 // 0.f -> camera zoomed all the way out
1586 // 1.f -> camera zoomed all the way in
1587 if (gSelectMgr->getObjectCount() && gSelectMgr->getSelectType() == SELECT_TYPE_HUD)
1588 {
1589 // already [0,1]
1590 return mAvatarObject->mHUDTargetZoom;
1591 }
1592 else if (mFocusOnAvatar && cameraThirdPerson())
1593 {
1594 return clamp_rescale(mCameraZoomFraction, MIN_ZOOM_FRACTION, MAX_ZOOM_FRACTION, 1.f, 0.f);
1595 }
1596 else if (cameraCustomizeAvatar())
1597 {
1598 F32 distance = (F32)mCameraFocusOffsetTarget.magVec();
1599 return clamp_rescale(distance, APPEARANCE_MIN_ZOOM, APPEARANCE_MAX_ZOOM, 1.f, 0.f );
1600 }
1601 else
1602 {
1603 F32 min_zoom;
1604 const F32 DIST_FUDGE = 16.f; // meters
1605 F32 max_zoom = gWorldPointer ? llmin(mDrawDistance - DIST_FUDGE,
1606 gWorldPointer->getRegionWidthInMeters() - DIST_FUDGE,
1607 MAX_CAMERA_DISTANCE_FROM_AGENT) : MAX_CAMERA_DISTANCE_FROM_AGENT;
1608
1609 F32 distance = (F32)mCameraFocusOffsetTarget.magVec();
1610 if (mFocusObject.notNull())
1611 {
1612 if (mFocusObject->isAvatar())
1613 {
1614 min_zoom = AVATAR_MIN_ZOOM;
1615 }
1616 else
1617 {
1618 min_zoom = OBJECT_MIN_ZOOM;
1619 }
1620 }
1621 else
1622 {
1623 min_zoom = LAND_MIN_ZOOM;
1624 }
1625
1626 return clamp_rescale(distance, min_zoom, max_zoom, 1.f, 0.f);
1627 }
1628}
1629
1630void LLAgent::setCameraZoomFraction(F32 fraction)
1631{
1632 // 0.f -> camera zoomed all the way out
1633 // 1.f -> camera zoomed all the way in
1634 if (gSelectMgr->getObjectCount() && gSelectMgr->getSelectType() == SELECT_TYPE_HUD)
1635 {
1636 mAvatarObject->mHUDTargetZoom = fraction;
1637 }
1638 else if (mFocusOnAvatar && cameraThirdPerson())
1639 {
1640 mCameraZoomFraction = rescale(fraction, 0.f, 1.f, MAX_ZOOM_FRACTION, MIN_ZOOM_FRACTION);
1641 }
1642 else if (cameraCustomizeAvatar())
1643 {
1644 LLVector3d camera_offset_dir = mCameraFocusOffsetTarget;
1645 camera_offset_dir.normVec();
1646 mCameraFocusOffsetTarget = camera_offset_dir * rescale(fraction, 0.f, 1.f, APPEARANCE_MAX_ZOOM, APPEARANCE_MIN_ZOOM);
1647 }
1648 else
1649 {
1650 F32 min_zoom = LAND_MIN_ZOOM;
1651 const F32 DIST_FUDGE = 16.f; // meters
1652 F32 max_zoom = llmin(mDrawDistance - DIST_FUDGE,
1653 gWorldPointer->getRegionWidthInMeters() - DIST_FUDGE,
1654 MAX_CAMERA_DISTANCE_FROM_AGENT);
1655
1656 if (mFocusObject.notNull())
1657 {
1658 if (mFocusObject.notNull())
1659 {
1660 if (mFocusObject->isAvatar())
1661 {
1662 min_zoom = AVATAR_MIN_ZOOM;
1663 }
1664 else
1665 {
1666 min_zoom = OBJECT_MIN_ZOOM;
1667 }
1668 }
1669 }
1670
1671 LLVector3d camera_offset_dir = mCameraFocusOffsetTarget;
1672 camera_offset_dir.normVec();
1673 mCameraFocusOffsetTarget = camera_offset_dir * rescale(fraction, 0.f, 1.f, max_zoom, min_zoom);
1674 }
1675 startCameraAnimation();
1676}
1677
1678
1679//-----------------------------------------------------------------------------
1680// cameraOrbitAround()
1681//-----------------------------------------------------------------------------
1682void LLAgent::cameraOrbitAround(const F32 radians)
1683{
1684 if (gSelectMgr->getObjectCount() && gSelectMgr->getSelectType() == SELECT_TYPE_HUD)
1685 {
1686 // do nothing for hud selection
1687 }
1688 else if (mFocusOnAvatar && (mCameraMode == CAMERA_MODE_THIRD_PERSON || mCameraMode == CAMERA_MODE_FOLLOW))
1689 {
1690 mFrameAgent.rotate(radians, getReferenceUpVector());
1691 }
1692 else
1693 {
1694 mCameraFocusOffsetTarget.rotVec(radians, 0.f, 0.f, 1.f);
1695
1696 cameraZoomIn(1.f);
1697 }
1698}
1699
1700
1701//-----------------------------------------------------------------------------
1702// cameraOrbitOver()
1703//-----------------------------------------------------------------------------
1704void LLAgent::cameraOrbitOver(const F32 angle)
1705{
1706 if (gSelectMgr->getObjectCount() && gSelectMgr->getSelectType() == SELECT_TYPE_HUD)
1707 {
1708 // do nothing for hud selection
1709 }
1710 else if (mFocusOnAvatar && mCameraMode == CAMERA_MODE_THIRD_PERSON)
1711 {
1712 pitch(angle);
1713 }
1714 else
1715 {
1716 LLVector3 camera_offset_unit(mCameraFocusOffsetTarget);
1717 camera_offset_unit.normVec();
1718
1719 F32 angle_from_up = acos( camera_offset_unit * getReferenceUpVector() );
1720
1721 LLVector3d left_axis;
1722 left_axis.setVec(gCamera->getLeftAxis());
1723 F32 new_angle = llclamp(angle_from_up - angle, 1.f * DEG_TO_RAD, 179.f * DEG_TO_RAD);
1724 mCameraFocusOffsetTarget.rotVec(angle_from_up - new_angle, left_axis);
1725
1726 cameraZoomIn(1.f);
1727 }
1728}
1729
1730//-----------------------------------------------------------------------------
1731// cameraZoomIn()
1732//-----------------------------------------------------------------------------
1733void LLAgent::cameraZoomIn(const F32 fraction)
1734{
1735 if (gDisconnected)
1736 {
1737 return;
1738 }
1739
1740 if (gSelectMgr->getObjectCount() && gSelectMgr->getSelectType() == SELECT_TYPE_HUD)
1741 {
1742 // just update hud zoom level
1743 mAvatarObject->mHUDTargetZoom /= fraction;
1744 return;
1745 }
1746
1747
1748 LLVector3d camera_offset(mCameraFocusOffsetTarget);
1749 LLVector3d camera_offset_unit(mCameraFocusOffsetTarget);
1750 F32 min_zoom = LAND_MIN_ZOOM;
1751 F32 current_distance = (F32)camera_offset_unit.normVec();
1752 F32 new_distance = current_distance * fraction;
1753
1754 // Don't move through focus point
1755 if (mFocusObject)
1756 {
1757 LLVector3 camera_offset_dir((F32)camera_offset_unit.mdV[VX], (F32)camera_offset_unit.mdV[VY], (F32)camera_offset_unit.mdV[VZ]);
1758
1759 if (mFocusObject->isAvatar())
1760 {
1761 calcCameraMinDistance(min_zoom);
1762 }
1763 else
1764 {
1765 min_zoom = OBJECT_MIN_ZOOM;
1766 }
1767 }
1768
1769 new_distance = llmax(new_distance, min_zoom);
1770
1771 // Don't zoom too far back
1772 const F32 DIST_FUDGE = 16.f; // meters
1773 F32 max_distance = llmin(mDrawDistance - DIST_FUDGE,
1774 gWorldPointer->getRegionWidthInMeters() - DIST_FUDGE );
1775
1776 if (new_distance > max_distance)
1777 {
1778 new_distance = max_distance;
1779
1780 /*
1781 // Unless camera is unlocked
1782 if (!LLViewerCamera::sDisableCameraConstraints)
1783 {
1784 return;
1785 }
1786 */
1787 }
1788
1789 if( cameraCustomizeAvatar() )
1790 {
1791 new_distance = llclamp( new_distance, APPEARANCE_MIN_ZOOM, APPEARANCE_MAX_ZOOM );
1792 }
1793
1794 mCameraFocusOffsetTarget = new_distance * camera_offset_unit;
1795}
1796
1797//-----------------------------------------------------------------------------
1798// cameraOrbitIn()
1799//-----------------------------------------------------------------------------
1800void LLAgent::cameraOrbitIn(const F32 meters)
1801{
1802 if (mFocusOnAvatar && mCameraMode == CAMERA_MODE_THIRD_PERSON)
1803 {
1804 F32 camera_offset_dist = llmax(0.001f, mCameraOffsetDefault.magVec());
1805
1806 mCameraZoomFraction = (mTargetCameraDistance - meters) / camera_offset_dist;
1807
1808 if (!gSavedSettings.getBOOL("FreezeTime") && mCameraZoomFraction < MIN_ZOOM_FRACTION && meters > 0.f)
1809 {
1810 // No need to animate, camera is already there.
1811 changeCameraToMouselook(FALSE);
1812 }
1813
1814 mCameraZoomFraction = llclamp(mCameraZoomFraction, MIN_ZOOM_FRACTION, MAX_ZOOM_FRACTION);
1815 }
1816 else
1817 {
1818 LLVector3d camera_offset(mCameraFocusOffsetTarget);
1819 LLVector3d camera_offset_unit(mCameraFocusOffsetTarget);
1820 F32 current_distance = (F32)camera_offset_unit.normVec();
1821 F32 new_distance = current_distance - meters;
1822 F32 min_zoom = LAND_MIN_ZOOM;
1823
1824 // Don't move through focus point
1825 if (mFocusObject.notNull())
1826 {
1827 if (mFocusObject->isAvatar())
1828 {
1829 min_zoom = AVATAR_MIN_ZOOM;
1830 }
1831 else
1832 {
1833 min_zoom = OBJECT_MIN_ZOOM;
1834 }
1835 }
1836
1837 new_distance = llmax(new_distance, min_zoom);
1838
1839 // Don't zoom too far back
1840 const F32 DIST_FUDGE = 16.f; // meters
1841 F32 max_distance = llmin(mDrawDistance - DIST_FUDGE,
1842 gWorldPointer->getRegionWidthInMeters() - DIST_FUDGE );
1843
1844 if (new_distance > max_distance)
1845 {
1846 // Unless camera is unlocked
1847 if (!LLViewerCamera::sDisableCameraConstraints)
1848 {
1849 return;
1850 }
1851 }
1852
1853 if( CAMERA_MODE_CUSTOMIZE_AVATAR == getCameraMode() )
1854 {
1855 llclamp( new_distance, APPEARANCE_MIN_ZOOM, APPEARANCE_MAX_ZOOM );
1856 }
1857
1858 // Compute new camera offset
1859 mCameraFocusOffsetTarget = new_distance * camera_offset_unit;
1860 cameraZoomIn(1.f);
1861 }
1862}
1863
1864
1865//-----------------------------------------------------------------------------
1866// cameraPanIn()
1867//-----------------------------------------------------------------------------
1868void LLAgent::cameraPanIn(F32 meters)
1869{
1870 LLVector3d at_axis;
1871 at_axis.setVec(gCamera->getAtAxis());
1872
1873 mFocusTargetGlobal += meters * at_axis;
1874 mFocusGlobal = mFocusTargetGlobal;
1875 // don't enforce zoom constraints as this is the only way for users to get past them easily
1876 updateFocusOffset();
1877}
1878
1879//-----------------------------------------------------------------------------
1880// cameraPanLeft()
1881//-----------------------------------------------------------------------------
1882void LLAgent::cameraPanLeft(F32 meters)
1883{
1884 LLVector3d left_axis;
1885 left_axis.setVec(gCamera->getLeftAxis());
1886
1887 mFocusTargetGlobal += meters * left_axis;
1888 mFocusGlobal = mFocusTargetGlobal;
1889 cameraZoomIn(1.f);
1890 updateFocusOffset();
1891}
1892
1893//-----------------------------------------------------------------------------
1894// cameraPanUp()
1895//-----------------------------------------------------------------------------
1896void LLAgent::cameraPanUp(F32 meters)
1897{
1898 LLVector3d up_axis;
1899 up_axis.setVec(gCamera->getUpAxis());
1900
1901 mFocusTargetGlobal += meters * up_axis;
1902 mFocusGlobal = mFocusTargetGlobal;
1903 cameraZoomIn(1.f);
1904 updateFocusOffset();
1905}
1906
1907//-----------------------------------------------------------------------------
1908// setKey()
1909//-----------------------------------------------------------------------------
1910void LLAgent::setKey(const S32 direction, S32 &key)
1911{
1912 if (direction > 0)
1913 {
1914 key = 1;
1915 }
1916 else if (direction < 0)
1917 {
1918 key = -1;
1919 }
1920 else
1921 {
1922 key = 0;
1923 }
1924}
1925
1926
1927//-----------------------------------------------------------------------------
1928// getControlFlags()
1929//-----------------------------------------------------------------------------
1930U32 LLAgent::getControlFlags()
1931{
1932/*
1933 // HACK -- avoids maintenance of control flags when camera mode is turned on or off,
1934 // only worries about it when the flags are measured
1935 if (mCameraMode == CAMERA_MODE_MOUSELOOK)
1936 {
1937 if ( !(mControlFlags & AGENT_CONTROL_MOUSELOOK) )
1938 {
1939 mControlFlags |= AGENT_CONTROL_MOUSELOOK;
1940 }
1941 }
1942*/
1943 return mControlFlags;
1944}
1945
1946//-----------------------------------------------------------------------------
1947// setControlFlags()
1948//-----------------------------------------------------------------------------
1949void LLAgent::setControlFlags(U32 mask)
1950{
1951 mControlFlags |= mask;
1952 mbFlagsDirty = TRUE;
1953}
1954
1955
1956//-----------------------------------------------------------------------------
1957// clearControlFlags()
1958//-----------------------------------------------------------------------------
1959void LLAgent::clearControlFlags(U32 mask)
1960{
1961 U32 old_flags = mControlFlags;
1962 mControlFlags &= ~mask;
1963 if (old_flags != mControlFlags)
1964 {
1965 mbFlagsDirty = TRUE;
1966 }
1967}
1968
1969//-----------------------------------------------------------------------------
1970// controlFlagsDirty()
1971//-----------------------------------------------------------------------------
1972BOOL LLAgent::controlFlagsDirty() const
1973{
1974 return mbFlagsDirty;
1975}
1976
1977//-----------------------------------------------------------------------------
1978// enableControlFlagReset()
1979//-----------------------------------------------------------------------------
1980void LLAgent::enableControlFlagReset()
1981{
1982 mbFlagsNeedReset = TRUE;
1983}
1984
1985//-----------------------------------------------------------------------------
1986// resetControlFlags()
1987//-----------------------------------------------------------------------------
1988void LLAgent::resetControlFlags()
1989{
1990 if (mbFlagsNeedReset)
1991 {
1992 mbFlagsNeedReset = FALSE;
1993 mbFlagsDirty = FALSE;
1994 // reset all of the ephemeral flags
1995 // some flags are managed elsewhere
1996 mControlFlags &= AGENT_CONTROL_AWAY | AGENT_CONTROL_FLY | AGENT_CONTROL_MOUSELOOK;
1997 }
1998}
1999
2000//-----------------------------------------------------------------------------
2001// setAFK()
2002//-----------------------------------------------------------------------------
2003void LLAgent::setAFK()
2004{
2005 // Drones can't go AFK
2006 if (gNoRender)
2007 {
2008 return;
2009 }
2010
2011 if (!gAllowAFK)
2012 {
2013 return;
2014 }
2015
2016 if (!gAgent.getRegion())
2017 {
2018 // Don't set AFK if we're not talking to a region yet.
2019 return;
2020 }
2021
2022 if (!(mControlFlags & AGENT_CONTROL_AWAY))
2023 {
2024 sendAnimationRequest(ANIM_AGENT_AWAY, ANIM_REQUEST_START);
2025 setControlFlags(AGENT_CONTROL_AWAY | AGENT_CONTROL_STOP);
2026 gAwayTimer.start();
2027 if (gAFKMenu)
2028 {
2029 gAFKMenu->setLabel("Set Not Away");
2030 }
2031 }
2032}
2033
2034//-----------------------------------------------------------------------------
2035// clearAFK()
2036//-----------------------------------------------------------------------------
2037void LLAgent::clearAFK()
2038{
2039 gAwayTriggerTimer.reset();
2040
2041 // Gods can sometimes get into away state (via gestures)
2042 // without setting the appropriate control flag. JC
2043 LLVOAvatar* av = mAvatarObject;
2044 if (mControlFlags & AGENT_CONTROL_AWAY
2045 || (av
2046 && (av->mSignaledAnimations.find(ANIM_AGENT_AWAY) != av->mSignaledAnimations.end())))
2047 {
2048 sendAnimationRequest(ANIM_AGENT_AWAY, ANIM_REQUEST_STOP);
2049 clearControlFlags(AGENT_CONTROL_AWAY);
2050 if (gAFKMenu)
2051 {
2052 gAFKMenu->setLabel("Set Away");
2053 }
2054 }
2055}
2056
2057//-----------------------------------------------------------------------------
2058// getAFK()
2059//-----------------------------------------------------------------------------
2060BOOL LLAgent::getAFK() const
2061{
2062 return (mControlFlags & AGENT_CONTROL_AWAY) != 0;
2063}
2064
2065//-----------------------------------------------------------------------------
2066// setBusy()
2067//-----------------------------------------------------------------------------
2068void LLAgent::setBusy()
2069{
2070 sendAnimationRequest(ANIM_AGENT_BUSY, ANIM_REQUEST_START);
2071 mIsBusy = TRUE;
2072 if (gBusyMenu)
2073 {
2074 gBusyMenu->setLabel("Set Not Busy");
2075 }
2076 if (gFloaterMute)
2077 {
2078 gFloaterMute->updateButtons();
2079 }
2080}
2081
2082//-----------------------------------------------------------------------------
2083// clearBusy()
2084//-----------------------------------------------------------------------------
2085void LLAgent::clearBusy()
2086{
2087 mIsBusy = FALSE;
2088 sendAnimationRequest(ANIM_AGENT_BUSY, ANIM_REQUEST_STOP);
2089 if (gBusyMenu)
2090 {
2091 gBusyMenu->setLabel("Set Busy");
2092 }
2093 if (gFloaterMute)
2094 {
2095 gFloaterMute->updateButtons();
2096 }
2097}
2098
2099//-----------------------------------------------------------------------------
2100// getBusy()
2101//-----------------------------------------------------------------------------
2102BOOL LLAgent::getBusy() const
2103{
2104 return mIsBusy;
2105}
2106
2107
2108//-----------------------------------------------------------------------------
2109// updateWanderTarget()
2110//-----------------------------------------------------------------------------
2111void LLAgent::updateWanderTarget()
2112{
2113 S32 num_regions;
2114 LLViewerRegion* rand_region;
2115 F32 rand_x;
2116 F32 rand_y;
2117
2118 if (mWanderTimer.checkExpirationAndReset(frand(MAX_WANDER_TIME)))
2119 {
2120 // Pick a random spot to wander towards
2121 num_regions = gWorldPointer->mActiveRegionList.getLength();
2122 S32 region_num = llround(frand(1.f) * num_regions);
2123 rand_region = gWorldPointer->mActiveRegionList.getFirstData();
2124 S32 i = 0;
2125 while (i < region_num)
2126 {
2127 rand_region = gWorldPointer->mActiveRegionList.getNextData();
2128 i++;
2129 }
2130 rand_x = frand(rand_region->getWidth());
2131 rand_y = frand(rand_region->getWidth());
2132
2133 stopAutoPilot();
2134 startAutoPilotGlobal(rand_region->getPosGlobalFromRegion(LLVector3(rand_x, rand_y, 0.f)));
2135 }
2136}
2137
2138//-----------------------------------------------------------------------------
2139// startAutoPilotGlobal()
2140//-----------------------------------------------------------------------------
2141void 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)
2142{
2143 if (!gAgent.getAvatarObject() || !gWorldPointer)
2144 {
2145 return;
2146 }
2147
2148 mAutoPilotFinishedCallback = finish_callback;
2149 mAutoPilotCallbackData = callback_data;
2150 mAutoPilotRotationThreshold = rot_threshold;
2151 mAutoPilotBehaviorName = behavior_name;
2152
2153 LLVector3d delta_pos( target_global );
2154 delta_pos -= getPositionGlobal();
2155 F64 distance = delta_pos.magVec();
2156 LLVector3d trace_target = target_global;
2157
2158 trace_target.mdV[VZ] -= 10.f;
2159
2160 LLVector3d intersection;
2161 LLVector3 normal;
2162 LLViewerObject *hit_obj;
2163 F32 heightDelta = gWorldPointer->resolveStepHeightGlobal(NULL, target_global, trace_target, intersection, normal, &hit_obj);
2164
2165 if (stop_distance > 0.f)
2166 {
2167 mAutoPilotStopDistance = stop_distance;
2168 }
2169 else
2170 {
2171 // Guess at a reasonable stop distance.
2172 mAutoPilotStopDistance = fsqrtf( distance );
2173 if (mAutoPilotStopDistance < 0.5f)
2174 {
2175 mAutoPilotStopDistance = 0.5f;
2176 }
2177 }
2178
2179 mAutoPilotFlyOnStop = getFlying();
2180
2181 if (distance > 30.0)
2182 {
2183 setFlying(TRUE);
2184 }
2185
2186 if ( distance > 1.f && heightDelta > (sqrtf(mAutoPilotStopDistance) + 1.f))
2187 {
2188 setFlying(TRUE);
2189 mAutoPilotFlyOnStop = TRUE;
2190 }
2191
2192 mAutoPilot = TRUE;
2193 mAutoPilotTargetGlobal = target_global;
2194
2195 // trace ray down to find height of destination from ground
2196 LLVector3d traceEndPt = target_global;
2197 traceEndPt.mdV[VZ] -= 20.f;
2198
2199 LLVector3d targetOnGround;
2200 LLVector3 groundNorm;
2201 LLViewerObject *obj;
2202
2203 gWorldPointer->resolveStepHeightGlobal(NULL, target_global, traceEndPt, targetOnGround, groundNorm, &obj);
2204 F64 target_height = llmax((F64)gAgent.getAvatarObject()->getPelvisToFoot(), target_global.mdV[VZ] - targetOnGround.mdV[VZ]);
2205
2206 // clamp z value of target to minimum height above ground
2207 mAutoPilotTargetGlobal.mdV[VZ] = targetOnGround.mdV[VZ] + target_height;
2208 mAutoPilotTargetDist = (F32)dist_vec(gAgent.getPositionGlobal(), mAutoPilotTargetGlobal);
2209 if (target_rotation)
2210 {
2211 mAutoPilotUseRotation = TRUE;
2212 mAutoPilotTargetFacing = LLVector3::x_axis * *target_rotation;
2213 mAutoPilotTargetFacing.mV[VZ] = 0.f;
2214 mAutoPilotTargetFacing.normVec();
2215 }
2216 else
2217 {
2218 mAutoPilotUseRotation = FALSE;
2219 }
2220
2221 mAutoPilotNoProgressFrameCount = 0;
2222}
2223
2224
2225//-----------------------------------------------------------------------------
2226// startFollowPilot()
2227//-----------------------------------------------------------------------------
2228void LLAgent::startFollowPilot(const LLUUID &leader_id)
2229{
2230 if (!mAutoPilot) return;
2231
2232 mLeaderID = leader_id;
2233 if ( mLeaderID.isNull() ) return;
2234
2235 LLViewerObject* object = gObjectList.findObject(mLeaderID);
2236 if (!object)
2237 {
2238 mLeaderID = LLUUID::null;
2239 return;
2240 }
2241
2242 startAutoPilotGlobal(object->getPositionGlobal());
2243}
2244
2245
2246//-----------------------------------------------------------------------------
2247// stopAutoPilot()
2248//-----------------------------------------------------------------------------
2249void LLAgent::stopAutoPilot(BOOL user_cancel)
2250{
2251 if (mAutoPilot)
2252 {
2253 mAutoPilot = FALSE;
2254 if (mAutoPilotUseRotation && !user_cancel)
2255 {
2256 resetAxes(mAutoPilotTargetFacing);
2257 }
2258 //NB: auto pilot can terminate for a reason other than reaching the destination
2259 //TODO: enforce rotation constraint here as well
2260 if (mAutoPilotFinishedCallback &&
2261 ((mAutoPilotTargetDist < mAutoPilotStopDistance) || (mAutoPilotNoProgressFrameCount > AUTOPILOT_MAX_TIME_NO_PROGRESS * gFPSClamped)))
2262 {
2263 mAutoPilotFinishedCallback(!user_cancel && dist_vec(gAgent.getPositionGlobal(), mAutoPilotTargetGlobal) < mAutoPilotTargetDist, mAutoPilotCallbackData);
2264 }
2265 mLeaderID = LLUUID::null;
2266
2267 // If the user cancelled, don't change the fly state
2268 if (!user_cancel)
2269 {
2270 setFlying(mAutoPilotFlyOnStop);
2271 }
2272 setControlFlags(AGENT_CONTROL_STOP);
2273
2274 if (user_cancel && !mAutoPilotBehaviorName.empty())
2275 {
2276 if (mAutoPilotBehaviorName == "Sit")
2277 LLNotifyBox::showXml("CancelledSit");
2278 else if (mAutoPilotBehaviorName == "Attach")
2279 LLNotifyBox::showXml("CancelledAttach");
2280 else
2281 LLNotifyBox::showXml("Cancelled");
2282 }
2283 }
2284}
2285
2286
2287// Returns necessary agent pitch and yaw changes, radians.
2288//-----------------------------------------------------------------------------
2289// autoPilot()
2290//-----------------------------------------------------------------------------
2291void LLAgent::autoPilot(F32 *delta_yaw)
2292{
2293 if (mAutoPilot)
2294 {
2295 if (!mLeaderID.isNull())
2296 {
2297 LLViewerObject* object = gObjectList.findObject(mLeaderID);
2298 if (!object)
2299 {
2300 stopAutoPilot();
2301 return;
2302 }
2303 mAutoPilotTargetGlobal = object->getPositionGlobal();
2304 }
2305
2306 if (!mAvatarObject)
2307 {
2308 return;
2309 }
2310
2311 if (mAvatarObject->mInAir)
2312 {
2313 setFlying(TRUE);
2314 }
2315
2316 LLVector3 at;
2317 at.setVec(mFrameAgent.getAtAxis());
2318 LLVector3 target_agent = getPosAgentFromGlobal(mAutoPilotTargetGlobal);
2319 LLVector3 direction = target_agent - getPositionAgent();
2320
2321 F32 target_dist = direction.magVec();
2322
2323 if (target_dist >= mAutoPilotTargetDist)
2324 {
2325 mAutoPilotNoProgressFrameCount++;
2326 if (mAutoPilotNoProgressFrameCount > AUTOPILOT_MAX_TIME_NO_PROGRESS * gFPSClamped)
2327 {
2328 stopAutoPilot();
2329 return;
2330 }
2331 }
2332
2333 mAutoPilotTargetDist = target_dist;
2334
2335 // Make this a two-dimensional solution
2336 at.mV[VZ] = 0.f;
2337 direction.mV[VZ] = 0.f;
2338
2339 at.normVec();
2340 F32 xy_distance = direction.normVec();
2341
2342 F32 yaw = 0.f;
2343 if (mAutoPilotTargetDist > mAutoPilotStopDistance)
2344 {
2345 yaw = angle_between(mFrameAgent.getAtAxis(), direction);
2346 }
2347 else if (mAutoPilotUseRotation)
2348 {
2349 // we're close now just aim at target facing
2350 yaw = angle_between(at, mAutoPilotTargetFacing);
2351 direction = mAutoPilotTargetFacing;
2352 }
2353
2354 yaw = 4.f * yaw / gFPSClamped;
2355
2356 // figure out which direction to turn
2357 LLVector3 scratch(at % direction);
2358
2359 if (scratch.mV[VZ] > 0.f)
2360 {
2361 setControlFlags(AGENT_CONTROL_YAW_POS);
2362 }
2363 else
2364 {
2365 yaw = -yaw;
2366 setControlFlags(AGENT_CONTROL_YAW_NEG);
2367 }
2368
2369 *delta_yaw = yaw;
2370
2371 // Compute when to start slowing down and when to stop
2372 F32 stop_distance = mAutoPilotStopDistance;
2373 F32 slow_distance;
2374 if (getFlying())
2375 {
2376 slow_distance = llmax(6.f, mAutoPilotStopDistance + 5.f);
2377 stop_distance = llmax(2.f, mAutoPilotStopDistance);
2378 }
2379 else
2380 {
2381 slow_distance = llmax(3.f, mAutoPilotStopDistance + 2.f);
2382 }
2383
2384 // If we're flying, handle autopilot points above or below you.
2385 if (getFlying() && xy_distance < AUTOPILOT_HEIGHT_ADJUST_DISTANCE)
2386 {
2387 if (mAvatarObject)
2388 {
2389 F64 current_height = mAvatarObject->getPositionGlobal().mdV[VZ];
2390 F32 delta_z = (F32)(mAutoPilotTargetGlobal.mdV[VZ] - current_height);
2391 F32 slope = delta_z / xy_distance;
2392 if (slope > 0.45f && delta_z > 6.f)
2393 {
2394 setControlFlags(AGENT_CONTROL_FAST_UP | AGENT_CONTROL_UP_POS);
2395 }
2396 else if (slope > 0.002f && delta_z > 0.5f)
2397 {
2398 setControlFlags(AGENT_CONTROL_UP_POS);
2399 }
2400 else if (slope < -0.45f && delta_z < -6.f && current_height > AUTOPILOT_MIN_TARGET_HEIGHT_OFF_GROUND)
2401 {
2402 setControlFlags(AGENT_CONTROL_FAST_UP | AGENT_CONTROL_UP_NEG);
2403 }
2404 else if (slope < -0.002f && delta_z < -0.5f && current_height > AUTOPILOT_MIN_TARGET_HEIGHT_OFF_GROUND)
2405 {
2406 setControlFlags(AGENT_CONTROL_UP_NEG);
2407 }
2408 }
2409 }
2410
2411 // calculate delta rotation to target heading
2412 F32 delta_target_heading = angle_between(mFrameAgent.getAtAxis(), mAutoPilotTargetFacing);
2413
2414 if (xy_distance > slow_distance && yaw < (F_PI / 10.f))
2415 {
2416 // walking/flying fast
2417 setControlFlags(AGENT_CONTROL_FAST_AT | AGENT_CONTROL_AT_POS);
2418 }
2419 else if (mAutoPilotTargetDist > mAutoPilotStopDistance)
2420 {
2421 // walking/flying slow
2422 if (at * direction > 0.9f)
2423 {
2424 setControlFlags(AGENT_CONTROL_AT_POS);
2425 }
2426 else if (at * direction < -0.9f)
2427 {
2428 setControlFlags(AGENT_CONTROL_AT_NEG);
2429 }
2430 }
2431
2432 // check to see if we need to keep rotating to target orientation
2433 if (mAutoPilotTargetDist < mAutoPilotStopDistance)
2434 {
2435 setControlFlags(AGENT_CONTROL_STOP);
2436 if(!mAutoPilotUseRotation || (delta_target_heading < mAutoPilotRotationThreshold))
2437 {
2438 stopAutoPilot();
2439 }
2440 }
2441 }
2442}
2443
2444
2445//-----------------------------------------------------------------------------
2446// propagate()
2447//-----------------------------------------------------------------------------
2448void LLAgent::propagate(const F32 dt)
2449{
2450 // Update UI based on agent motion
2451 LLFloaterMove *floater_move = LLFloaterMove::getInstance();
2452 if (floater_move)
2453 {
2454 floater_move->mForwardButton ->setToggleState( mAtKey > 0 || mWalkKey > 0 );
2455 floater_move->mBackwardButton ->setToggleState( mAtKey < 0 || mWalkKey < 0 );
2456 floater_move->mSlideLeftButton ->setToggleState( mLeftKey > 0 );
2457 floater_move->mSlideRightButton->setToggleState( mLeftKey < 0 );
2458 floater_move->mTurnLeftButton ->setToggleState( mYawKey > 0.f );
2459 floater_move->mTurnRightButton ->setToggleState( mYawKey < 0.f );
2460 floater_move->mMoveUpButton ->setToggleState( mUpKey > 0 );
2461 floater_move->mMoveDownButton ->setToggleState( mUpKey < 0 );
2462 }
2463
2464 // handle rotation based on keyboard levels
2465 const F32 YAW_RATE = 90.f * DEG_TO_RAD; // radians per second
2466 yaw( YAW_RATE * mYawKey * dt );
2467
2468 const F32 PITCH_RATE = 90.f * DEG_TO_RAD; // radians per second
2469 pitch(PITCH_RATE * (F32) mPitchKey * dt);
2470
2471 // handle auto-land behavior
2472 if (mAvatarObject)
2473 {
2474 BOOL in_air = mAvatarObject->mInAir;
2475 LLVector3 land_vel = getVelocity();
2476 land_vel.mV[VZ] = 0.f;
2477
2478 if (!in_air
2479 && mUpKey < 0
2480 && land_vel.magVecSquared() < MAX_VELOCITY_AUTO_LAND_SQUARED
2481 && gSavedSettings.getBOOL("AutomaticFly"))
2482 {
2483 // land automatically
2484 setFlying(FALSE);
2485 }
2486 }
2487
2488 // clear keys
2489 mAtKey = 0;
2490 mWalkKey = 0;
2491 mLeftKey = 0;
2492 mUpKey = 0;
2493 mYawKey = 0.f;
2494 mPitchKey = 0;
2495}
2496
2497//-----------------------------------------------------------------------------
2498// updateAgentPosition()
2499//-----------------------------------------------------------------------------
2500void LLAgent::updateAgentPosition(const F32 dt, const F32 yaw_radians, const S32 mouse_x, const S32 mouse_y)
2501{
2502 propagate(dt);
2503
2504 // static S32 cameraUpdateCount = 0;
2505
2506 rotate(yaw_radians, 0, 0, 1);
2507
2508 //
2509 // Check for water and land collision, set underwater flag
2510 //
2511
2512 updateLookAt(mouse_x, mouse_y);
2513}
2514
2515//-----------------------------------------------------------------------------
2516// updateLookAt()
2517//-----------------------------------------------------------------------------
2518void LLAgent::updateLookAt(const S32 mouse_x, const S32 mouse_y)
2519{
2520 static LLVector3 last_at_axis;
2521
2522
2523 if ( mAvatarObject.isNull() )
2524 {
2525 return;
2526 }
2527
2528 LLQuaternion av_inv_rot = ~mAvatarObject->mRoot.getWorldRotation();
2529 LLVector3 root_at = LLVector3::x_axis * mAvatarObject->mRoot.getWorldRotation();
2530
2531 if ((gViewerWindow->getMouseVelocityStat()->getCurrent() < 0.01f) &&
2532 (root_at * last_at_axis > 0.95f ))
2533 {
2534 LLVector3 vel = mAvatarObject->getVelocity();
2535 if (vel.magVecSquared() > 4.f)
2536 {
2537 setLookAt(LOOKAT_TARGET_IDLE, mAvatarObject, vel * av_inv_rot);
2538 }
2539 else
2540 {
2541 // *FIX: rotate mframeagent by sit object's rotation?
2542 LLQuaternion look_rotation = mAvatarObject->mIsSitting ? mAvatarObject->getRenderRotation() : mFrameAgent.getQuaternion(); // use camera's current rotation
2543 LLVector3 look_offset = LLVector3(2.f, 0.f, 0.f) * look_rotation * av_inv_rot;
2544 setLookAt(LOOKAT_TARGET_IDLE, mAvatarObject, look_offset);
2545 }
2546 last_at_axis = root_at;
2547 return;
2548 }
2549
2550 last_at_axis = root_at;
2551
2552 if (CAMERA_MODE_CUSTOMIZE_AVATAR == getCameraMode())
2553 {
2554 setLookAt(LOOKAT_TARGET_NONE, mAvatarObject, LLVector3(-2.f, 0.f, 0.f));
2555 }
2556 else
2557 {
2558 // Move head based on cursor position
2559 ELookAtType lookAtType = LOOKAT_TARGET_NONE;
2560 LLVector3 headLookAxis;
2561 LLCoordFrame frameCamera = *((LLCoordFrame*)gCamera);
2562
2563 F32 x_from_center = mouse_x_from_center( mouse_x ); // range from -0.5 to 0.5
2564 F32 y_from_center = mouse_y_from_center( mouse_y ); // range from -0.5 to 0.5
2565
2566 if (cameraMouselook())
2567 {
2568 lookAtType = LOOKAT_TARGET_MOUSELOOK;
2569 }
2570 else if (cameraThirdPerson())
2571 {
2572 frameCamera.yaw( - x_from_center * gSavedSettings.getF32("YawFromMousePosition") * DEG_TO_RAD);
2573 frameCamera.pitch( - y_from_center * gSavedSettings.getF32("PitchFromMousePosition") * DEG_TO_RAD);
2574 lookAtType = LOOKAT_TARGET_FREELOOK;
2575 }
2576
2577 headLookAxis = frameCamera.getAtAxis();
2578 // RN: we use world-space offset for mouselook and freelook
2579 //headLookAxis = headLookAxis * av_inv_rot;
2580 setLookAt(lookAtType, mAvatarObject, headLookAxis);
2581 }
2582}
2583
2584// friends and operators
2585
2586std::ostream& operator<<(std::ostream &s, const LLAgent &agent)
2587{
2588 // This is unfinished, but might never be used.
2589 // We'll just leave it for now; we can always delete it.
2590 s << " { "
2591 << " Frame = " << agent.mFrameAgent << "\n"
2592 << " }";
2593 return s;
2594}
2595
2596
2597// ------------------- Beginning of legacy LLCamera hack ----------------------
2598// This section is included for legacy LLCamera support until
2599// it is no longer needed. Some legacy code must exist in
2600// non-legacy functions, and is labeled with "// legacy" comments.
2601
2602//-----------------------------------------------------------------------------
2603// setAvatarObject()
2604//-----------------------------------------------------------------------------
2605void LLAgent::setAvatarObject(LLVOAvatar *avatar)
2606{
2607 mAvatarObject = avatar;
2608
2609 if (!avatar)
2610 {
2611 llinfos << "Setting LLAgent::mAvatarObject to NULL" << llendl;
2612 return;
2613 }
2614
2615 if (!mLookAt)
2616 {
2617 mLookAt = (LLHUDEffectLookAt *)gHUDManager->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_LOOKAT);
2618 }
2619 if (!mPointAt)
2620 {
2621 mPointAt = (LLHUDEffectPointAt *)gHUDManager->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINTAT);
2622 }
2623
2624 if (!mLookAt.isNull())
2625 {
2626 mLookAt->setSourceObject(avatar);
2627 }
2628 if (!mPointAt.isNull())
2629 {
2630 mPointAt->setSourceObject(avatar);
2631 }
2632
2633 sendAgentWearablesRequest();
2634}
2635
2636// TRUE if your own avatar needs to be rendered. Usually only
2637// in third person and build.
2638//-----------------------------------------------------------------------------
2639// needsRenderAvatar()
2640//-----------------------------------------------------------------------------
2641BOOL LLAgent::needsRenderAvatar()
2642{
2643 if (cameraMouselook() && !LLVOAvatar::sVisibleInFirstPerson)
2644 {
2645 return FALSE;
2646 }
2647
2648 return mShowAvatar && mGenderChosen;
2649}
2650
2651// TRUE if we need to render your own avatar's head.
2652BOOL LLAgent::needsRenderHead()
2653{
2654 return mShowAvatar && !cameraMouselook();
2655}
2656
2657//-----------------------------------------------------------------------------
2658// startTyping()
2659//-----------------------------------------------------------------------------
2660void LLAgent::startTyping()
2661{
2662 mTypingTimer.reset();
2663
2664 if (getRenderState() & AGENT_STATE_TYPING)
2665 {
2666 // already typing, don't trigger a different animation
2667 return;
2668 }
2669 setRenderState(AGENT_STATE_TYPING);
2670
2671 if (mChatTimer.getElapsedTimeF32() < 2.f)
2672 {
2673 LLViewerObject* chatter = gObjectList.findObject(mLastChatterID);
2674 if (chatter && chatter->isAvatar())
2675 {
2676 gAgent.setLookAt(LOOKAT_TARGET_RESPOND, chatter, LLVector3::zero);
2677 }
2678 }
2679
2680 if (gSavedSettings.getBOOL("PlayTypingAnim"))
2681 {
2682 sendAnimationRequest(ANIM_AGENT_TYPE, ANIM_REQUEST_START);
2683 }
2684 gChatBar->sendChatFromViewer("", CHAT_TYPE_START, FALSE);
2685}
2686
2687//-----------------------------------------------------------------------------
2688// stopTyping()
2689//-----------------------------------------------------------------------------
2690void LLAgent::stopTyping()
2691{
2692 if (mRenderState & AGENT_STATE_TYPING)
2693 {
2694 clearRenderState(AGENT_STATE_TYPING);
2695 sendAnimationRequest(ANIM_AGENT_TYPE, ANIM_REQUEST_STOP);
2696 gChatBar->sendChatFromViewer("", CHAT_TYPE_STOP, FALSE);
2697 }
2698}
2699
2700//-----------------------------------------------------------------------------
2701// setRenderState()
2702//-----------------------------------------------------------------------------
2703void LLAgent::setRenderState(U8 newstate)
2704{
2705 mRenderState |= newstate;
2706}
2707
2708//-----------------------------------------------------------------------------
2709// clearRenderState()
2710//-----------------------------------------------------------------------------
2711void LLAgent::clearRenderState(U8 clearstate)
2712{
2713 mRenderState &= ~clearstate;
2714}
2715
2716
2717//-----------------------------------------------------------------------------
2718// getRenderState()
2719//-----------------------------------------------------------------------------
2720U8 LLAgent::getRenderState()
2721{
2722 if (gNoRender || gToolMgr == NULL || gSelectMgr == NULL || gKeyboard == NULL)
2723 {
2724 return 0;
2725 }
2726
2727 // *FIX: don't do stuff in a getter! This is infinite loop city!
2728 if ((mTypingTimer.getElapsedTimeF32() > TYPING_TIMEOUT_SECS)
2729 && (mRenderState & AGENT_STATE_TYPING))
2730 {
2731 stopTyping();
2732 }
2733
2734 if ((!gSelectMgr->isEmpty() && gSelectMgr->shouldShowSelection())
2735 || gToolMgr->getCurrentTool( gKeyboard->currentMask(TRUE) )->isEditing() )
2736 {
2737 setRenderState(AGENT_STATE_EDITING);
2738 }
2739 else
2740 {
2741 clearRenderState(AGENT_STATE_EDITING);
2742 }
2743
2744 return mRenderState;
2745}
2746
2747//-----------------------------------------------------------------------------
2748//-----------------------------------------------------------------------------
2749
2750static const LLFloaterView::skip_list_t& get_skip_list()
2751{
2752 static LLFloaterView::skip_list_t skip_list;
2753 skip_list.insert(gFloaterMap);
2754 return skip_list;
2755}
2756
2757//-----------------------------------------------------------------------------
2758// endAnimationUpdateUI()
2759//-----------------------------------------------------------------------------
2760void LLAgent::endAnimationUpdateUI()
2761{
2762 if (mCameraMode == mLastCameraMode)
2763 {
2764 // We're already done endAnimationUpdateUI for this transition.
2765 return;
2766 }
2767
2768 // clean up UI from mode we're leaving
2769 if ( mLastCameraMode == CAMERA_MODE_MOUSELOOK )
2770 {
2771 // show mouse cursor
2772 gViewerWindow->showCursor();
2773 // show menus
2774 gMenuBarView->setVisible(TRUE);
2775 gStatusBar->setVisibleForMouselook(true);
2776
2777 gCurrentToolset = gBasicToolset;
2778 gToolMgr->useSelectedTool( gCurrentToolset );
2779
2780 // Only pop if we have pushed...
2781 if (TRUE == mViewsPushed)
2782 {
2783 mViewsPushed = FALSE;
2784 gFloaterView->popVisibleAll(get_skip_list());
2785 }
2786
2787 gAgent.setLookAt(LOOKAT_TARGET_CLEAR);
2788 if( gMorphView )
2789 {
2790 gMorphView->setVisible( FALSE );
2791 }
2792
2793 // Disable mouselook-specific animations
2794 if (mAvatarObject)
2795 {
2796 if( mAvatarObject->isAnyAnimationSignaled(AGENT_GUN_AIM_ANIMS, NUM_AGENT_GUN_AIM_ANIMS) )
2797 {
2798 if (mAvatarObject->mSignaledAnimations.find(ANIM_AGENT_AIM_RIFLE_R) != mAvatarObject->mSignaledAnimations.end())
2799 {
2800 sendAnimationRequest(ANIM_AGENT_AIM_RIFLE_R, ANIM_REQUEST_STOP);
2801 sendAnimationRequest(ANIM_AGENT_HOLD_RIFLE_R, ANIM_REQUEST_START);
2802 }
2803 if (mAvatarObject->mSignaledAnimations.find(ANIM_AGENT_AIM_HANDGUN_R) != mAvatarObject->mSignaledAnimations.end())
2804 {
2805 sendAnimationRequest(ANIM_AGENT_AIM_HANDGUN_R, ANIM_REQUEST_STOP);
2806 sendAnimationRequest(ANIM_AGENT_HOLD_HANDGUN_R, ANIM_REQUEST_START);
2807 }
2808 if (mAvatarObject->mSignaledAnimations.find(ANIM_AGENT_AIM_BAZOOKA_R) != mAvatarObject->mSignaledAnimations.end())
2809 {
2810 sendAnimationRequest(ANIM_AGENT_AIM_BAZOOKA_R, ANIM_REQUEST_STOP);
2811 sendAnimationRequest(ANIM_AGENT_HOLD_BAZOOKA_R, ANIM_REQUEST_START);
2812 }
2813 if (mAvatarObject->mSignaledAnimations.find(ANIM_AGENT_AIM_BOW_L) != mAvatarObject->mSignaledAnimations.end())
2814 {
2815 sendAnimationRequest(ANIM_AGENT_AIM_BOW_L, ANIM_REQUEST_STOP);
2816 sendAnimationRequest(ANIM_AGENT_HOLD_BOW_L, ANIM_REQUEST_START);
2817 }
2818 }
2819 }
2820 }
2821 else
2822 if( mLastCameraMode == CAMERA_MODE_CUSTOMIZE_AVATAR )
2823 {
2824 // make sure we ask to save changes
2825
2826 gCurrentToolset = gBasicToolset;
2827 gToolMgr->useSelectedTool( gCurrentToolset );
2828
2829 // HACK: If we're quitting, and we were in customize avatar, don't
2830 // let the mini-map go visible again. JC
2831 if (!gQuitRequested)
2832 {
2833 gFloaterMap->popVisible();
2834 }
2835
2836 if( gMorphView )
2837 {
2838 gMorphView->setVisible( FALSE );
2839 }
2840
2841 if (mAvatarObject)
2842 {
2843 sendAnimationRequest(ANIM_AGENT_CUSTOMIZE, ANIM_REQUEST_STOP);
2844 sendAnimationRequest(ANIM_AGENT_CUSTOMIZE_DONE, ANIM_REQUEST_START);
2845 }
2846 setLookAt(LOOKAT_TARGET_CLEAR);
2847 }
2848
2849 //---------------------------------------------------------------------
2850 // Set up UI for mode we're entering
2851 //---------------------------------------------------------------------
2852 if (mCameraMode == CAMERA_MODE_MOUSELOOK)
2853 {
2854 // hide menus
2855 gMenuBarView->setVisible(FALSE);
2856 gStatusBar->setVisibleForMouselook(false);
2857
2858 // clear out camera lag effect
2859 mCameraLag.clearVec();
2860
2861 // JC - Added for always chat in third person option
2862 gFocusMgr.setKeyboardFocus(NULL, NULL);
2863
2864 gCurrentToolset = gMouselookToolset;
2865 gToolMgr->useSelectedTool( gMouselookToolset );
2866
2867 mViewsPushed = TRUE;
2868
2869 gFloaterView->pushVisibleAll(FALSE, get_skip_list());
2870
2871 if( gMorphView )
2872 {
2873 gMorphView->setVisible(FALSE);
2874 }
2875
2876 gIMView->setFloaterOpen( FALSE );
2877 gConsole->setVisible( TRUE );
2878
2879 if (mAvatarObject)
2880 {
2881 // Trigger mouselook-specific animations
2882 if( mAvatarObject->isAnyAnimationSignaled(AGENT_GUN_HOLD_ANIMS, NUM_AGENT_GUN_HOLD_ANIMS) )
2883 {
2884 if (mAvatarObject->mSignaledAnimations.find(ANIM_AGENT_HOLD_RIFLE_R) != mAvatarObject->mSignaledAnimations.end())
2885 {
2886 sendAnimationRequest(ANIM_AGENT_HOLD_RIFLE_R, ANIM_REQUEST_STOP);
2887 sendAnimationRequest(ANIM_AGENT_AIM_RIFLE_R, ANIM_REQUEST_START);
2888 }
2889 if (mAvatarObject->mSignaledAnimations.find(ANIM_AGENT_HOLD_HANDGUN_R) != mAvatarObject->mSignaledAnimations.end())
2890 {
2891 sendAnimationRequest(ANIM_AGENT_HOLD_HANDGUN_R, ANIM_REQUEST_STOP);
2892 sendAnimationRequest(ANIM_AGENT_AIM_HANDGUN_R, ANIM_REQUEST_START);
2893 }
2894 if (mAvatarObject->mSignaledAnimations.find(ANIM_AGENT_HOLD_BAZOOKA_R) != mAvatarObject->mSignaledAnimations.end())
2895 {
2896 sendAnimationRequest(ANIM_AGENT_HOLD_BAZOOKA_R, ANIM_REQUEST_STOP);
2897 sendAnimationRequest(ANIM_AGENT_AIM_BAZOOKA_R, ANIM_REQUEST_START);
2898 }
2899 if (mAvatarObject->mSignaledAnimations.find(ANIM_AGENT_HOLD_BOW_L) != mAvatarObject->mSignaledAnimations.end())
2900 {
2901 sendAnimationRequest(ANIM_AGENT_HOLD_BOW_L, ANIM_REQUEST_STOP);
2902 sendAnimationRequest(ANIM_AGENT_AIM_BOW_L, ANIM_REQUEST_START);
2903 }
2904 }
2905 if (mAvatarObject->getParent())
2906 {
2907 LLVector3 at_axis = gCamera->getAtAxis();
2908 LLViewerObject* root_object = (LLViewerObject*)mAvatarObject->getRoot();
2909 if (root_object->flagCameraDecoupled())
2910 {
2911 resetAxes(at_axis);
2912 }
2913 else
2914 {
2915 resetAxes(at_axis * ~((LLViewerObject*)mAvatarObject->getParent())->getRenderRotation());
2916 }
2917 }
2918 }
2919
2920 }
2921 else if (mCameraMode == CAMERA_MODE_CUSTOMIZE_AVATAR)
2922 {
2923 gCurrentToolset = gFaceEditToolset;
2924 gToolMgr->useSelectedTool( gFaceEditToolset );
2925
2926 gFloaterMap->pushVisible(FALSE);
2927 /*
2928 LLView *view;
2929 for (view = gFloaterView->getFirstChild(); view; view = gFloaterView->getNextChild())
2930 {
2931 view->pushVisible(FALSE);
2932 }
2933 */
2934
2935 if( gMorphView )
2936 {
2937 gMorphView->setVisible( TRUE );
2938 }
2939
2940 // freeze avatar
2941 if (mAvatarObject)
2942 {
2943 mPauseRequest = mAvatarObject->requestPause();
2944 }
2945 }
2946
2947 if (getAvatarObject())
2948 {
2949 getAvatarObject()->updateAttachmentVisibility(mCameraMode);
2950 }
2951
2952 gFloaterTools->dirty();
2953
2954 // Don't let this be called more than once if the camera
2955 // mode hasn't changed. --JC
2956 mLastCameraMode = mCameraMode;
2957}
2958
2959
2960//-----------------------------------------------------------------------------
2961// updateCamera()
2962//-----------------------------------------------------------------------------
2963void LLAgent::updateCamera()
2964{
2965 //Ventrella - changed camera_skyward to the new global "mCameraUpVector"
2966 mCameraUpVector = LLVector3::z_axis;
2967 //LLVector3 camera_skyward(0.f, 0.f, 1.f);
2968 //end Ventrella
2969
2970 U32 camera_mode = mCameraAnimating ? mLastCameraMode : mCameraMode;
2971
2972 validateFocusObject();
2973
2974 if (!mAvatarObject.isNull() &&
2975 mAvatarObject->mIsSitting &&
2976 camera_mode == CAMERA_MODE_MOUSELOOK)
2977 {
2978 //Ventrella
2979 //changed camera_skyward to the new global "mCameraUpVector"
2980 mCameraUpVector = mCameraUpVector * mAvatarObject->getRenderRotation();
2981 //end Ventrella
2982 }
2983
2984 if (cameraThirdPerson() && mFocusOnAvatar && LLFollowCamMgr::getActiveFollowCamParams())
2985 {
2986 changeCameraToFollow();
2987 }
2988
2989 //Ventrella
2990 //NOTE - this needs to be integrated into a general upVector system here within llAgent.
2991 if ( camera_mode == CAMERA_MODE_FOLLOW && mFocusOnAvatar )
2992 {
2993 mCameraUpVector = mFollowCam.getUpVector();
2994 }
2995 //end Ventrella
2996
2997 if (mSitCameraEnabled)
2998 {
2999 if (mSitCameraReferenceObject->isDead())
3000 {
3001 setSitCamera(LLUUID::null);
3002 }
3003 }
3004
3005 // Update UI with our camera inputs
3006 if (gFloaterCamera)
3007 {
3008 gFloaterCamera->mRotate->setToggleState(
3009 mOrbitRightKey > 0.f, // left
3010 mOrbitUpKey > 0.f, // top
3011 mOrbitLeftKey > 0.f, // right
3012 mOrbitDownKey > 0.f); // bottom
3013
3014 gFloaterCamera->mZoom->setToggleState(
3015 mOrbitInKey > 0.f, // top
3016 mOrbitOutKey > 0.f); // bottom
3017
3018 gFloaterCamera->mTrack->setToggleState(
3019 mPanLeftKey > 0.f, // left
3020 mPanUpKey > 0.f, // top
3021 mPanRightKey > 0.f, // right
3022 mPanDownKey > 0.f); // bottom
3023 }
3024
3025 // Handle camera movement based on keyboard.
3026 const F32 ORBIT_OVER_RATE = 90.f * DEG_TO_RAD; // radians per second
3027 const F32 ORBIT_AROUND_RATE = 90.f * DEG_TO_RAD; // radians per second
3028 const F32 PAN_RATE = 5.f; // meters per second
3029
3030 if( mOrbitUpKey || mOrbitDownKey )
3031 {
3032 F32 input_rate = mOrbitUpKey - mOrbitDownKey;
3033 cameraOrbitOver( input_rate * ORBIT_OVER_RATE / gFPSClamped );
3034 }
3035
3036 if( mOrbitLeftKey || mOrbitRightKey)
3037 {
3038 F32 input_rate = mOrbitLeftKey - mOrbitRightKey;
3039 cameraOrbitAround( input_rate * ORBIT_AROUND_RATE / gFPSClamped );
3040 }
3041
3042 if( mOrbitInKey || mOrbitOutKey )
3043 {
3044 F32 input_rate = mOrbitInKey - mOrbitOutKey;
3045
3046 LLVector3d to_focus = gAgent.getPosGlobalFromAgent(gCamera->getOrigin()) - calcFocusPositionTargetGlobal();
3047 F32 distance_to_focus = (F32)to_focus.magVec();
3048 // Move at distance (in meters) meters per second
3049 cameraOrbitIn( input_rate * distance_to_focus / gFPSClamped );
3050 }
3051
3052 if( mPanInKey || mPanOutKey )
3053 {
3054 F32 input_rate = mPanInKey - mPanOutKey;
3055 cameraPanIn( input_rate * PAN_RATE / gFPSClamped );
3056 }
3057
3058 if( mPanRightKey || mPanLeftKey )
3059 {
3060 F32 input_rate = mPanRightKey - mPanLeftKey;
3061 cameraPanLeft( input_rate * -PAN_RATE / gFPSClamped );
3062 }
3063
3064 if( mPanUpKey || mPanDownKey )
3065 {
3066 F32 input_rate = mPanUpKey - mPanDownKey;
3067 cameraPanUp( input_rate * PAN_RATE / gFPSClamped );
3068 }
3069
3070 // Clear camera keyboard keys.
3071 mOrbitLeftKey = 0.f;
3072 mOrbitRightKey = 0.f;
3073 mOrbitUpKey = 0.f;
3074 mOrbitDownKey = 0.f;
3075 mOrbitInKey = 0.f;
3076 mOrbitOutKey = 0.f;
3077
3078 mPanRightKey = 0.f;
3079 mPanLeftKey = 0.f;
3080 mPanUpKey = 0.f;
3081 mPanDownKey = 0.f;
3082 mPanInKey = 0.f;
3083 mPanOutKey = 0.f;
3084
3085 // lerp camera focus offset
3086 mCameraFocusOffset = lerp(mCameraFocusOffset, mCameraFocusOffsetTarget, LLCriticalDamp::getInterpolant(CAMERA_FOCUS_HALF_LIFE));
3087
3088 //Ventrella
3089 if ( mCameraMode == CAMERA_MODE_FOLLOW )
3090 {
3091 if ( !mAvatarObject.isNull() )
3092 {
3093 //--------------------------------------------------------------------------------
3094 // this is where the avatar's position and rotation are given to followCam, and
3095 // where it is updated. All three of its attributes are updated: (1) position,
3096 // (2) focus, and (3) upvector. They can then be queried elsewhere in llAgent.
3097 //--------------------------------------------------------------------------------
3098 // *TODO: use combined rotation of frameagent and sit object
3099 LLQuaternion avatarRotationForFollowCam = mAvatarObject->mIsSitting ? mAvatarObject->getRenderRotation() : mFrameAgent.getQuaternion();
3100
3101 LLFollowCamParams* current_cam = LLFollowCamMgr::getActiveFollowCamParams();
3102 if (current_cam)
3103 {
3104 mFollowCam.copyParams(*current_cam);
3105 mFollowCam.setSubjectPositionAndRotation( mAvatarObject->getRenderPosition(), avatarRotationForFollowCam );
3106 mFollowCam.update();
3107 }
3108 else
3109 {
3110 changeCameraToThirdPerson(TRUE);
3111 }
3112 }
3113 }
3114 // end Ventrella
3115
3116 BOOL hit_limit;
3117 LLVector3d camera_pos_global;
3118 LLVector3d camera_target_global = calcCameraPositionTargetGlobal(&hit_limit);
3119 mCameraVirtualPositionAgent = getPosAgentFromGlobal(camera_target_global);
3120 LLVector3d focus_target_global = calcFocusPositionTargetGlobal();
3121
3122 // perform field of view correction
3123 mCameraFOVZoomFactor = calcCameraFOVZoomFactor();
3124 camera_target_global = focus_target_global + (camera_target_global - focus_target_global) * (1.f + mCameraFOVZoomFactor);
3125
3126 // do alpha fade on focus object
3127 F32 fade_increment = mFocusObjectFadeTimer.getElapsedTimeAndResetF32();
3128
3129 if (mFocusObject.notNull() && !mFocusObject->isAttachment() && mFocusObject->mDrawable.notNull())
3130 {
3131 F32 increment = fade_increment;
3132 if (mFocusObjectDist < -0.2f)
3133 {
3134 increment *= -1.f;
3135 }
3136
3137 if (mFocusObject->getVObjRadius() > MIN_RADIUS_ALPHA_SIZZLE)
3138 {
3139 S32 num_faces = mFocusObject->mDrawable->getNumFaces();
3140 for (S32 i = 0; i < num_faces; i++)
3141 {
3142 LLFace* facep = mFocusObject->mDrawable->getFace(i);
3143 F32 fade = facep->mAlphaFade;
3144 fade = llclamp(fade + increment, 0.f, 1.f);
3145 facep->mAlphaFade = fade;
3146 }
3147 }
3148 }
3149
3150 // do alpha fade in on fade objects
3151 std::set< LLPointer<LLViewerObject> >::iterator fade_object_it;
3152 for (fade_object_it = mFadeObjects.begin(); fade_object_it != mFadeObjects.end(); )
3153 {
3154 LLViewerObject* fade_object = *fade_object_it;
3155 if (fade_object->isDead())
3156 {
3157 // remove from list
3158 mFadeObjects.erase(fade_object_it++);
3159 }
3160 else
3161 {
3162 LLDrawable* drawablep = fade_object->mDrawable;
3163 if (drawablep && fade_object->getVObjRadius() > MIN_RADIUS_ALPHA_SIZZLE)
3164 {
3165 S32 num_faces = drawablep->getNumFaces();
3166 BOOL fade_done = TRUE;
3167 for (S32 i = 0; i < num_faces; i++)
3168 {
3169 LLFace* facep = drawablep->getFace(i);
3170 F32 fade = facep->mAlphaFade;
3171 fade = llclamp(fade - fade_increment, 0.f, 1.f);
3172 facep->mAlphaFade = fade;
3173 if (fade > 0.f)
3174 {
3175 fade_done = FALSE;
3176 }
3177 }
3178 if (fade_done)
3179 {
3180 mFadeObjects.erase(fade_object_it++);
3181 }
3182 else
3183 {
3184 fade_object_it++;
3185 }
3186 }
3187 else
3188 {
3189 fade_object_it++;
3190 }
3191 }
3192 }
3193
3194 mShowAvatar = TRUE; // can see avatar by default
3195
3196 // Adjust position for animation
3197 if (mCameraAnimating)
3198 {
3199 F32 time = mAnimationTimer.getElapsedTimeF32();
3200
3201 // yet another instance of critically damped motion, hooray!
3202 // F32 fraction_of_animation = 1.f - pow(2.f, -time / CAMERA_ZOOM_HALF_LIFE);
3203
3204 // linear interpolation
3205 F32 fraction_of_animation = time / mAnimationDuration;
3206
3207 BOOL isfirstPerson = mCameraMode == CAMERA_MODE_MOUSELOOK;
3208 BOOL wasfirstPerson = mLastCameraMode == CAMERA_MODE_MOUSELOOK;
3209 F32 fraction_animation_to_skip;
3210
3211 if (mAnimationCameraStartGlobal == camera_target_global)
3212 {
3213 fraction_animation_to_skip = 0.f;
3214 }
3215 else
3216 {
3217 LLVector3d cam_delta = mAnimationCameraStartGlobal - camera_target_global;
3218 fraction_animation_to_skip = HEAD_BUFFER_SIZE / (F32)cam_delta.magVec();
3219 }
3220 F32 animation_start_fraction = (wasfirstPerson) ? fraction_animation_to_skip : 0.f;
3221 F32 animation_finish_fraction = (isfirstPerson) ? (1.f - fraction_animation_to_skip) : 1.f;
3222
3223 if (fraction_of_animation < animation_finish_fraction)
3224 {
3225 if (fraction_of_animation < animation_start_fraction || fraction_of_animation > animation_finish_fraction )
3226 {
3227 mShowAvatar = FALSE;
3228 }
3229
3230 // ...adjust position for animation
3231 camera_pos_global = lerp(mAnimationCameraStartGlobal, camera_target_global, fraction_of_animation);
3232 mFocusGlobal = lerp(mAnimationFocusStartGlobal, focus_target_global, fraction_of_animation);
3233 }
3234 else
3235 {
3236 // ...animation complete
3237 mCameraAnimating = FALSE;
3238
3239 camera_pos_global = camera_target_global;
3240 mFocusGlobal = focus_target_global;
3241
3242 endAnimationUpdateUI();
3243 mShowAvatar = TRUE;
3244 }
3245
3246 if (getAvatarObject() && mCameraMode != CAMERA_MODE_MOUSELOOK)
3247 {
3248 getAvatarObject()->updateAttachmentVisibility(mCameraMode);
3249 }
3250 }
3251 else
3252 {
3253 camera_pos_global = camera_target_global;
3254 mFocusGlobal = focus_target_global;
3255 mShowAvatar = TRUE;
3256 }
3257
3258 mCameraCurrentFOVZoomFactor = lerp(mCameraCurrentFOVZoomFactor, mCameraFOVZoomFactor, LLCriticalDamp::getInterpolant(FOV_ZOOM_HALF_LIFE));
3259
3260// llinfos << "Current FOV Zoom: " << mCameraCurrentFOVZoomFactor << " Target FOV Zoom: " << mCameraFOVZoomFactor << " Object penetration: " << mFocusObjectDist << llendl;
3261
3262 F32 ui_offset = 0.f;
3263 if( CAMERA_MODE_CUSTOMIZE_AVATAR == mCameraMode )
3264 {
3265 ui_offset = calcCustomizeAvatarUIOffset( camera_pos_global );
3266 }
3267
3268
3269 LLVector3 focus_agent = getPosAgentFromGlobal(mFocusGlobal);
3270
3271 mCameraPositionAgent = getPosAgentFromGlobal(camera_pos_global);
3272
3273 // Move the camera
3274
3275 //Ventrella
3276 gCamera->updateCameraLocation(mCameraPositionAgent, mCameraUpVector, focus_agent);
3277 //gCamera->updateCameraLocation(mCameraPositionAgent, camera_skyward, focus_agent);
3278 //end Ventrella
3279
3280 //RN: translate UI offset after camera is oriented properly
3281 gCamera->translate(gCamera->getLeftAxis() * ui_offset);
3282
3283 // Change FOV
3284 gCamera->setView(gCamera->getDefaultFOV() / (1.f + mCameraCurrentFOVZoomFactor));
3285
3286 // follow camera when in customize mode
3287 if (cameraCustomizeAvatar())
3288 {
3289 setLookAt(LOOKAT_TARGET_FOCUS, NULL, mCameraPositionAgent);
3290 }
3291
3292 // update the travel distance stat
3293 // this isn't directly related to the camera
3294 // but this seemed like the best place to do this
3295 LLVector3d global_pos = getPositionGlobal();
3296 if (! mLastPositionGlobal.isExactlyZero())
3297 {
3298 LLVector3d delta = global_pos - mLastPositionGlobal;
3299 mDistanceTraveled += delta.magVec();
3300 }
3301 mLastPositionGlobal = global_pos;
3302
3303 if (LLVOAvatar::sVisibleInFirstPerson && mAvatarObject.notNull() && !mAvatarObject->mIsSitting && cameraMouselook())
3304 {
3305 LLVector3 head_pos = mAvatarObject->mHeadp->getWorldPosition() +
3306 LLVector3(0.08f, 0.f, 0.05f) * mAvatarObject->mHeadp->getWorldRotation() +
3307 LLVector3(0.1f, 0.f, 0.f) * mAvatarObject->mPelvisp->getWorldRotation();
3308 LLVector3 diff = mCameraPositionAgent - head_pos;
3309 diff = diff * ~mAvatarObject->mRoot.getWorldRotation();
3310
3311 LLJoint* torso_joint = mAvatarObject->mTorsop;
3312 LLJoint* chest_joint = mAvatarObject->mChestp;
3313 LLVector3 torso_scale = torso_joint->getScale();
3314 LLVector3 chest_scale = chest_joint->getScale();
3315
3316 // shorten avatar skeleton to avoid foot interpenetration
3317 if (!mAvatarObject->mInAir)
3318 {
3319 LLVector3 chest_offset = LLVector3(0.f, 0.f, chest_joint->getPosition().mV[VZ]) * torso_joint->getWorldRotation();
3320 F32 z_compensate = llclamp(-diff.mV[VZ], -0.2f, 1.f);
3321 F32 scale_factor = llclamp(1.f - ((z_compensate * 0.5f) / chest_offset.mV[VZ]), 0.5f, 1.2f);
3322 torso_joint->setScale(LLVector3(1.f, 1.f, scale_factor));
3323
3324 LLJoint* neck_joint = mAvatarObject->mNeckp;
3325 LLVector3 neck_offset = LLVector3(0.f, 0.f, neck_joint->getPosition().mV[VZ]) * chest_joint->getWorldRotation();
3326 scale_factor = llclamp(1.f - ((z_compensate * 0.5f) / neck_offset.mV[VZ]), 0.5f, 1.2f);
3327 chest_joint->setScale(LLVector3(1.f, 1.f, scale_factor));
3328 diff.mV[VZ] = 0.f;
3329 }
3330
3331 mAvatarObject->mPelvisp->setPosition(mAvatarObject->mPelvisp->getPosition() + diff);
3332
3333 mAvatarObject->mRoot.updateWorldMatrixChildren();
3334
3335 for(LLViewerJointAttachment *attachment = mAvatarObject->mAttachmentPoints.getFirstData();
3336 attachment;
3337 attachment = mAvatarObject->mAttachmentPoints.getNextData())
3338 {
3339 LLViewerObject *attached_object = attachment->getObject(0);
3340 if (attached_object && !attached_object->isDead() && attached_object->mDrawable.notNull())
3341 {
3342 // clear any existing "early" movements of attachment
3343 attached_object->mDrawable->clearState(LLDrawable::EARLY_MOVE);
3344 gPipeline.updateMoveNormalAsync(attached_object->mDrawable);
3345 attached_object->updateText();
3346 }
3347 }
3348
3349 torso_joint->setScale(torso_scale);
3350 chest_joint->setScale(chest_scale);
3351 }
3352}
3353
3354void LLAgent::updateFocusOffset()
3355{
3356 validateFocusObject();
3357 if (mFocusObject.notNull())
3358 {
3359 LLVector3d obj_pos = getPosGlobalFromAgent(mFocusObject->getRenderPosition());
3360 mFocusObjectOffset.setVec(mFocusTargetGlobal - obj_pos);
3361 }
3362}
3363
3364void LLAgent::validateFocusObject()
3365{
3366 if (mFocusObject.notNull() &&
3367 (mFocusObject->isDead()))
3368 {
3369 mFocusObjectOffset.clearVec();
3370 clearFocusObject();
3371 mCameraFOVZoomFactor = 0.f;
3372 }
3373}
3374
3375//-----------------------------------------------------------------------------
3376// calcCustomizeAvatarUIOffset()
3377//-----------------------------------------------------------------------------
3378F32 LLAgent::calcCustomizeAvatarUIOffset( const LLVector3d& camera_pos_global )
3379{
3380 F32 ui_offset = 0.f;
3381
3382 if( gFloaterCustomize )
3383 {
3384 const LLRect& rect = gFloaterCustomize->getRect();
3385
3386 // Move the camera so that the avatar isn't covered up by this floater.
3387 F32 fraction_of_fov = 0.5f - (0.5f * (1.f - llmin(1.f, ((F32)rect.getWidth() / (F32)gViewerWindow->getWindowWidth()))));
3388 F32 apparent_angle = fraction_of_fov * gCamera->getView() * gCamera->getAspect(); // radians
3389 F32 offset = tan(apparent_angle);
3390
3391 if( rect.mLeft < (gViewerWindow->getWindowWidth() - rect.mRight) )
3392 {
3393 // Move the avatar to the right (camera to the left)
3394 ui_offset = offset;
3395 }
3396 else
3397 {
3398 // Move the avatar to the left (camera to the right)
3399 ui_offset = -offset;
3400 }
3401 }
3402 F32 range = (F32)dist_vec(camera_pos_global, gAgent.getFocusGlobal());
3403 mUIOffset = lerp(mUIOffset, ui_offset, LLCriticalDamp::getInterpolant(0.05f));
3404 return mUIOffset * range;
3405}
3406
3407//-----------------------------------------------------------------------------
3408// calcFocusPositionTargetGlobal()
3409//-----------------------------------------------------------------------------
3410LLVector3d LLAgent::calcFocusPositionTargetGlobal()
3411{
3412 if (mFocusObject.notNull() && mFocusObject->isDead())
3413 {
3414 clearFocusObject();
3415 }
3416
3417 // Ventrella
3418 if ( mCameraMode == CAMERA_MODE_FOLLOW && mFocusOnAvatar )
3419 {
3420 mFocusTargetGlobal = gAgent.getPosGlobalFromAgent(mFollowCam.getSimulatedFocus());
3421 return mFocusTargetGlobal;
3422 }// End Ventrella
3423 else if (mCameraMode == CAMERA_MODE_MOUSELOOK)
3424 {
3425 LLVector3d at_axis(1.0, 0.0, 0.0);
3426 LLQuaternion agent_rot = mFrameAgent.getQuaternion();
3427 if (!mAvatarObject.isNull() && mAvatarObject->getParent())
3428 {
3429 LLViewerObject* root_object = (LLViewerObject*)mAvatarObject->getRoot();
3430 if (!root_object->flagCameraDecoupled())
3431 {
3432 agent_rot *= ((LLViewerObject*)(mAvatarObject->getParent()))->getRenderRotation();
3433 }
3434 }
3435 at_axis = at_axis * agent_rot;
3436 mFocusTargetGlobal = calcCameraPositionTargetGlobal() + at_axis;
3437 return mFocusTargetGlobal;
3438 }
3439 else if (mCameraMode == CAMERA_MODE_CUSTOMIZE_AVATAR)
3440 {
3441 return mFocusTargetGlobal;
3442 }
3443 else if (!mFocusOnAvatar)
3444 {
3445 if (mFocusObject.notNull() && !mFocusObject->isDead() && mFocusObject->mDrawable.notNull())
3446 {
3447 LLDrawable* drawablep = mFocusObject->mDrawable;
3448
3449 if (mTrackFocusObject && drawablep && drawablep->isActive())
3450 {
3451 if (mFocusObject->isSelected())
3452 {
3453 gPipeline.updateMoveNormalAsync(drawablep);
3454 }
3455 else
3456 {
3457 if (drawablep->isState(LLDrawable::MOVE_UNDAMPED))
3458 {
3459 gPipeline.updateMoveNormalAsync(drawablep);
3460 }
3461 else
3462 {
3463 gPipeline.updateMoveDampedAsync(drawablep);
3464 }
3465 }
3466 }
3467 // if not tracking object, update offset based on new object position
3468 else
3469 {
3470 updateFocusOffset();
3471 }
3472 LLVector3 focus_agent = mFocusObject->getRenderPosition() + mFocusObjectOffset;
3473 mFocusTargetGlobal.setVec(getPosGlobalFromAgent(focus_agent));
3474 // *FIX: get camera pointat behavior working
3475 //if (mTrackFocusObject)
3476 //{
3477 // mCameraFocusOffset = gAgent.getPosGlobalFromAgent(gCamera->getOrigin()) - mFocusTargetGlobal;
3478 //}
3479 }
3480 return mFocusTargetGlobal;
3481 }
3482 else if (mSitCameraEnabled && mAvatarObject.notNull() && mAvatarObject->mIsSitting && mSitCameraReferenceObject.notNull())
3483 {
3484 // sit camera
3485 LLVector3 object_pos = mSitCameraReferenceObject->getRenderPosition();
3486 LLQuaternion object_rot = mSitCameraReferenceObject->getRenderRotation();
3487
3488 LLVector3 target_pos = object_pos + (mSitCameraFocus * object_rot);
3489 return getPosGlobalFromAgent(target_pos);
3490 }
3491 else
3492 {
3493 // ...offset from avatar
3494 LLVector3d focus_offset;
3495 focus_offset.setVec(gSavedSettings.getVector3("FocusOffsetDefault"));
3496
3497 LLQuaternion agent_rot = mFrameAgent.getQuaternion();
3498 if (!mAvatarObject.isNull() && mAvatarObject->getParent())
3499 {
3500 agent_rot *= ((LLViewerObject*)(mAvatarObject->getParent()))->getRenderRotation();
3501 }
3502
3503 focus_offset = focus_offset * agent_rot;
3504
3505 return getPositionGlobal() + focus_offset;
3506 }
3507}
3508
3509void LLAgent::setupSitCamera()
3510{
3511 // agent frame entering this function is in world coordinates
3512 if (mAvatarObject.notNull() && mAvatarObject->getParent())
3513 {
3514 LLQuaternion parent_rot = ((LLViewerObject*)mAvatarObject->getParent())->getRenderRotation();
3515 // slam agent coordinate frame to proper parent local version
3516 LLVector3 at_axis = mFrameAgent.getAtAxis();
3517 at_axis.mV[VZ] = 0.f;
3518 at_axis.normVec();
3519 resetAxes(at_axis * ~parent_rot);
3520 }
3521}
3522
3523//-----------------------------------------------------------------------------
3524// getCameraPositionAgent()
3525//-----------------------------------------------------------------------------
3526const LLVector3 &LLAgent::getCameraPositionAgent() const
3527{
3528 return gCamera->getOrigin();
3529}
3530
3531//-----------------------------------------------------------------------------
3532// getCameraPositionGlobal()
3533//-----------------------------------------------------------------------------
3534LLVector3d LLAgent::getCameraPositionGlobal() const
3535{
3536 if (gCamera)
3537 {
3538 return getPosGlobalFromAgent(gCamera->getOrigin());
3539 }
3540 else
3541 {
3542 return (LLVector3d::zero);
3543 }
3544}
3545
3546//-----------------------------------------------------------------------------
3547// calcCameraFOVZoomFactor()
3548//-----------------------------------------------------------------------------
3549F32 LLAgent::calcCameraFOVZoomFactor()
3550{
3551 LLVector3 camera_offset_dir;
3552 camera_offset_dir.setVec(mCameraFocusOffset);
3553
3554 if (mCameraMode == CAMERA_MODE_MOUSELOOK)
3555 {
3556 return 0.f;
3557 }
3558 else if (mFocusObject.notNull() && !mFocusObject->isAvatar())
3559 {
3560 // don't FOV zoom on mostly transparent objects
3561 LLVector3 focus_offset = mFocusObjectOffset;
3562 F32 obj_min_dist = 0.f;
3563 calcCameraMinDistance(obj_min_dist);
3564 F32 current_distance = llmax(0.001f, camera_offset_dir.magVec());
3565
3566 mFocusObjectDist = obj_min_dist - current_distance;
3567
3568 F32 new_fov_zoom = llclamp(mFocusObjectDist / current_distance, 0.f, 1000.f);
3569 return new_fov_zoom;
3570 }
3571 else // focusing on land or avatar
3572 {
3573 // keep old field of view until user changes focus explicitly
3574 return mCameraFOVZoomFactor;
3575 //return 0.f;
3576 }
3577}
3578
3579//-----------------------------------------------------------------------------
3580// calcCameraPositionTargetGlobal()
3581//-----------------------------------------------------------------------------
3582LLVector3d LLAgent::calcCameraPositionTargetGlobal(BOOL *hit_limit)
3583{
3584 // Compute base camera position and look-at points.
3585 F32 camera_land_height;
3586 LLVector3d frame_center_global = mAvatarObject.isNull() ? getPositionGlobal()
3587 : getPosGlobalFromAgent(mAvatarObject->mRoot.getWorldPosition());
3588
3589 LLVector3 upAxis = getUpAxis();
3590 BOOL isConstrained = FALSE;
3591 LLVector3d head_offset;
3592 head_offset.setVec(mThirdPersonHeadOffset);
3593
3594 LLVector3d camera_position_global;
3595
3596 // Ventrella
3597 if ( mCameraMode == CAMERA_MODE_FOLLOW && mFocusOnAvatar )
3598 {
3599 camera_position_global = gAgent.getPosGlobalFromAgent(mFollowCam.getSimulatedPosition());
3600 }// End Ventrella
3601 else if (mCameraMode == CAMERA_MODE_MOUSELOOK)
3602 {
3603 if (mAvatarObject.isNull() || mAvatarObject->mDrawable.isNull())
3604 {
3605 llwarns << "Null avatar drawable!" << llendl;
3606 return LLVector3d::zero;
3607 }
3608 head_offset.clearVec();
3609 if (mAvatarObject->mIsSitting && mAvatarObject->getParent())
3610 {
3611 mAvatarObject->updateHeadOffset();
3612 head_offset.mdV[VX] = mAvatarObject->mHeadOffset.mV[VX];
3613 head_offset.mdV[VY] = mAvatarObject->mHeadOffset.mV[VY];
3614 head_offset.mdV[VZ] = mAvatarObject->mHeadOffset.mV[VZ] + 0.1f;
3615 const LLMatrix4& mat = ((LLViewerObject*) mAvatarObject->getParent())->getRenderMatrix();
3616 camera_position_global = getPosGlobalFromAgent
3617 ((mAvatarObject->getPosition()+
3618 LLVector3(head_offset)*mAvatarObject->getRotation()) * mat);
3619 }
3620 else
3621 {
3622 head_offset.mdV[VZ] = mAvatarObject->mHeadOffset.mV[VZ];
3623 if (mAvatarObject->mIsSitting)
3624 {
3625 head_offset.mdV[VZ] += 0.1;
3626 }
3627 camera_position_global = getPosGlobalFromAgent(mAvatarObject->getRenderPosition());//frame_center_global;
3628 head_offset = head_offset * mAvatarObject->getRenderRotation();
3629 camera_position_global = camera_position_global + head_offset;
3630 }
3631 }
3632 else if (mCameraMode == CAMERA_MODE_THIRD_PERSON && mFocusOnAvatar)
3633 {
3634 LLVector3 local_camera_offset;
3635 F32 camera_distance = 0.f;
3636
3637 if (mSitCameraEnabled
3638 && mAvatarObject.notNull()
3639 && mAvatarObject->mIsSitting
3640 && mSitCameraReferenceObject.notNull())
3641 {
3642 // sit camera
3643 LLVector3 object_pos = mSitCameraReferenceObject->getRenderPosition();
3644 LLQuaternion object_rot = mSitCameraReferenceObject->getRenderRotation();
3645
3646 LLVector3 target_pos = object_pos + (mSitCameraPos * object_rot);
3647
3648 camera_position_global = getPosGlobalFromAgent(target_pos);
3649 }
3650 else
3651 {
3652 local_camera_offset = mCameraZoomFraction * mCameraOffsetDefault;
3653
3654 // are we sitting down?
3655 if (mAvatarObject.notNull() && mAvatarObject->getParent())
3656 {
3657 LLQuaternion parent_rot = ((LLViewerObject*)mAvatarObject->getParent())->getRenderRotation();
3658 // slam agent coordinate frame to proper parent local version
3659 LLVector3 at_axis = mFrameAgent.getAtAxis() * parent_rot;
3660 at_axis.mV[VZ] = 0.f;
3661 at_axis.normVec();
3662 resetAxes(at_axis * ~parent_rot);
3663
3664 local_camera_offset = local_camera_offset * mFrameAgent.getQuaternion() * parent_rot;
3665 }
3666 else
3667 {
3668 local_camera_offset = mFrameAgent.rotateToAbsolute( local_camera_offset );
3669 }
3670
3671 if (!mCameraCollidePlane.isExactlyZero() && (mAvatarObject.isNull() || !mAvatarObject->mIsSitting))
3672 {
3673 LLVector3 plane_normal;
3674 plane_normal.setVec(mCameraCollidePlane.mV);
3675
3676 F32 offset_dot_norm = local_camera_offset * plane_normal;
3677 if (llabs(offset_dot_norm) < 0.001f)
3678 {
3679 offset_dot_norm = 0.001f;
3680 }
3681
3682 camera_distance = local_camera_offset.normVec();
3683
3684 F32 pos_dot_norm = getPosAgentFromGlobal(frame_center_global + head_offset) * plane_normal;
3685
3686 // if agent is outside the colliding half-plane
3687 if (pos_dot_norm > mCameraCollidePlane.mV[VW])
3688 {
3689 // check to see if camera is on the opposite side (inside) the half-plane
3690 if (offset_dot_norm + pos_dot_norm < mCameraCollidePlane.mV[VW])
3691 {
3692 // diminish offset by factor to push it back outside the half-plane
3693 camera_distance *= (pos_dot_norm - mCameraCollidePlane.mV[VW] - CAMERA_COLLIDE_EPSILON) / -offset_dot_norm;
3694 }
3695 }
3696 else
3697 {
3698 if (offset_dot_norm + pos_dot_norm > mCameraCollidePlane.mV[VW])
3699 {
3700 camera_distance *= (mCameraCollidePlane.mV[VW] - pos_dot_norm - CAMERA_COLLIDE_EPSILON) / offset_dot_norm;
3701 }
3702 }
3703 }
3704 else
3705 {
3706 camera_distance = local_camera_offset.normVec();
3707 }
3708
3709 mTargetCameraDistance = llmax(camera_distance, MIN_CAMERA_DISTANCE);
3710
3711 if (mTargetCameraDistance != mCurrentCameraDistance)
3712 {
3713 F32 camera_lerp_amt = LLCriticalDamp::getInterpolant(CAMERA_ZOOM_HALF_LIFE);
3714
3715 mCurrentCameraDistance = lerp(mCurrentCameraDistance, mTargetCameraDistance, camera_lerp_amt);
3716 }
3717
3718 // Make the camera distance current
3719 local_camera_offset *= mCurrentCameraDistance;
3720
3721 // set the global camera position
3722 LLVector3d camera_offset;
3723
3724 LLVector3 av_pos = mAvatarObject.isNull() ? LLVector3::zero : mAvatarObject->getRenderPosition();
3725 camera_offset.setVec( local_camera_offset );
3726 camera_position_global = frame_center_global + head_offset + camera_offset;
3727
3728 if (!mAvatarObject.isNull())
3729 {
3730 LLVector3d camera_lag_d;
3731 F32 lag_interp = LLCriticalDamp::getInterpolant(CAMERA_LAG_HALF_LIFE);
3732 LLVector3 target_lag;
3733 LLVector3 vel = getVelocity();
3734
3735 // lag by appropriate amount for flying
3736 F32 time_in_air = mAvatarObject->mTimeInAir.getElapsedTimeF32();
3737 if(!mCameraAnimating && mAvatarObject->mInAir && time_in_air > GROUND_TO_AIR_CAMERA_TRANSITION_START_TIME)
3738 {
3739 LLVector3 frame_at_axis = mFrameAgent.getAtAxis();
3740 frame_at_axis -= projected_vec(frame_at_axis, getReferenceUpVector());
3741 frame_at_axis.normVec();
3742
3743 //transition smoothly in air mode, to avoid camera pop
3744 F32 u = (time_in_air - GROUND_TO_AIR_CAMERA_TRANSITION_START_TIME) / GROUND_TO_AIR_CAMERA_TRANSITION_TIME;
3745 u = llclamp(u, 0.f, 1.f);
3746
3747 lag_interp *= u;
3748
3749 if (gViewerWindow->getLeftMouseDown() && gLastHitObjectID == mAvatarObject->getID())
3750 {
3751 // disable camera lag when using mouse-directed steering
3752 target_lag.clearVec();
3753 }
3754 else
3755 {
3756 target_lag = vel * gSavedSettings.getF32("DynamicCameraStrength") / 30.f;
3757 }
3758
3759 mCameraLag = lerp(mCameraLag, target_lag, lag_interp);
3760
3761 F32 lag_dist = mCameraLag.magVec();
3762 if (lag_dist > MAX_CAMERA_LAG)
3763 {
3764 mCameraLag = mCameraLag * MAX_CAMERA_LAG / lag_dist;
3765 }
3766
3767 // clamp camera lag so that avatar is always in front
3768 F32 dot = (mCameraLag - (frame_at_axis * (MIN_CAMERA_LAG * u))) * frame_at_axis;
3769 if (dot < -(MIN_CAMERA_LAG * u))
3770 {
3771 mCameraLag -= (dot + (MIN_CAMERA_LAG * u)) * frame_at_axis;
3772 }
3773 }
3774 else
3775 {
3776 mCameraLag = lerp(mCameraLag, LLVector3::zero, LLCriticalDamp::getInterpolant(0.15f));
3777 }
3778
3779 camera_lag_d.setVec(mCameraLag);
3780 camera_position_global = camera_position_global - camera_lag_d;
3781 }
3782 }
3783 }
3784 else
3785 {
3786 LLVector3d focusPosGlobal = calcFocusPositionTargetGlobal();
3787 // camera gets pushed out later wrt mCameraFOVZoomFactor...this is "raw" value
3788 camera_position_global = focusPosGlobal + mCameraFocusOffset;
3789 }
3790
3791 if (!LLViewerCamera::sDisableCameraConstraints && !gAgent.isGodlike())
3792 {
3793 LLViewerRegion* regionp = gWorldPointer->getRegionFromPosGlobal(
3794 camera_position_global);
3795 bool constrain = true;
3796 if(regionp && regionp->canManageEstate())
3797 {
3798 constrain = false;
3799 }
3800 if(constrain)
3801 {
3802 F32 max_dist = ( CAMERA_MODE_CUSTOMIZE_AVATAR == mCameraMode ) ?
3803 APPEARANCE_MAX_ZOOM : MAX_CAMERA_DISTANCE_FROM_AGENT;
3804
3805 LLVector3d camera_offset = camera_position_global
3806 - gAgent.getPositionGlobal();
3807 F32 camera_distance = (F32)camera_offset.magVec();
3808
3809 if(camera_distance > max_dist)
3810 {
3811 camera_position_global = gAgent.getPositionGlobal() +
3812 (max_dist / camera_distance) * camera_offset;
3813 isConstrained = TRUE;
3814 }
3815 }
3816
3817// JC - Could constrain camera based on parcel stuff here.
3818// LLViewerRegion *regionp = gWorldPointer->getRegionFromPosGlobal(camera_position_global);
3819//
3820// if (regionp && !regionp->mParcelOverlay->isBuildCameraAllowed(regionp->getPosRegionFromGlobal(camera_position_global)))
3821// {
3822// camera_position_global = last_position_global;
3823//
3824// isConstrained = TRUE;
3825// }
3826 }
3827
3828 // Don't let camera go underground
3829 F32 camera_min_off_ground = getCameraMinOffGround();
3830
3831 if (gWorldPointer)
3832 {
3833 camera_land_height = gWorldPointer->resolveLandHeightGlobal(camera_position_global);
3834 }
3835 else
3836 {
3837 camera_land_height = 0.f;
3838 }
3839
3840 if (camera_position_global.mdV[VZ] < camera_land_height + camera_min_off_ground)
3841 {
3842 camera_position_global.mdV[VZ] = camera_land_height + camera_min_off_ground;
3843
3844 gMinObjectDistance = MIN_NEAR_PLANE;
3845 isConstrained = TRUE;
3846 }
3847
3848
3849 if (hit_limit)
3850 {
3851 *hit_limit = isConstrained;
3852 }
3853
3854 return camera_position_global;
3855}
3856
3857
3858//-----------------------------------------------------------------------------
3859// handleScrollWheel()
3860//-----------------------------------------------------------------------------
3861void LLAgent::handleScrollWheel(S32 clicks)
3862{
3863 if ( mCameraMode == CAMERA_MODE_FOLLOW && gAgent.getFocusOnAvatar())
3864 {
3865 if ( ! mFollowCam.getPositionLocked() ) // not if the followCam position is locked in place
3866 {
3867 mFollowCam.zoom( clicks );
3868 if ( mFollowCam.isZoomedToMinimumDistance() )
3869 {
3870 changeCameraToMouselook(FALSE);
3871 }
3872 }
3873 }
3874 else
3875 {
3876 const F32 ROOT_ROOT_TWO = sqrt(F_SQRT2);
3877
3878 // Block if camera is animating
3879 if (mCameraAnimating)
3880 {
3881 return;
3882 }
3883
3884 if (gSelectMgr->getObjectCount() && gSelectMgr->getSelectType() == SELECT_TYPE_HUD)
3885 {
3886 F32 zoom_factor = (F32)pow(0.8, -clicks);
3887 cameraZoomIn(zoom_factor);
3888 }
3889 else if (mFocusOnAvatar && mCameraMode == CAMERA_MODE_THIRD_PERSON)
3890 {
3891 F32 current_zoom_fraction = mTargetCameraDistance / mCameraOffsetDefault.magVec();
3892 current_zoom_fraction *= 1.f - pow(ROOT_ROOT_TWO, clicks);
3893
3894 cameraOrbitIn(current_zoom_fraction * mCameraOffsetDefault.magVec());
3895 }
3896 else
3897 {
3898 F32 current_zoom_fraction = (F32)mCameraFocusOffsetTarget.magVec();
3899 cameraOrbitIn(current_zoom_fraction * (1.f - pow(ROOT_ROOT_TWO, clicks)));
3900 }
3901 }
3902}
3903
3904
3905//-----------------------------------------------------------------------------
3906// getCameraMinOffGround()
3907//-----------------------------------------------------------------------------
3908F32 LLAgent::getCameraMinOffGround()
3909{
3910 if (mCameraMode == CAMERA_MODE_MOUSELOOK)
3911 {
3912 return 0.f;
3913 }
3914 else
3915 {
3916 if (LLViewerCamera::sDisableCameraConstraints)
3917 {
3918 return -1000.f;
3919 }
3920 else
3921 {
3922 return 0.5f;
3923 }
3924 }
3925}
3926
3927
3928//-----------------------------------------------------------------------------
3929// resetCamera()
3930//-----------------------------------------------------------------------------
3931void LLAgent::resetCamera()
3932{
3933 // Remove any pitch from the avatar
3934 LLVector3 at = mFrameAgent.getAtAxis();
3935 at.mV[VZ] = 0.f;
3936 at.normVec();
3937 gAgent.resetAxes(at);
3938 // have to explicitly clear field of view zoom now
3939 mCameraFOVZoomFactor = 0.f;
3940
3941 updateCamera();
3942}
3943
3944//-----------------------------------------------------------------------------
3945// changeCameraToMouselook()
3946//-----------------------------------------------------------------------------
3947void LLAgent::changeCameraToMouselook(BOOL animate)
3948{
3949 // visibility changes at end of animation
3950 gViewerWindow->getWindow()->resetBusyCount();
3951
3952 // unpause avatar animation
3953 mPauseRequest = NULL;
3954
3955 gCurrentToolset = gMouselookToolset;
3956 gCurrentToolset->selectFirstTool();
3957 gToolMgr->useSelectedTool( gCurrentToolset );
3958
3959 gSavedSettings.setBOOL("FirstPersonBtnState", FALSE);
3960 gSavedSettings.setBOOL("MouselookBtnState", TRUE);
3961 gSavedSettings.setBOOL("ThirdPersonBtnState", FALSE);
3962 gSavedSettings.setBOOL("BuildBtnState", FALSE);
3963
3964 if (mAvatarObject)
3965 {
3966 mAvatarObject->stopMotion( ANIM_AGENT_BODY_NOISE );
3967 mAvatarObject->stopMotion( ANIM_AGENT_BREATHE_ROT );
3968 }
3969
3970 //gViewerWindow->stopGrab();
3971 gSelectMgr->deselectAll();
3972 gViewerWindow->hideCursor();
3973 gViewerWindow->moveCursorToCenter();
3974
3975 if( mCameraMode != CAMERA_MODE_MOUSELOOK )
3976 {
3977 gViewerWindow->setKeyboardFocus( NULL, NULL );
3978
3979 mLastCameraMode = mCameraMode;
3980 mCameraMode = CAMERA_MODE_MOUSELOOK;
3981 U32 old_flags = mControlFlags;
3982 setControlFlags(AGENT_CONTROL_MOUSELOOK);
3983 if (old_flags != mControlFlags)
3984 {
3985 mbFlagsDirty = TRUE;
3986 }
3987
3988 if (animate)
3989 {
3990 startCameraAnimation();
3991 }
3992 else
3993 {
3994 mCameraAnimating = FALSE;
3995 endAnimationUpdateUI();
3996 }
3997 }
3998}
3999
4000
4001//-----------------------------------------------------------------------------
4002// changeCameraToDefault()
4003//-----------------------------------------------------------------------------
4004void LLAgent::changeCameraToDefault()
4005{
4006 if (LLFollowCamMgr::getActiveFollowCamParams())
4007 {
4008 changeCameraToFollow();
4009 }
4010 else
4011 {
4012 changeCameraToThirdPerson();
4013 }
4014}
4015
4016
4017// Ventrella
4018//-----------------------------------------------------------------------------
4019// changeCameraToFollow()
4020//-----------------------------------------------------------------------------
4021void LLAgent::changeCameraToFollow(BOOL animate)
4022{
4023 if( mCameraMode != CAMERA_MODE_FOLLOW )
4024 {
4025 if (mCameraMode == CAMERA_MODE_MOUSELOOK)
4026 {
4027 animate = FALSE;
4028 }
4029 startCameraAnimation();
4030
4031 mLastCameraMode = mCameraMode;
4032 mCameraMode = CAMERA_MODE_FOLLOW;
4033
4034 // bang-in the current focus, position, and up vector of the follow cam
4035 mFollowCam.reset( mCameraPositionAgent, gCamera->getPointOfInterest(), LLVector3::z_axis );
4036
4037 if (gBasicToolset)
4038 {
4039 gCurrentToolset = gBasicToolset;
4040 gCurrentToolset->selectFirstTool();
4041 gToolMgr->useSelectedTool( gCurrentToolset );
4042 }
4043
4044 if (mAvatarObject)
4045 {
4046 mAvatarObject->mPelvisp->setPosition(LLVector3::zero);
4047 mAvatarObject->startMotion( ANIM_AGENT_BODY_NOISE );
4048 mAvatarObject->startMotion( ANIM_AGENT_BREATHE_ROT );
4049 }
4050
4051 gSavedSettings.setBOOL("FirstPersonBtnState", FALSE);
4052 gSavedSettings.setBOOL("MouselookBtnState", FALSE);
4053 gSavedSettings.setBOOL("ThirdPersonBtnState", TRUE);
4054 gSavedSettings.setBOOL("BuildBtnState", FALSE);
4055
4056 // unpause avatar animation
4057 mPauseRequest = NULL;
4058
4059 U32 old_flags = mControlFlags;
4060 clearControlFlags(AGENT_CONTROL_MOUSELOOK);
4061 if (old_flags != mControlFlags)
4062 {
4063 mbFlagsDirty = TRUE;
4064 }
4065
4066 //RN: this doesn't seem to be necessary and destroys the UE for script-driven cameras
4067 //gViewerWindow->setKeyboardFocus( NULL, NULL );
4068 //gViewerWindow->setMouseCapture( NULL, NULL );
4069
4070 if (animate)
4071 {
4072 startCameraAnimation();
4073 }
4074 else
4075 {
4076 mCameraAnimating = FALSE;
4077 endAnimationUpdateUI();
4078 }
4079 }
4080}
4081
4082//-----------------------------------------------------------------------------
4083// changeCameraToThirdPerson()
4084//-----------------------------------------------------------------------------
4085void LLAgent::changeCameraToThirdPerson(BOOL animate)
4086{
4087//printf( "changeCameraToThirdPerson\n" );
4088
4089 gViewerWindow->getWindow()->resetBusyCount();
4090
4091 mCameraZoomFraction = INITIAL_ZOOM_FRACTION;
4092
4093 if (mAvatarObject)
4094 {
4095 mAvatarObject->mPelvisp->setPosition(LLVector3::zero);
4096 mAvatarObject->startMotion( ANIM_AGENT_BODY_NOISE );
4097 mAvatarObject->startMotion( ANIM_AGENT_BREATHE_ROT );
4098 }
4099
4100 gSavedSettings.setBOOL("FirstPersonBtnState", FALSE);
4101 gSavedSettings.setBOOL("MouselookBtnState", FALSE);
4102 gSavedSettings.setBOOL("ThirdPersonBtnState", TRUE);
4103 gSavedSettings.setBOOL("BuildBtnState", FALSE);
4104
4105 LLVector3 at_axis;
4106
4107 // unpause avatar animation
4108 mPauseRequest = NULL;
4109
4110 if( mCameraMode != CAMERA_MODE_THIRD_PERSON )
4111 {
4112 if (gBasicToolset)
4113 {
4114 gCurrentToolset = gBasicToolset;
4115 gCurrentToolset->selectFirstTool();
4116 gToolMgr->useSelectedTool( gCurrentToolset );
4117 }
4118
4119 mCameraLag.clearVec();
4120 if (mCameraMode == CAMERA_MODE_MOUSELOOK)
4121 {
4122 mCurrentCameraDistance = MIN_CAMERA_DISTANCE;
4123 mTargetCameraDistance = MIN_CAMERA_DISTANCE;
4124 animate = FALSE;
4125 }
4126 mLastCameraMode = mCameraMode;
4127 mCameraMode = CAMERA_MODE_THIRD_PERSON;
4128 U32 old_flags = mControlFlags;
4129 clearControlFlags(AGENT_CONTROL_MOUSELOOK);
4130 if (old_flags != mControlFlags)
4131 {
4132 mbFlagsDirty = TRUE;
4133 }
4134
4135 //RN: this doesn't seem to be necessary and destroys the UE for script-driven cameras
4136 //gViewerWindow->setKeyboardFocus( NULL, NULL );
4137 //gViewerWindow->setMouseCapture( NULL, NULL );
4138 }
4139
4140 // Remove any pitch from the avatar
4141 if (!mAvatarObject.isNull() && mAvatarObject->getParent())
4142 {
4143 LLQuaternion obj_rot = ((LLViewerObject*)mAvatarObject->getParent())->getRenderRotation();
4144 at_axis = gCamera->getAtAxis();
4145 at_axis.mV[VZ] = 0.f;
4146 at_axis.normVec();
4147 resetAxes(at_axis * ~obj_rot);
4148 }
4149 else
4150 {
4151 at_axis = mFrameAgent.getAtAxis();
4152 at_axis.mV[VZ] = 0.f;
4153 at_axis.normVec();
4154 resetAxes(at_axis);
4155 }
4156
4157
4158 if (animate)
4159 {
4160 startCameraAnimation();
4161 }
4162 else
4163 {
4164 mCameraAnimating = FALSE;
4165 endAnimationUpdateUI();
4166 }
4167}
4168
4169//-----------------------------------------------------------------------------
4170// changeCameraToCustomizeAvatar()
4171//-----------------------------------------------------------------------------
4172void LLAgent::changeCameraToCustomizeAvatar(BOOL animate)
4173{
4174 setControlFlags(AGENT_CONTROL_STAND_UP); // force stand up
4175 gViewerWindow->getWindow()->resetBusyCount();
4176
4177 if (gFaceEditToolset)
4178 {
4179 gCurrentToolset = gFaceEditToolset;
4180 gCurrentToolset->selectFirstTool();
4181 gToolMgr->useSelectedTool( gCurrentToolset );
4182 }
4183
4184 gSavedSettings.setBOOL("FirstPersonBtnState", FALSE);
4185 gSavedSettings.setBOOL("MouselookBtnState", FALSE);
4186 gSavedSettings.setBOOL("ThirdPersonBtnState", FALSE);
4187 gSavedSettings.setBOOL("BuildBtnState", FALSE);
4188
4189 if (animate)
4190 {
4191 startCameraAnimation();
4192 }
4193
4194 // Remove any pitch from the avatar
4195 LLVector3 at = mFrameAgent.getAtAxis();
4196 at.mV[VZ] = 0.f;
4197 at.normVec();
4198 gAgent.resetAxes(at);
4199
4200 if( mCameraMode != CAMERA_MODE_CUSTOMIZE_AVATAR )
4201 {
4202 mLastCameraMode = mCameraMode;
4203 mCameraMode = CAMERA_MODE_CUSTOMIZE_AVATAR;
4204 U32 old_flags = mControlFlags;
4205 clearControlFlags(AGENT_CONTROL_MOUSELOOK);
4206 if (old_flags != mControlFlags)
4207 {
4208 mbFlagsDirty = TRUE;
4209 }
4210
4211 gViewerWindow->setKeyboardFocus( NULL, NULL );
4212 gViewerWindow->setMouseCapture( NULL, NULL );
4213
4214 LLVOAvatar::onCustomizeStart();
4215 }
4216
4217 if (animate && !mAvatarObject.isNull())
4218 {
4219 sendAnimationRequest(ANIM_AGENT_CUSTOMIZE, ANIM_REQUEST_START);
4220 LLMotion* turn_motion = mAvatarObject->findMotion(ANIM_AGENT_CUSTOMIZE);
4221 if (turn_motion)
4222 {
4223 mAnimationDuration = turn_motion->getDuration() + CUSTOMIZE_AVATAR_CAMERA_ANIM_SLOP;
4224 }
4225 else
4226 {
4227 mAnimationDuration = gSavedSettings.getF32("ZoomTime");
4228 }
4229 gAgent.setFocusGlobal(LLVector3d::zero);
4230 }
4231 else
4232 {
4233 mCameraAnimating = FALSE;
4234 endAnimationUpdateUI();
4235 }
4236
4237}
4238
4239
4240//
4241// Focus point management
4242//
4243
4244//-----------------------------------------------------------------------------
4245// startCameraAnimation()
4246//-----------------------------------------------------------------------------
4247void LLAgent::startCameraAnimation()
4248{
4249 mAnimationCameraStartGlobal = getCameraPositionGlobal();
4250 mAnimationFocusStartGlobal = mFocusGlobal;
4251 mAnimationTimer.reset();
4252 mCameraAnimating = TRUE;
4253 mAnimationDuration = gSavedSettings.getF32("ZoomTime");
4254}
4255
4256//-----------------------------------------------------------------------------
4257// stopCameraAnimation()
4258//-----------------------------------------------------------------------------
4259void LLAgent::stopCameraAnimation()
4260{
4261 mCameraAnimating = FALSE;
4262}
4263
4264void LLAgent::clearFocusObject()
4265{
4266 if (mFocusObject.notNull())
4267 {
4268 startCameraAnimation();
4269
4270 setFocusObject(NULL);
4271 mFocusObjectOffset.clearVec();
4272 }
4273}
4274
4275void LLAgent::setFocusObject(LLViewerObject* object)
4276{
4277 if (mFocusObject.notNull() &&
4278 mFocusObject->mDrawable.notNull() &&
4279 mFocusObject->getPCode() == LL_PCODE_VOLUME &&
4280 mFocusObject != object)
4281 {
4282 LLPointer<LLViewerObject> fade_object_ptr(mFocusObject);
4283
4284 if (fade_object_ptr.notNull() && mFadeObjects.find(fade_object_ptr) == mFadeObjects.end())
4285 {
4286 mFadeObjects.insert(fade_object_ptr);
4287 }
4288 }
4289
4290 mFocusObject = object;
4291}
4292
4293// Focus on a point, but try to keep camera position stable.
4294//-----------------------------------------------------------------------------
4295// setFocusGlobal()
4296//-----------------------------------------------------------------------------
4297void LLAgent::setFocusGlobal(const LLVector3d& focus, const LLUUID &object_id)
4298{
4299 setFocusObject(gObjectList.findObject(object_id));
4300 LLVector3d old_focus = mFocusTargetGlobal;
4301 LLViewerObject *focus_obj = mFocusObject;
4302
4303 // if focus has changed
4304 if (old_focus != focus)
4305 {
4306 if (focus.isExactlyZero())
4307 {
4308 if (!mAvatarObject.isNull())
4309 {
4310 mFocusTargetGlobal = getPosGlobalFromAgent(mAvatarObject->mHeadp->getWorldPosition());
4311 }
4312 else
4313 {
4314 mFocusTargetGlobal = getPositionGlobal();
4315 }
4316 mCameraFocusOffsetTarget = getCameraPositionGlobal() - mFocusTargetGlobal;
4317 mCameraFocusOffset = mCameraFocusOffsetTarget;
4318 setLookAt(LOOKAT_TARGET_CLEAR);
4319 }
4320 else
4321 {
4322 mFocusTargetGlobal = focus;
4323 if (!focus_obj)
4324 {
4325 mCameraFOVZoomFactor = 0.f;
4326 }
4327
4328 mCameraFocusOffsetTarget = gAgent.getPosGlobalFromAgent(mCameraVirtualPositionAgent) - mFocusTargetGlobal;
4329
4330 startCameraAnimation();
4331
4332 if (focus_obj)
4333 {
4334 if (focus_obj->isAvatar())
4335 {
4336 setLookAt(LOOKAT_TARGET_FOCUS, focus_obj);
4337 }
4338 else
4339 {
4340 setLookAt(LOOKAT_TARGET_FOCUS, focus_obj, (getPosAgentFromGlobal(focus) - focus_obj->getRenderPosition()) * ~focus_obj->getRenderRotation());
4341 }
4342 }
4343 else
4344 {
4345 setLookAt(LOOKAT_TARGET_FOCUS, NULL, getPosAgentFromGlobal(mFocusTargetGlobal));
4346 }
4347 }
4348 }
4349 else // focus == mFocusTargetGlobal
4350 {
4351 if (focus.isExactlyZero())
4352 {
4353 if (!mAvatarObject.isNull())
4354 {
4355 mFocusTargetGlobal = getPosGlobalFromAgent(mAvatarObject->mHeadp->getWorldPosition());
4356 }
4357 else
4358 {
4359 mFocusTargetGlobal = getPositionGlobal();
4360 }
4361 }
4362 mCameraFocusOffsetTarget = (getCameraPositionGlobal() - mFocusTargetGlobal) / (1.f + mCameraFOVZoomFactor);;
4363 mCameraFocusOffset = mCameraFocusOffsetTarget;
4364 }
4365
4366 if (mFocusObject.notNull())
4367 {
4368 // for attachments, make offset relative to avatar, not the attachment
4369 if (mFocusObject->isAttachment())
4370 {
4371 while (!mFocusObject->isAvatar())
4372 {
4373 mFocusObject = (LLViewerObject*) mFocusObject->getParent();
4374 }
4375 setFocusObject((LLViewerObject*)mFocusObject);
4376 }
4377 updateFocusOffset();
4378 }
4379}
4380
4381// Used for avatar customization
4382//-----------------------------------------------------------------------------
4383// setCameraPosAndFocusGlobal()
4384//-----------------------------------------------------------------------------
4385void LLAgent::setCameraPosAndFocusGlobal(const LLVector3d& camera_pos, const LLVector3d& focus, const LLUUID &object_id)
4386{
4387 LLVector3d old_focus = mFocusTargetGlobal;
4388
4389 F64 focus_delta_squared = (old_focus - focus).magVecSquared();
4390 const F64 ANIM_EPSILON_SQUARED = 0.0001;
4391 if( focus_delta_squared > ANIM_EPSILON_SQUARED )
4392 {
4393 startCameraAnimation();
4394
4395 if( CAMERA_MODE_CUSTOMIZE_AVATAR == mCameraMode )
4396 {
4397 // Compensate for the fact that the camera has already been offset to make room for LLFloaterCustomize.
4398 mAnimationCameraStartGlobal -= LLVector3d(gCamera->getLeftAxis() * calcCustomizeAvatarUIOffset( mAnimationCameraStartGlobal ));
4399 }
4400 }
4401
4402 //gCamera->setOrigin( gAgent.getPosAgentFromGlobal( camera_pos ) );
4403 setFocusObject(gObjectList.findObject(object_id));
4404 mFocusTargetGlobal = focus;
4405 mCameraFocusOffsetTarget = camera_pos - focus;
4406 mCameraFocusOffset = mCameraFocusOffsetTarget;
4407
4408 if (mFocusObject)
4409 {
4410 if (mFocusObject->isAvatar())
4411 {
4412 setLookAt(LOOKAT_TARGET_FOCUS, mFocusObject);
4413 }
4414 else
4415 {
4416 setLookAt(LOOKAT_TARGET_FOCUS, mFocusObject, (getPosAgentFromGlobal(focus) - mFocusObject->getRenderPosition()) * ~mFocusObject->getRenderRotation());
4417 }
4418 }
4419 else
4420 {
4421 setLookAt(LOOKAT_TARGET_FOCUS, NULL, getPosAgentFromGlobal(mFocusTargetGlobal));
4422 }
4423
4424 if( mCameraAnimating )
4425 {
4426 const F64 ANIM_METERS_PER_SECOND = 10.0;
4427 const F64 MIN_ANIM_SECONDS = 0.5;
4428 F64 anim_duration = llmax( MIN_ANIM_SECONDS, sqrt(focus_delta_squared) / ANIM_METERS_PER_SECOND );
4429 setAnimationDuration( (F32)anim_duration );
4430 }
4431
4432 updateFocusOffset();
4433}
4434
4435//-----------------------------------------------------------------------------
4436// setSitCamera()
4437//-----------------------------------------------------------------------------
4438void LLAgent::setSitCamera(const LLUUID &object_id, const LLVector3 &camera_pos, const LLVector3 &camera_focus)
4439{
4440 BOOL camera_enabled = !object_id.isNull();
4441
4442 if (camera_enabled)
4443 {
4444 LLViewerObject *reference_object = gObjectList.findObject(object_id);
4445 if (reference_object)
4446 {
4447 //convert to root object relative?
4448 mSitCameraPos = camera_pos;
4449 mSitCameraFocus = camera_focus;
4450 mSitCameraReferenceObject = reference_object;
4451 mSitCameraEnabled = TRUE;
4452 }
4453 }
4454 else
4455 {
4456 mSitCameraPos.clearVec();
4457 mSitCameraFocus.clearVec();
4458 mSitCameraReferenceObject = NULL;
4459 mSitCameraEnabled = FALSE;
4460 }
4461}
4462
4463//-----------------------------------------------------------------------------
4464// setFocusOnAvatar()
4465//-----------------------------------------------------------------------------
4466void LLAgent::setFocusOnAvatar(BOOL focus_on_avatar, BOOL animate)
4467{
4468 if (focus_on_avatar != mFocusOnAvatar)
4469 {
4470 if (animate)
4471 {
4472 startCameraAnimation();
4473 }
4474 else
4475 {
4476 stopCameraAnimation();
4477 }
4478 }
4479
4480 //RN: when focused on the avatar, we're not "looking" at it
4481 // looking implies intent while focusing on avatar means
4482 // you're just walking around with a camera on you...eesh.
4483 if (focus_on_avatar && !mFocusOnAvatar)
4484 {
4485 setFocusGlobal(LLVector3d::zero);
4486 mCameraFOVZoomFactor = 0.f;
4487 if (mCameraMode == CAMERA_MODE_THIRD_PERSON)
4488 {
4489 LLVector3 at_axis;
4490 if (!mAvatarObject.isNull() && mAvatarObject->getParent())
4491 {
4492 LLQuaternion obj_rot = ((LLViewerObject*)mAvatarObject->getParent())->getRenderRotation();
4493 at_axis = gCamera->getAtAxis();
4494 at_axis.mV[VZ] = 0.f;
4495 at_axis.normVec();
4496 resetAxes(at_axis * ~obj_rot);
4497 }
4498 else
4499 {
4500 at_axis = gCamera->getAtAxis();
4501 at_axis.mV[VZ] = 0.f;
4502 at_axis.normVec();
4503 resetAxes(at_axis);
4504 }
4505 }
4506 }
4507
4508 mFocusOnAvatar = focus_on_avatar;
4509}
4510
4511//-----------------------------------------------------------------------------
4512// heardChat()
4513//-----------------------------------------------------------------------------
4514void LLAgent::heardChat(const LLChat& chat)
4515{
4516 if (chat.mChatType == CHAT_TYPE_START
4517 || chat.mChatType == CHAT_TYPE_STOP)
4518 {
4519 return;
4520 }
4521
4522 mLastChatterID = chat.mFromID;
4523 mChatTimer.reset();
4524
4525 mNearChatRadius = CHAT_NORMAL_RADIUS / 2.f;
4526}
4527
4528//-----------------------------------------------------------------------------
4529// lookAtLastChat()
4530//-----------------------------------------------------------------------------
4531void LLAgent::lookAtLastChat()
4532{
4533 // Block if camera is animating or not in normal third person camera mode
4534 if (mCameraAnimating || !cameraThirdPerson())
4535 {
4536 return;
4537 }
4538
4539 LLViewerObject *chatter = gObjectList.findObject(mLastChatterID);
4540 if (chatter)
4541 {
4542 LLVector3 delta_pos;
4543 if (chatter->isAvatar())
4544 {
4545 LLVOAvatar *chatter_av = (LLVOAvatar*)chatter;
4546 if (!mAvatarObject.isNull() && chatter_av->mHeadp)
4547 {
4548 delta_pos = chatter_av->mHeadp->getWorldPosition() - mAvatarObject->mHeadp->getWorldPosition();
4549 }
4550 else
4551 {
4552 delta_pos = chatter->getPositionAgent() - getPositionAgent();
4553 }
4554 delta_pos.normVec();
4555
4556 setControlFlags(AGENT_CONTROL_STOP);
4557
4558 changeCameraToThirdPerson();
4559
4560 LLVector3 new_camera_pos = mAvatarObject->mHeadp->getWorldPosition();
4561 LLVector3 left = delta_pos % LLVector3::z_axis;
4562 left.normVec();
4563 LLVector3 up = left % delta_pos;
4564 up.normVec();
4565 new_camera_pos -= delta_pos * 0.4f;
4566 new_camera_pos += left * 0.3f;
4567 new_camera_pos += up * 0.2f;
4568 if (chatter_av->mHeadp)
4569 {
4570 setFocusGlobal(getPosGlobalFromAgent(chatter_av->mHeadp->getWorldPosition()), mLastChatterID);
4571 mCameraFocusOffsetTarget = getPosGlobalFromAgent(new_camera_pos) - gAgent.getPosGlobalFromAgent(chatter_av->mHeadp->getWorldPosition());
4572 }
4573 else
4574 {
4575 setFocusGlobal(chatter->getPositionGlobal(), mLastChatterID);
4576 mCameraFocusOffsetTarget = getPosGlobalFromAgent(new_camera_pos) - chatter->getPositionGlobal();
4577 }
4578 setFocusOnAvatar(FALSE, TRUE);
4579 }
4580 else
4581 {
4582 delta_pos = chatter->getRenderPosition() - getPositionAgent();
4583 delta_pos.normVec();
4584
4585 setControlFlags(AGENT_CONTROL_STOP);
4586
4587 changeCameraToThirdPerson();
4588
4589 LLVector3 new_camera_pos = mAvatarObject->mHeadp->getWorldPosition();
4590 LLVector3 left = delta_pos % LLVector3::z_axis;
4591 left.normVec();
4592 LLVector3 up = left % delta_pos;
4593 up.normVec();
4594 new_camera_pos -= delta_pos * 0.4f;
4595 new_camera_pos += left * 0.3f;
4596 new_camera_pos += up * 0.2f;
4597
4598 setFocusGlobal(chatter->getPositionGlobal(), mLastChatterID);
4599 mCameraFocusOffsetTarget = getPosGlobalFromAgent(new_camera_pos) - chatter->getPositionGlobal();
4600 setFocusOnAvatar(FALSE, TRUE);
4601 }
4602 }
4603}
4604
4605const F32 SIT_POINT_EXTENTS = 0.2f;
4606
4607// Grabs current position
4608void LLAgent::setStartPosition(U32 location_id)
4609{
4610 LLViewerObject *object;
4611
4612 if ( !(gAgentID == LLUUID::null) )
4613 {
4614 // we've got an ID for an agent viewerobject
4615 object = gObjectList.findObject(gAgentID);
4616 if (object)
4617 {
4618 // we've got the viewer object
4619 // Sometimes the agent can be velocity interpolated off of
4620 // this simulator. Clamp it to the region the agent is
4621 // in, a little bit in on each side.
4622 const F32 INSET = 0.5f; //meters
4623 const F32 REGION_WIDTH = gWorldPointer->getRegionWidthInMeters();
4624
4625 LLVector3 agent_pos = getPositionAgent();
4626
4627 if (mAvatarObject)
4628 {
4629 // the z height is at the agent's feet
4630 agent_pos.mV[VZ] -= 0.5f * mAvatarObject->mBodySize.mV[VZ];
4631 }
4632
4633 agent_pos.mV[VX] = llclamp( agent_pos.mV[VX], INSET, REGION_WIDTH - INSET );
4634 agent_pos.mV[VY] = llclamp( agent_pos.mV[VY], INSET, REGION_WIDTH - INSET );
4635
4636 // Don't let them go below ground, or too high.
4637 agent_pos.mV[VZ] = llclamp( agent_pos.mV[VZ],
4638 mRegionp->getLandHeightRegion( agent_pos ),
4639 gWorldPointer->getRegionMaxHeight() );
4640
4641 LLMessageSystem* msg = gMessageSystem;
4642 msg->newMessageFast(_PREHASH_SetStartLocationRequest);
4643 msg->nextBlockFast( _PREHASH_AgentData);
4644 msg->addUUIDFast(_PREHASH_AgentID, getID());
4645 msg->addUUIDFast(_PREHASH_SessionID, getSessionID());
4646 msg->nextBlockFast( _PREHASH_StartLocationData);
4647 // corrected by sim
4648 msg->addStringFast(_PREHASH_SimName, "");
4649 msg->addU32Fast(_PREHASH_LocationID, location_id);
4650 msg->addVector3Fast(_PREHASH_LocationPos, agent_pos);
4651 msg->addVector3Fast(_PREHASH_LocationLookAt,mFrameAgent.getAtAxis());
4652
4653 // Reliable only helps when setting home location. Last
4654 // location is sent on quit, and we don't have time to ack
4655 // the packets.
4656 msg->sendReliable(mRegionp->getHost());
4657
4658 const U32 HOME_INDEX = 1;
4659 if( HOME_INDEX == location_id )
4660 {
4661 setHomePosRegion( mRegionp->getHandle(), getPositionAgent() );
4662 }
4663 }
4664 else
4665 {
4666 llinfos << "setStartPosition - Can't find agent viewerobject id " << gAgentID << llendl;
4667 }
4668 }
4669}
4670
4671void LLAgent::requestStopMotion( LLMotion* motion )
4672{
4673 // Notify all avatars that a motion has stopped.
4674 // This is needed to clear the animation state bits
4675 LLUUID anim_state = motion->getID();
4676
4677 // if motion is not looping, it could have stopped by running out of time
4678 // so we need to tell the server this
4679// llinfos << "Sending stop for motion " << motion->getName() << llendl;
4680 sendAnimationRequest( anim_state, ANIM_REQUEST_STOP );
4681
4682 // handle automatic state transitions (based on completion of animation playback)
4683 if (anim_state == ANIM_AGENT_STANDUP)
4684 {
4685 // send stand up command
4686 setControlFlags(AGENT_CONTROL_FINISH_ANIM);
4687
4688 // now trigger dusting self off animation
4689 if (mAvatarObject.notNull() && !mAvatarObject->mBelowWater && rand() % 3 == 0)
4690 sendAnimationRequest( ANIM_AGENT_BRUSH, ANIM_REQUEST_START );
4691 }
4692 else if (anim_state == ANIM_AGENT_PRE_JUMP || anim_state == ANIM_AGENT_LAND || anim_state == ANIM_AGENT_MEDIUM_LAND)
4693 {
4694 setControlFlags(AGENT_CONTROL_FINISH_ANIM);
4695 }
4696}
4697
4698BOOL LLAgent::isGodlike() const
4699{
4700#ifdef HACKED_GODLIKE_VIEWER
4701 return TRUE;
4702#else
4703 if(mAdminOverride) return TRUE;
4704 return mGodLevel > GOD_NOT;
4705#endif
4706}
4707
4708U8 LLAgent::getGodLevel() const
4709{
4710#ifdef HACKED_GODLIKE_VIEWER
4711 return GOD_MAINTENANCE;
4712#else
4713 if(mAdminOverride) return GOD_FULL;
4714 return mGodLevel;
4715#endif
4716}
4717
4718
4719void LLAgent::buildFullname(std::string& name) const
4720{
4721 if (mAvatarObject)
4722 {
4723 name = mAvatarObject->getFullname();
4724 }
4725}
4726
4727void LLAgent::buildFullnameAndTitle(std::string& name) const
4728{
4729 if (isGroupMember())
4730 {
4731 name = mGroupTitle;
4732 name += ' ';
4733 }
4734 else
4735 {
4736 name.erase(0, name.length());
4737 }
4738
4739 if (mAvatarObject)
4740 {
4741 name += mAvatarObject->getFullname();
4742 }
4743}
4744
4745BOOL LLAgent::isInGroup(const LLUUID& group_id) const
4746{
4747 S32 count = mGroups.count();
4748 for(S32 i = 0; i < count; ++i)
4749 {
4750 if(mGroups.get(i).mID == group_id)
4751 {
4752 return TRUE;
4753 }
4754 }
4755 return FALSE;
4756}
4757
4758// This implementation should mirror LLAgentInfo::hasPowerInGroup
4759BOOL LLAgent::hasPowerInGroup(const LLUUID& group_id, U64 power) const
4760{
4761 // GP_NO_POWERS can also mean no power is enough to grant an ability.
4762 if (GP_NO_POWERS == power) return FALSE;
4763
4764 S32 count = mGroups.count();
4765 for(S32 i = 0; i < count; ++i)
4766 {
4767 if(mGroups.get(i).mID == group_id)
4768 {
4769 return (BOOL)((mGroups.get(i).mPowers & power) > 0);
4770 }
4771 }
4772 return FALSE;
4773}
4774
4775BOOL LLAgent::hasPowerInActiveGroup(U64 power) const
4776{
4777 return (mGroupID.notNull() && (hasPowerInGroup(mGroupID, power)));
4778}
4779
4780U64 LLAgent::getPowerInGroup(const LLUUID& group_id) const
4781{
4782 S32 count = mGroups.count();
4783 for(S32 i = 0; i < count; ++i)
4784 {
4785 if(mGroups.get(i).mID == group_id)
4786 {
4787 return (mGroups.get(i).mPowers);
4788 }
4789 }
4790
4791 return GP_NO_POWERS;
4792}
4793
4794BOOL LLAgent::getGroupData(const LLUUID& group_id, LLGroupData& data) const
4795{
4796 S32 count = mGroups.count();
4797 for(S32 i = 0; i < count; ++i)
4798 {
4799 if(mGroups.get(i).mID == group_id)
4800 {
4801 data = mGroups.get(i);
4802 return TRUE;
4803 }
4804 }
4805 return FALSE;
4806}
4807
4808S32 LLAgent::getGroupContribution(const LLUUID& group_id) const
4809{
4810 S32 count = mGroups.count();
4811 for(S32 i = 0; i < count; ++i)
4812 {
4813 if(mGroups.get(i).mID == group_id)
4814 {
4815 S32 contribution = mGroups.get(i).mContribution;
4816 return contribution;
4817 }
4818 }
4819 return 0;
4820}
4821
4822BOOL LLAgent::setGroupContribution(const LLUUID& group_id, S32 contribution)
4823{
4824 S32 count = mGroups.count();
4825 for(S32 i = 0; i < count; ++i)
4826 {
4827 if(mGroups.get(i).mID == group_id)
4828 {
4829 mGroups.get(i).mContribution = contribution;
4830 LLMessageSystem* msg = gMessageSystem;
4831 msg->newMessage("SetGroupContribution");
4832 msg->nextBlock("AgentData");
4833 msg->addUUID("AgentID", gAgentID);
4834 msg->addUUID("SessionID", gAgentSessionID);
4835 msg->nextBlock("Data");
4836 msg->addUUID("GroupID", group_id);
4837 msg->addS32("Contribution", contribution);
4838 sendReliableMessage();
4839 return TRUE;
4840 }
4841 }
4842 return FALSE;
4843}
4844
4845BOOL LLAgent::setGroupAcceptNotices(const LLUUID& group_id, BOOL accept_notices)
4846{
4847 S32 count = mGroups.count();
4848 for(S32 i = 0; i < count; ++i)
4849 {
4850 if(mGroups.get(i).mID == group_id)
4851 {
4852 mGroups.get(i).mAcceptNotices = accept_notices;
4853 LLMessageSystem* msg = gMessageSystem;
4854 msg->newMessage("SetGroupAcceptNotices");
4855 msg->nextBlock("AgentData");
4856 msg->addUUID("AgentID", gAgentID);
4857 msg->addUUID("SessionID", gAgentSessionID);
4858 msg->nextBlock("Data");
4859 msg->addUUID("GroupID", group_id);
4860 msg->addBOOL("AcceptNotices", accept_notices);
4861 sendReliableMessage();
4862 return TRUE;
4863 }
4864 }
4865 return FALSE;
4866}
4867
4868// utility to build a location string
4869void LLAgent::buildLocationString(std::string& str)
4870{
4871 const LLVector3& agent_pos_region = getPositionAgent();
4872 S32 pos_x = S32(agent_pos_region.mV[VX]);
4873 S32 pos_y = S32(agent_pos_region.mV[VY]);
4874 S32 pos_z = S32(agent_pos_region.mV[VZ]);
4875
4876 // Round the numbers based on the velocity
4877 LLVector3 agent_velocity = getVelocity();
4878 F32 velocity_mag_sq = agent_velocity.magVecSquared();
4879
4880 const F32 FLY_CUTOFF = 6.f; // meters/sec
4881 const F32 FLY_CUTOFF_SQ = FLY_CUTOFF * FLY_CUTOFF;
4882 const F32 WALK_CUTOFF = 1.5f; // meters/sec
4883 const F32 WALK_CUTOFF_SQ = WALK_CUTOFF * WALK_CUTOFF;
4884
4885 if (velocity_mag_sq > FLY_CUTOFF_SQ)
4886 {
4887 pos_x -= pos_x % 4;
4888 pos_y -= pos_y % 4;
4889 }
4890 else if (velocity_mag_sq > WALK_CUTOFF_SQ)
4891 {
4892 pos_x -= pos_x % 2;
4893 pos_y -= pos_y % 2;
4894 }
4895
4896 // create a defult name and description for the landmark
4897 std::string buffer;
4898 if( !strcmp("", gParcelMgr->getAgentParcelName()) )
4899 {
4900 // the parcel doesn't have a name
4901 buffer = llformat("%.32s (%d, %d, %d)",
4902 getRegion()->getName().c_str(),
4903 pos_x, pos_y, pos_z);
4904 }
4905 else
4906 {
4907 // the parcel has a name, so include it in the landmark name
4908 buffer = llformat("%.32s, %.32s (%d, %d, %d)",
4909 gParcelMgr->getAgentParcelName(),
4910 getRegion()->getName().c_str(),
4911 pos_x, pos_y, pos_z);
4912 }
4913 str = buffer;
4914}
4915
4916LLQuaternion LLAgent::getHeadRotation()
4917{
4918 if (mAvatarObject.isNull() || !mAvatarObject->mPelvisp || !mAvatarObject->mHeadp)
4919 {
4920 return LLQuaternion::DEFAULT;
4921 }
4922
4923 if (!gAgent.cameraMouselook())
4924 {
4925 return mAvatarObject->getRotation();
4926 }
4927
4928 // We must be in mouselook
4929 LLVector3 look_dir( gCamera->getAtAxis() );
4930 LLVector3 up = look_dir % mFrameAgent.getLeftAxis();
4931 LLVector3 left = up % look_dir;
4932
4933 LLQuaternion rot(look_dir, left, up);
4934 if (mAvatarObject->getParent())
4935 {
4936 rot = rot * ~mAvatarObject->getParent()->getRotation();
4937 }
4938
4939 return rot;
4940}
4941
4942void LLAgent::sendAnimationRequests(LLDynamicArray<LLUUID> &anim_ids, EAnimRequest request)
4943{
4944 if (gAgentID.isNull())
4945 {
4946 return;
4947 }
4948
4949 S32 num_valid_anims = 0;
4950
4951 LLMessageSystem* msg = gMessageSystem;
4952 msg->newMessageFast(_PREHASH_AgentAnimation);
4953 msg->nextBlockFast(_PREHASH_AgentData);
4954 msg->addUUIDFast(_PREHASH_AgentID, getID());
4955 msg->addUUIDFast(_PREHASH_SessionID, getSessionID());
4956
4957 for (S32 i = 0; i < anim_ids.count(); i++)
4958 {
4959 if (anim_ids[i].isNull())
4960 {
4961 continue;
4962 }
4963 msg->nextBlockFast(_PREHASH_AnimationList);
4964 msg->addUUIDFast(_PREHASH_AnimID, (anim_ids[i]) );
4965 msg->addBOOLFast(_PREHASH_StartAnim, (request == ANIM_REQUEST_START) ? TRUE : FALSE);
4966 num_valid_anims++;
4967 }
4968
4969 if (num_valid_anims)
4970 {
4971 sendReliableMessage();
4972 }
4973}
4974
4975void LLAgent::sendAnimationRequest(const LLUUID &anim_id, EAnimRequest request)
4976{
4977 if (gAgentID.isNull() || anim_id.isNull() || !mRegionp)
4978 {
4979 return;
4980 }
4981
4982 LLMessageSystem* msg = gMessageSystem;
4983 msg->newMessageFast(_PREHASH_AgentAnimation);
4984 msg->nextBlockFast(_PREHASH_AgentData);
4985 msg->addUUIDFast(_PREHASH_AgentID, getID());
4986 msg->addUUIDFast(_PREHASH_SessionID, getSessionID());
4987
4988 msg->nextBlockFast(_PREHASH_AnimationList);
4989 msg->addUUIDFast(_PREHASH_AnimID, (anim_id) );
4990 msg->addBOOLFast(_PREHASH_StartAnim, (request == ANIM_REQUEST_START) ? TRUE : FALSE);
4991
4992 sendReliableMessage();
4993}
4994
4995void LLAgent::friendsChanged()
4996{
4997 LLCollectProxyBuddies collector;
4998 LLAvatarTracker::instance().applyFunctor(collector);
4999 mProxyForAgents = collector.mProxy;
5000}
5001
5002BOOL LLAgent::isGrantedProxy(const LLPermissions& perm)
5003{
5004 return (mProxyForAgents.count(perm.getOwner()) > 0);
5005}
5006
5007BOOL LLAgent::allowOperation(PermissionBit op,
5008 const LLPermissions& perm,
5009 U64 group_proxy_power,
5010 U8 god_minimum)
5011{
5012 // Check god level.
5013 if (getGodLevel() >= god_minimum) return TRUE;
5014
5015 if (!perm.isOwned()) return FALSE;
5016
5017 // A group member with group_proxy_power can act as owner.
5018 BOOL is_group_owned;
5019 LLUUID owner_id;
5020 perm.getOwnership(owner_id, is_group_owned);
5021 LLUUID group_id(perm.getGroup());
5022 LLUUID agent_proxy(getID());
5023
5024 if (is_group_owned)
5025 {
5026 if (hasPowerInGroup(group_id, group_proxy_power))
5027 {
5028 // Let the member assume the group's id for permission requests.
5029 agent_proxy = owner_id;
5030 }
5031 }
5032 else
5033 {
5034 // Check for granted mod permissions.
5035 if ((PERM_OWNER != op) && isGrantedProxy(perm))
5036 {
5037 agent_proxy = owner_id;
5038 }
5039 }
5040
5041 // This is the group id to use for permission requests.
5042 // Only group members may use this field.
5043 LLUUID group_proxy = LLUUID::null;
5044 if (group_id.notNull() && isInGroup(group_id))
5045 {
5046 group_proxy = group_id;
5047 }
5048
5049 // We now have max ownership information.
5050 if (PERM_OWNER == op)
5051 {
5052 // This this was just a check for ownership, we can now return the answer.
5053 return (agent_proxy == owner_id);
5054 }
5055
5056 return perm.allowOperationBy(op, agent_proxy, group_proxy);
5057}
5058
5059
5060void LLAgent::getName(LLString& name)
5061{
5062 // Note: assumes that name points to a buffer of at least DB_FULL_NAME_BUF_SIZE bytes.
5063 name.clear();
5064
5065 if (mAvatarObject)
5066 {
5067 LLNameValue *first_nv = mAvatarObject->getNVPair("FirstName");
5068 LLNameValue *last_nv = mAvatarObject->getNVPair("LastName");
5069 if (first_nv && last_nv)
5070 {
5071 name = first_nv->printData() + " " + last_nv->printData();
5072 }
5073 else
5074 {
5075 llwarns << "Agent is missing FirstName and/or LastName nv pair." << llendl;
5076 }
5077 }
5078 else
5079 {
5080 name = gSavedSettings.getString("FirstName") + " " + gSavedSettings.getString("LastName");
5081 }
5082}
5083
5084const LLColor4 &LLAgent::getEffectColor()
5085{
5086 return mEffectColor;
5087}
5088
5089void LLAgent::setEffectColor(const LLColor4 &color)
5090{
5091 mEffectColor = color;
5092}
5093
5094void LLAgent::initOriginGlobal(const LLVector3d &origin_global)
5095{
5096 mAgentOriginGlobal = origin_global;
5097}
5098
5099void update_group_floaters(const LLUUID& group_id)
5100{
5101 // *HACK: added to do a live update of the groups floater if it is
5102 // open.
5103 LLFloaterGroups* fg = LLFloaterGroups::getInstance(gAgent.getID());
5104 if(fg)
5105 {
5106 fg->reset();
5107 }
5108
5109 LLFloaterGroupInfo::refreshGroup(group_id);
5110
5111 // update avatar info
5112 LLFloaterAvatarInfo* fa = LLFloaterAvatarInfo::getInstance(gAgent.getID());
5113 if(fa)
5114 {
5115 fa->resetGroupList();
5116 }
5117
5118 if (gIMView)
5119 {
5120 // update the talk view
5121 gIMView->refresh();
5122 }
5123}
5124
5125// static
5126void LLAgent::processAgentDropGroup(LLMessageSystem *msg, void **)
5127{
5128 LLUUID agent_id;
5129 msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id );
5130
5131 if (agent_id != gAgentID)
5132 {
5133 llwarns << "processAgentDropGroup for agent other than me" << llendl;
5134 return;
5135 }
5136
5137 LLUUID group_id;
5138 msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_GroupID, group_id );
5139
5140 // Remove the group if it already exists remove it and add the new data to pick up changes.
5141 LLGroupData gd;
5142 gd.mID = group_id;
5143 S32 index = gAgent.mGroups.find(gd);
5144 if (index != -1)
5145 {
5146 gAgent.mGroups.remove(index);
5147 if (gAgent.getGroupID() == group_id)
5148 {
5149 gAgent.mGroupID.setNull();
5150 gAgent.mGroupPowers = 0;
5151 gAgent.mGroupName[0] = '\0';
5152 gAgent.mGroupTitle[0] = '\0';
5153 }
5154
5155 // refresh all group information
5156 gAgent.sendAgentDataUpdateRequest();
5157
5158 gGroupMgr->clearGroupData(group_id);
5159 // close the floater for this group, if any.
5160 LLFloaterGroupInfo::closeGroup(group_id);
5161 // refresh the group panel of the search window, if necessary.
5162 LLFloaterDirectory::refreshGroup(group_id);
5163 }
5164 else
5165 {
5166 llwarns << "processAgentDropGroup, agent is not part of group " << group_id << llendl;
5167 }
5168}
5169
5170// static
5171void LLAgent::processAgentGroupDataUpdate(LLMessageSystem *msg, void **)
5172{
5173 LLUUID agent_id;
5174
5175 msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id );
5176
5177 if (agent_id != gAgentID)
5178 {
5179 llwarns << "processAgentGroupDataUpdate for agent other than me" << llendl;
5180 return;
5181 }
5182
5183 S32 count = msg->getNumberOfBlocksFast(_PREHASH_GroupData);
5184 LLGroupData group;
5185 S32 index = -1;
5186 bool need_floater_update = false;
5187 char group_name[DB_GROUP_NAME_BUF_SIZE];
5188 for(S32 i = 0; i < count; ++i)
5189 {
5190 msg->getUUIDFast(_PREHASH_GroupData, _PREHASH_GroupID, group.mID, i);
5191 msg->getUUIDFast(_PREHASH_GroupData, _PREHASH_GroupInsigniaID, group.mInsigniaID, i);
5192 msg->getU64(_PREHASH_GroupData, "GroupPowers", group.mPowers, i);
5193 msg->getBOOL(_PREHASH_GroupData, "AcceptNotices", group.mAcceptNotices, i);
5194 msg->getS32(_PREHASH_GroupData, "Contribution", group.mContribution, i);
5195 msg->getStringFast(_PREHASH_GroupData, _PREHASH_GroupName, DB_GROUP_NAME_BUF_SIZE, group_name, i);
5196 group.mName.assign(group_name);
5197
5198 if(group.mID.notNull())
5199 {
5200 need_floater_update = true;
5201 // Remove the group if it already exists remove it and add the new data to pick up changes.
5202 index = gAgent.mGroups.find(group);
5203 if (index != -1)
5204 {
5205 gAgent.mGroups.remove(index);
5206 }
5207 gAgent.mGroups.put(group);
5208 }
5209 if (need_floater_update)
5210 {
5211 update_group_floaters(group.mID);
5212 }
5213 }
5214
5215}
5216
5217// static
5218void LLAgent::processAgentDataUpdate(LLMessageSystem *msg, void **)
5219{
5220 LLUUID agent_id;
5221
5222 msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id );
5223
5224 if (agent_id != gAgentID)
5225 {
5226 llwarns << "processAgentDataUpdate for agent other than me" << llendl;
5227 return;
5228 }
5229
5230 msg->getStringFast(_PREHASH_AgentData, _PREHASH_GroupTitle, DB_GROUP_TITLE_BUF_SIZE, gAgent.mGroupTitle);
5231 LLUUID active_id;
5232 msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_ActiveGroupID, active_id);
5233
5234
5235 if(active_id.notNull())
5236 {
5237 gAgent.mGroupID = active_id;
5238 msg->getU64(_PREHASH_AgentData, "GroupPowers", gAgent.mGroupPowers);
5239 msg->getString(_PREHASH_AgentData, _PREHASH_GroupName, DB_GROUP_NAME_BUF_SIZE, gAgent.mGroupName);
5240 }
5241 else
5242 {
5243 gAgent.mGroupID.setNull();
5244 gAgent.mGroupPowers = 0;
5245 gAgent.mGroupName[0] = '\0';
5246 }
5247
5248 update_group_floaters(active_id);
5249
5250 gAgent.fireEvent(new LLEvent(&gAgent, "new group"), "");
5251}
5252
5253// static
5254void LLAgent::processScriptControlChange(LLMessageSystem *msg, void **)
5255{
5256 S32 block_count = msg->getNumberOfBlocks("Data");
5257 for (S32 block_index = 0; block_index < block_count; block_index++)
5258 {
5259 BOOL take_controls;
5260 U32 controls;
5261 BOOL passon;
5262 U32 i;
5263 msg->getBOOL("Data", "TakeControls", take_controls, block_index);
5264 if (take_controls)
5265 {
5266 // take controls
5267 msg->getU32("Data", "Controls", controls, block_index );
5268 msg->getBOOL("Data", "PassToAgent", passon, block_index );
5269 U32 total_count = 0;
5270 for (i = 0; i < TOTAL_CONTROLS; i++)
5271 {
5272 if (controls & ( 1 << i))
5273 {
5274 if (passon)
5275 {
5276 gAgent.mControlsTakenPassedOnCount[i]++;
5277 }
5278 else
5279 {
5280 gAgent.mControlsTakenCount[i]++;
5281 }
5282 total_count++;
5283 }
5284 }
5285
5286 // Any control taken? If so, might be first time.
5287 if (total_count > 0)
5288 {
5289 LLFirstUse::useOverrideKeys();
5290 }
5291 }
5292 else
5293 {
5294 // release controls
5295 msg->getU32("Data", "Controls", controls, block_index );
5296 msg->getBOOL("Data", "PassToAgent", passon, block_index );
5297 for (i = 0; i < TOTAL_CONTROLS; i++)
5298 {
5299 if (controls & ( 1 << i))
5300 {
5301 if (passon)
5302 {
5303 gAgent.mControlsTakenPassedOnCount[i]--;
5304 if (gAgent.mControlsTakenPassedOnCount[i] < 0)
5305 {
5306 gAgent.mControlsTakenPassedOnCount[i] = 0;
5307 }
5308 }
5309 else
5310 {
5311 gAgent.mControlsTakenCount[i]--;
5312 if (gAgent.mControlsTakenCount[i] < 0)
5313 {
5314 gAgent.mControlsTakenCount[i] = 0;
5315 }
5316 }
5317 }
5318 }
5319 }
5320 }
5321}
5322
5323/*
5324// static
5325void LLAgent::processControlTake(LLMessageSystem *msg, void **)
5326{
5327 U32 controls;
5328 msg->getU32("Data", "Controls", controls );
5329 U32 passon;
5330 msg->getBOOL("Data", "PassToAgent", passon );
5331
5332 S32 i;
5333 S32 total_count = 0;
5334 for (i = 0; i < TOTAL_CONTROLS; i++)
5335 {
5336 if (controls & ( 1 << i))
5337 {
5338 if (passon)
5339 {
5340 gAgent.mControlsTakenPassedOnCount[i]++;
5341 }
5342 else
5343 {
5344 gAgent.mControlsTakenCount[i]++;
5345 }
5346 total_count++;
5347 }
5348 }
5349
5350 // Any control taken? If so, might be first time.
5351 if (total_count > 0)
5352 {
5353 LLFirstUse::useOverrideKeys();
5354 }
5355}
5356
5357// static
5358void LLAgent::processControlRelease(LLMessageSystem *msg, void **)
5359{
5360 U32 controls;
5361 msg->getU32("Data", "Controls", controls );
5362 U32 passon;
5363 msg->getBOOL("Data", "PassToAgent", passon );
5364
5365 S32 i;
5366 for (i = 0; i < TOTAL_CONTROLS; i++)
5367 {
5368 if (controls & ( 1 << i))
5369 {
5370 if (passon)
5371 {
5372 gAgent.mControlsTakenPassedOnCount[i]--;
5373 if (gAgent.mControlsTakenPassedOnCount[i] < 0)
5374 {
5375 gAgent.mControlsTakenPassedOnCount[i] = 0;
5376 }
5377 }
5378 else
5379 {
5380 gAgent.mControlsTakenCount[i]--;
5381 if (gAgent.mControlsTakenCount[i] < 0)
5382 {
5383 gAgent.mControlsTakenCount[i] = 0;
5384 }
5385 }
5386 }
5387 }
5388}
5389*/
5390
5391//static
5392void LLAgent::processAgentCachedTextureResponse(LLMessageSystem *mesgsys, void **user_data)
5393{
5394 gAgent.mNumPendingQueries--;
5395
5396 LLVOAvatar* avatarp = gAgent.getAvatarObject();
5397 if (!avatarp || avatarp->isDead())
5398 {
5399 llwarns << "No avatar for user in cached texture update!" << llendl;
5400 return;
5401 }
5402
5403 if (gAgent.cameraCustomizeAvatar())
5404 {
5405 // ignore baked textures when in customize mode
5406 return;
5407 }
5408
5409 S32 query_id;
5410 mesgsys->getS32Fast(_PREHASH_AgentData, _PREHASH_SerialNum, query_id);
5411
5412 S32 num_texture_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_WearableData);
5413
5414
5415 S32 num_results = 0;
5416 for (S32 texture_block = 0; texture_block < num_texture_blocks; texture_block++)
5417 {
5418 LLUUID texture_id;
5419 U8 texture_index;
5420
5421 mesgsys->getUUIDFast(_PREHASH_WearableData, _PREHASH_TextureID, texture_id, texture_block);
5422 mesgsys->getU8Fast(_PREHASH_WearableData, _PREHASH_TextureIndex, texture_index, texture_block);
5423
5424 if (texture_id.notNull()
5425 && (S32)texture_index < BAKED_TEXTURE_COUNT
5426 && gAgent.mActiveCacheQueries[ texture_index ] == query_id)
5427 {
5428 //llinfos << "Received cached texture " << (U32)texture_index << ": " << texture_id << llendl;
5429 avatarp->setCachedBakedTexture((LLVOAvatar::ETextureIndex)LLVOAvatar::sBakedTextureIndices[texture_index], texture_id);
5430 //avatarp->setTETexture( LLVOAvatar::sBakedTextureIndices[texture_index], texture_id );
5431 gAgent.mActiveCacheQueries[ texture_index ] = 0;
5432 num_results++;
5433 }
5434 }
5435
5436 llinfos << "Received cached texture response for " << num_results << " textures." << llendl;
5437
5438 avatarp->updateMeshTextures();
5439
5440 if (gAgent.mNumPendingQueries == 0)
5441 {
5442 // RN: not sure why composites are disabled at this point
5443 avatarp->setCompositeUpdatesEnabled(TRUE);
5444 gAgent.sendAgentSetAppearance();
5445 }
5446}
5447
5448BOOL LLAgent::anyControlGrabbed() const
5449{
5450 U32 i;
5451 for (i = 0; i < TOTAL_CONTROLS; i++)
5452 {
5453 if (gAgent.mControlsTakenCount[i] > 0)
5454 return TRUE;
5455 if (gAgent.mControlsTakenPassedOnCount[i] > 0)
5456 return TRUE;
5457 }
5458 return FALSE;
5459}
5460
5461BOOL LLAgent::isControlGrabbed(S32 control_index) const
5462{
5463 return mControlsTakenCount[control_index] > 0;
5464}
5465
5466void LLAgent::forceReleaseControls()
5467{
5468 gMessageSystem->newMessage("ForceScriptControlRelease");
5469 gMessageSystem->nextBlock("AgentData");
5470 gMessageSystem->addUUID("AgentID", getID());
5471 gMessageSystem->addUUID("SessionID", getSessionID());
5472 sendReliableMessage();
5473}
5474
5475void LLAgent::setHomePosRegion( const U64& region_handle, const LLVector3& pos_region)
5476{
5477 mHaveHomePosition = TRUE;
5478 mHomeRegionHandle = region_handle;
5479 mHomePosRegion = pos_region;
5480}
5481
5482BOOL LLAgent::getHomePosGlobal( LLVector3d* pos_global )
5483{
5484 if(!mHaveHomePosition)
5485 {
5486 return FALSE;
5487 }
5488 F32 x = 0;
5489 F32 y = 0;
5490 from_region_handle( mHomeRegionHandle, &x, &y);
5491 pos_global->setVec( x + mHomePosRegion.mV[VX], y + mHomePosRegion.mV[VY], mHomePosRegion.mV[VZ] );
5492 return TRUE;
5493}
5494
5495void LLAgent::clearVisualParams(void *data)
5496{
5497 LLVOAvatar* avatarp = gAgent.getAvatarObject();
5498 if (avatarp)
5499 {
5500 avatarp->clearVisualParamWeights();
5501 avatarp->updateVisualParams();
5502 }
5503}
5504
5505//---------------------------------------------------------------------------
5506// Teleport
5507//---------------------------------------------------------------------------
5508
5509// teleportCore() - stuff to do on any teleport
5510// protected
5511bool LLAgent::teleportCore(bool is_local)
5512{
5513 if(TELEPORT_NONE != mTeleportState)
5514 {
5515 llwarns << "Attempt to teleport when already teleporting." << llendl;
5516 return false;
5517 }
5518
5519 // Don't call LLFirstUse::useTeleport because we don't know
5520 // yet if the teleport will succeed. Look in
5521 // process_teleport_location_reply
5522
5523 // close the map and find panels so we can see our destination
5524 LLFloaterWorldMap::hide(NULL);
5525 LLFloaterDirectory::hide(NULL);
5526
5527 // Close all pie menus, deselect land, etc.
5528 // Don't change the camera until we know teleport succeeded. JC
5529 resetView(FALSE);
5530
5531 // local logic
5532 gViewerStats->incStat(LLViewerStats::ST_TELEPORT_COUNT);
5533 if (!is_local)
5534 {
5535 gTeleportDisplay = TRUE;
5536 gAgent.setTeleportState( LLAgent::TELEPORT_START );
5537 }
5538 make_ui_sound("UISndTeleportOut");
5539 return true;
5540}
5541
5542void LLAgent::teleportRequest(
5543 const U64& region_handle,
5544 const LLVector3& pos_local)
5545{
5546 LLViewerRegion* regionp = getRegion();
5547 if(regionp && teleportCore())
5548 {
5549 llinfos << "TeleportRequest: '" << region_handle << "':" << pos_local
5550 << llendl;
5551 LLMessageSystem* msg = gMessageSystem;
5552 msg->newMessage("TeleportLocationRequest");
5553 msg->nextBlockFast(_PREHASH_AgentData);
5554 msg->addUUIDFast(_PREHASH_AgentID, getID());
5555 msg->addUUIDFast(_PREHASH_SessionID, getSessionID());
5556 msg->nextBlockFast(_PREHASH_Info);
5557 msg->addU64("RegionHandle", region_handle);
5558 msg->addVector3("Position", pos_local);
5559 LLVector3 look_at(0,1,0);
5560 msg->addVector3("LookAt", look_at);
5561 sendReliableMessage();
5562 }
5563}
5564
5565// Landmark ID = LLUUID::null means teleport home
5566void LLAgent::teleportViaLandmark(const LLUUID& landmark_id)
5567{
5568 LLViewerRegion *regionp = getRegion();
5569 if(regionp && teleportCore())
5570 {
5571 LLMessageSystem* msg = gMessageSystem;
5572 msg->newMessageFast(_PREHASH_TeleportLandmarkRequest);
5573 msg->nextBlockFast(_PREHASH_Info);
5574 msg->addUUIDFast(_PREHASH_AgentID, getID());
5575 msg->addUUIDFast(_PREHASH_SessionID, getSessionID());
5576 msg->addUUIDFast(_PREHASH_LandmarkID, landmark_id);
5577 sendReliableMessage();
5578 }
5579}
5580
5581void LLAgent::teleportViaLure(const LLUUID& lure_id, BOOL godlike)
5582{
5583 LLViewerRegion* regionp = getRegion();
5584 if(regionp && teleportCore())
5585 {
5586 U32 teleport_flags = 0x0;
5587 if (godlike)
5588 {
5589 teleport_flags |= TELEPORT_FLAGS_VIA_GODLIKE_LURE;
5590 teleport_flags |= TELEPORT_FLAGS_DISABLE_CANCEL;
5591 }
5592 else
5593 {
5594 teleport_flags |= TELEPORT_FLAGS_VIA_LURE;
5595 }
5596
5597 // send the message
5598 LLMessageSystem* msg = gMessageSystem;
5599 msg->newMessageFast(_PREHASH_TeleportLureRequest);
5600 msg->nextBlockFast(_PREHASH_Info);
5601 msg->addUUIDFast(_PREHASH_AgentID, getID());
5602 msg->addUUIDFast(_PREHASH_SessionID, getSessionID());
5603 msg->addUUIDFast(_PREHASH_LureID, lure_id);
5604 msg->addU32("TeleportFlags", teleport_flags);
5605 sendReliableMessage();
5606 }
5607}
5608
5609
5610// James Cook, July 28, 2005
5611void LLAgent::teleportCancel()
5612{
5613 LLViewerRegion* regionp = getRegion();
5614 if(regionp)
5615 {
5616 // send the message
5617 LLMessageSystem* msg = gMessageSystem;
5618 msg->newMessage("TeleportCancel");
5619 msg->nextBlockFast(_PREHASH_Info);
5620 msg->addUUIDFast(_PREHASH_AgentID, getID());
5621 msg->addUUIDFast(_PREHASH_SessionID, getSessionID());
5622 sendReliableMessage();
5623 }
5624 gTeleportDisplay = FALSE;
5625 gAgent.setTeleportState( LLAgent::TELEPORT_CANCELLING );
5626}
5627
5628
5629void LLAgent::teleportViaLocation(const LLVector3d& pos_global)
5630{
5631 LLViewerRegion* regionp = getRegion();
5632 LLSimInfo* info = gWorldMap->simInfoFromPosGlobal(pos_global);
5633 if(regionp && info)
5634 {
5635 U32 x_pos;
5636 U32 y_pos;
5637 from_region_handle(info->mHandle, &x_pos, &y_pos);
5638 LLVector3 pos_local(
5639 (F32)(pos_global.mdV[VX] - x_pos),
5640 (F32)(pos_global.mdV[VY] - y_pos),
5641 (F32)(pos_global.mdV[VZ]));
5642 teleportRequest(info->mHandle, pos_local);
5643 }
5644 else if(regionp &&
5645 teleportCore(regionp->getHandle() == to_region_handle_global((F32)pos_global.mdV[VX], (F32)pos_global.mdV[VY])))
5646 {
5647 llwarns << "Using deprecated teleportlocationrequest." << llendl;
5648 // send the message
5649 LLMessageSystem* msg = gMessageSystem;
5650 msg->newMessageFast(_PREHASH_TeleportLocationRequest);
5651 msg->nextBlockFast(_PREHASH_AgentData);
5652 msg->addUUIDFast(_PREHASH_AgentID, getID());
5653 msg->addUUIDFast(_PREHASH_SessionID, getSessionID());
5654
5655 msg->nextBlockFast(_PREHASH_Info);
5656 F32 width = regionp->getWidth();
5657 LLVector3 pos(fmod((F32)pos_global.mdV[VX], width),
5658 fmod((F32)pos_global.mdV[VY], width),
5659 (F32)pos_global.mdV[VZ]);
5660 F32 region_x = (F32)(pos_global.mdV[VX]);
5661 F32 region_y = (F32)(pos_global.mdV[VY]);
5662 U64 region_handle = to_region_handle_global(region_x, region_y);
5663 msg->addU64Fast(_PREHASH_RegionHandle, region_handle);
5664 msg->addVector3Fast(_PREHASH_Position, pos);
5665 pos.mV[VX] += 1;
5666 msg->addVector3Fast(_PREHASH_LookAt, pos);
5667 sendReliableMessage();
5668 }
5669}
5670
5671void LLAgent::setTeleportState(ETeleportState state)
5672{
5673 mTeleportState = state;
5674 if (mTeleportState > TELEPORT_NONE && gSavedSettings.getBOOL("FreezeTime"))
5675 {
5676 LLFloaterSnapshot::hide(0);
5677 }
5678}
5679
5680void LLAgent::fidget()
5681{
5682 if (!getAFK())
5683 {
5684 F32 curTime = mFidgetTimer.getElapsedTimeF32();
5685 if (curTime > mNextFidgetTime)
5686 {
5687 // pick a random fidget anim here
5688 S32 oldFidget = mCurrentFidget;
5689
5690 mCurrentFidget = gLindenLabRandomNumber.llrand(NUM_AGENT_STAND_ANIMS);
5691
5692 if (mCurrentFidget != oldFidget)
5693 {
5694 LLAgent::stopFidget();
5695
5696
5697 switch(mCurrentFidget)
5698 {
5699 case 0:
5700 mCurrentFidget = 0;
5701 break;
5702 case 1:
5703 sendAnimationRequest(ANIM_AGENT_STAND_1, ANIM_REQUEST_START);
5704 mCurrentFidget = 1;
5705 break;
5706 case 2:
5707 sendAnimationRequest(ANIM_AGENT_STAND_2, ANIM_REQUEST_START);
5708 mCurrentFidget = 2;
5709 break;
5710 case 3:
5711 sendAnimationRequest(ANIM_AGENT_STAND_3, ANIM_REQUEST_START);
5712 mCurrentFidget = 3;
5713 break;
5714 case 4:
5715 sendAnimationRequest(ANIM_AGENT_STAND_4, ANIM_REQUEST_START);
5716 mCurrentFidget = 4;
5717 break;
5718 }
5719 }
5720
5721 // calculate next fidget time
5722 mNextFidgetTime = curTime + gLindenLabRandomNumber.llfrand(MAX_FIDGET_TIME - MIN_FIDGET_TIME) + MIN_FIDGET_TIME;
5723 }
5724 }
5725}
5726
5727void LLAgent::stopFidget()
5728{
5729 LLDynamicArray<LLUUID> anims;
5730 anims.put(ANIM_AGENT_STAND_1);
5731 anims.put(ANIM_AGENT_STAND_2);
5732 anims.put(ANIM_AGENT_STAND_3);
5733 anims.put(ANIM_AGENT_STAND_4);
5734
5735 gAgent.sendAnimationRequests(anims, ANIM_REQUEST_STOP);
5736}
5737
5738
5739void LLAgent::requestEnterGodMode()
5740{
5741 LLMessageSystem* msg = gMessageSystem;
5742 msg->newMessageFast(_PREHASH_RequestGodlikePowers);
5743 msg->nextBlockFast(_PREHASH_AgentData);
5744 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
5745 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
5746 msg->nextBlockFast(_PREHASH_RequestBlock);
5747 msg->addBOOLFast(_PREHASH_Godlike, TRUE);
5748 msg->addUUIDFast(_PREHASH_Token, LLUUID::null);
5749
5750 // simulator and userserver need to know about your request
5751 sendReliableMessage();
5752 msg->sendReliable(gUserServer);
5753}
5754
5755void LLAgent::requestLeaveGodMode()
5756{
5757 LLMessageSystem* msg = gMessageSystem;
5758 msg->newMessageFast(_PREHASH_RequestGodlikePowers);
5759 msg->nextBlockFast(_PREHASH_AgentData);
5760 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
5761 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
5762 msg->nextBlockFast(_PREHASH_RequestBlock);
5763 msg->addBOOLFast(_PREHASH_Godlike, FALSE);
5764 msg->addUUIDFast(_PREHASH_Token, LLUUID::null);
5765
5766 // simulator and userserver need to know about your request
5767 sendReliableMessage();
5768 msg->sendReliable(gUserServer);
5769}
5770
5771// wearables
5772LLAgent::createStandardWearablesAllDoneCallback::~createStandardWearablesAllDoneCallback()
5773{
5774 gAgent.createStandardWearablesAllDone();
5775}
5776
5777LLAgent::sendAgentWearablesUpdateCallback::~sendAgentWearablesUpdateCallback()
5778{
5779 gAgent.sendAgentWearablesUpdate();
5780}
5781
5782LLAgent::addWearableToAgentInventoryCallback::addWearableToAgentInventoryCallback(
5783 LLPointer<LLRefCount> cb, S32 index, LLWearable* wearable, U32 todo) :
5784 mIndex(index),
5785 mWearable(wearable),
5786 mTodo(todo),
5787 mCB(cb)
5788{
5789}
5790
5791void LLAgent::addWearableToAgentInventoryCallback::fire(const LLUUID& inv_item)
5792{
5793 if (inv_item.isNull())
5794 return;
5795
5796 gAgent.addWearabletoAgentInventoryDone(mIndex, inv_item, mWearable);
5797
5798 if (mTodo & CALL_UPDATE)
5799 {
5800 gAgent.sendAgentWearablesUpdate();
5801 }
5802 if (mTodo & CALL_RECOVERDONE)
5803 {
5804 gAgent.recoverMissingWearableDone();
5805 }
5806 /*
5807 * Do this for every one in the loop
5808 */
5809 if (mTodo & CALL_CREATESTANDARDDONE)
5810 {
5811 gAgent.createStandardWearablesDone(mIndex);
5812 }
5813 if (mTodo & CALL_MAKENEWOUTFITDONE)
5814 {
5815 gAgent.makeNewOutfitDone(mIndex);
5816 }
5817}
5818
5819void LLAgent::addWearabletoAgentInventoryDone(
5820 S32 index,
5821 const LLUUID& item_id,
5822 LLWearable* wearable)
5823{
5824 if (item_id.isNull())
5825 return;
5826
5827 LLUUID old_item_id = mWearableEntry[index].mItemID;
5828 mWearableEntry[index].mItemID = item_id;
5829 mWearableEntry[index].mWearable = wearable;
5830 if (old_item_id.notNull())
5831 gInventory.addChangedMask(LLInventoryObserver::LABEL, old_item_id);
5832 gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id);
5833 LLViewerInventoryItem* item = gInventory.getItem(item_id);
5834 if(item && wearable)
5835 {
5836 // We're changing the asset id, so we both need to set it
5837 // locally via setAssetUUID() and via setTransactionID() which
5838 // will be decoded on the server. JC
5839 item->setAssetUUID(wearable->getID());
5840 item->setTransactionID(wearable->getTransactionID());
5841 gInventory.addChangedMask(LLInventoryObserver::INTERNAL, item_id);
5842 item->updateServer(FALSE);
5843 }
5844 gInventory.notifyObservers();
5845}
5846
5847void LLAgent::sendAgentWearablesUpdate()
5848{
5849 // First make sure that we have inventory items for each wearable
5850 S32 i;
5851 for(i=0; i < WT_COUNT; ++i)
5852 {
5853 LLWearable* wearable = mWearableEntry[ i ].mWearable;
5854 if (wearable)
5855 {
5856 if( mWearableEntry[ i ].mItemID.isNull() )
5857 {
5858 LLPointer<LLInventoryCallback> cb =
5859 new addWearableToAgentInventoryCallback(
5860 LLPointer<LLRefCount>(NULL),
5861 i,
5862 wearable,
5863 addWearableToAgentInventoryCallback::CALL_NONE);
5864 addWearableToAgentInventory(cb, wearable);
5865 }
5866 else
5867 {
5868 gInventory.addChangedMask( LLInventoryObserver::LABEL,
5869 mWearableEntry[i].mItemID );
5870 }
5871 }
5872 }
5873
5874 // Then make sure the inventory is in sync with the avatar.
5875 gInventory.notifyObservers();
5876
5877 // Send the AgentIsNowWearing
5878 gMessageSystem->newMessageFast(_PREHASH_AgentIsNowWearing);
5879
5880 gMessageSystem->nextBlockFast(_PREHASH_AgentData);
5881 gMessageSystem->addUUIDFast(_PREHASH_AgentID, getID());
5882 gMessageSystem->addUUIDFast(_PREHASH_SessionID, getSessionID());
5883
5884 lldebugs << "sendAgentWearablesUpdate()" << llendl;
5885 for(i=0; i < WT_COUNT; ++i)
5886 {
5887 gMessageSystem->nextBlockFast(_PREHASH_WearableData);
5888
5889 U8 type_u8 = (U8)i;
5890 gMessageSystem->addU8Fast(_PREHASH_WearableType, type_u8 );
5891
5892 LLWearable* wearable = mWearableEntry[ i ].mWearable;
5893 if( wearable )
5894 {
5895 //llinfos << "Sending wearable " << wearable->getName() << llendl;
5896 gMessageSystem->addUUIDFast(_PREHASH_ItemID, mWearableEntry[ i ].mItemID );
5897 }
5898 else
5899 {
5900 //llinfos << "Not wearing wearable type " << LLWearable::typeToTypeName((EWearableType)i) << llendl;
5901 gMessageSystem->addUUIDFast(_PREHASH_ItemID, LLUUID::null );
5902 }
5903
5904 lldebugs << " " << LLWearable::typeToTypeLabel((EWearableType)i) << ": " << (wearable ? wearable->getID() : LLUUID::null) << llendl;
5905 }
5906 gAgent.sendReliableMessage();
5907}
5908
5909void LLAgent::saveWearable( EWearableType type, BOOL send_update )
5910{
5911 LLWearable* old_wearable = mWearableEntry[(S32)type].mWearable;
5912 if( old_wearable && (old_wearable->isDirty() || old_wearable->isOldVersion()) )
5913 {
5914 LLWearable* new_wearable = gWearableList.createCopyFromAvatar( old_wearable );
5915 mWearableEntry[(S32)type].mWearable = new_wearable;
5916
5917 LLInventoryItem* item = gInventory.getItem(mWearableEntry[(S32)type].mItemID);
5918 if( item )
5919 {
5920 // Update existing inventory item
5921 LLPointer<LLViewerInventoryItem> template_item =
5922 new LLViewerInventoryItem(item->getUUID(),
5923 item->getParentUUID(),
5924 item->getPermissions(),
5925 new_wearable->getID(),
5926 new_wearable->getAssetType(),
5927 item->getInventoryType(),
5928 item->getName(),
5929 item->getDescription(),
5930 item->getSaleInfo(),
5931 item->getFlags(),
5932 item->getCreationDate());
5933 template_item->setTransactionID(new_wearable->getTransactionID());
5934 template_item->updateServer(FALSE);
5935 gInventory.updateItem(template_item);
5936 }
5937 else
5938 {
5939 // Add a new inventory item (shouldn't ever happen here)
5940 U32 todo = addWearableToAgentInventoryCallback::CALL_NONE;
5941 if (send_update)
5942 {
5943 todo |= addWearableToAgentInventoryCallback::CALL_UPDATE;
5944 }
5945 LLPointer<LLInventoryCallback> cb =
5946 new addWearableToAgentInventoryCallback(
5947 LLPointer<LLRefCount>(NULL),
5948 (S32)type,
5949 new_wearable,
5950 todo);
5951 addWearableToAgentInventory(cb, new_wearable);
5952 return;
5953 }
5954
5955 if( send_update )
5956 {
5957 sendAgentWearablesUpdate();
5958 }
5959 }
5960}
5961
5962void LLAgent::saveWearableAs(
5963 EWearableType type,
5964 const std::string& new_name,
5965 BOOL save_in_lost_and_found)
5966{
5967 if(!isWearableCopyable(type))
5968 {
5969 llwarns << "LLAgent::saveWearableAs() not copyable." << llendl;
5970 return;
5971 }
5972 LLWearable* old_wearable = getWearable(type);
5973 if(!old_wearable)
5974 {
5975 llwarns << "LLAgent::saveWearableAs() no old wearable." << llendl;
5976 return;
5977 }
5978 LLInventoryItem* item = gInventory.getItem(mWearableEntry[type].mItemID);
5979 if(!item)
5980 {
5981 llwarns << "LLAgent::saveWearableAs() no inventory item." << llendl;
5982 return;
5983 }
5984 std::string trunc_name(new_name);
5985 LLString::truncate(trunc_name, DB_INV_ITEM_NAME_STR_LEN);
5986 LLWearable* new_wearable = gWearableList.createCopyFromAvatar(
5987 old_wearable,
5988 trunc_name);
5989 LLPointer<LLInventoryCallback> cb =
5990 new addWearableToAgentInventoryCallback(
5991 LLPointer<LLRefCount>(NULL),
5992 type,
5993 new_wearable,
5994 addWearableToAgentInventoryCallback::CALL_UPDATE);
5995 LLUUID category_id;
5996 if (save_in_lost_and_found)
5997 {
5998 category_id = gInventory.findCategoryUUIDForType(
5999 LLAssetType::AT_LOST_AND_FOUND);
6000 }
6001 else
6002 {
6003 // put in same folder as original
6004 category_id = item->getParentUUID();
6005 }
6006
6007 copy_inventory_item(
6008 gAgent.getID(),
6009 item->getPermissions().getOwner(),
6010 item->getUUID(),
6011 category_id,
6012 new_name,
6013 cb);
6014
6015/*
6016 LLWearable* old_wearable = getWearable( type );
6017 if( old_wearable )
6018 {
6019 LLString old_name = old_wearable->getName();
6020 old_wearable->setName( new_name );
6021 LLWearable* new_wearable = gWearableList.createCopyFromAvatar( old_wearable );
6022 old_wearable->setName( old_name );
6023
6024 LLUUID category_id;
6025 LLInventoryItem* item = gInventory.getItem( mWearableEntry[ type ].mItemID );
6026 if( item )
6027 {
6028 new_wearable->setPermissions(item->getPermissions());
6029 if (save_in_lost_and_found)
6030 {
6031 category_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_LOST_AND_FOUND);
6032 }
6033 else
6034 {
6035 // put in same folder as original
6036 category_id = item->getParentUUID();
6037 }
6038 LLInventoryView* view = LLInventoryView::getActiveInventory();
6039 if(view)
6040 {
6041 view->getPanel()->setSelection(item->getUUID(), TAKE_FOCUS_NO);
6042 }
6043 }
6044
6045 mWearableEntry[ type ].mWearable = new_wearable;
6046 LLPointer<LLInventoryCallback> cb =
6047 new addWearableToAgentInventoryCallback(
6048 LLPointer<LLRefCount>(NULL),
6049 type,
6050 addWearableToAgentInventoryCallback::CALL_UPDATE);
6051 addWearableToAgentInventory(cb, new_wearable, category_id);
6052 }
6053*/
6054}
6055
6056void LLAgent::revertWearable( EWearableType type )
6057{
6058 LLWearable* wearable = mWearableEntry[(S32)type].mWearable;
6059 if( wearable )
6060 {
6061 wearable->writeToAvatar( TRUE );
6062 }
6063 sendAgentSetAppearance();
6064}
6065
6066void LLAgent::revertAllWearables()
6067{
6068 for( S32 i=0; i < WT_COUNT; i++ )
6069 {
6070 revertWearable( (EWearableType)i );
6071 }
6072}
6073
6074void LLAgent::saveAllWearables()
6075{
6076 //if(!gInventory.isLoaded())
6077 //{
6078 // return;
6079 //}
6080
6081 for( S32 i=0; i < WT_COUNT; i++ )
6082 {
6083 saveWearable( (EWearableType)i, FALSE );
6084 }
6085 sendAgentWearablesUpdate();
6086}
6087
6088// Called when the user changes the name of a wearable inventory item that is currenlty being worn.
6089void LLAgent::setWearableName( const LLUUID& item_id, const std::string& new_name )
6090{
6091 for( S32 i=0; i < WT_COUNT; i++ )
6092 {
6093 if( mWearableEntry[i].mItemID == item_id )
6094 {
6095 LLWearable* old_wearable = mWearableEntry[i].mWearable;
6096 llassert( old_wearable );
6097
6098 LLString old_name = old_wearable->getName();
6099 old_wearable->setName( new_name );
6100 LLWearable* new_wearable = gWearableList.createCopy( old_wearable );
6101 LLInventoryItem* item = gInventory.getItem(item_id);
6102 if(item)
6103 {
6104 new_wearable->setPermissions(item->getPermissions());
6105 }
6106 old_wearable->setName( old_name );
6107
6108 mWearableEntry[i].mWearable = new_wearable;
6109 sendAgentWearablesUpdate();
6110 break;
6111 }
6112 }
6113}
6114
6115
6116BOOL LLAgent::isWearableModifiable(EWearableType type)
6117{
6118 LLUUID item_id = getWearableItem(type);
6119 if(!item_id.isNull())
6120 {
6121 LLInventoryItem* item = gInventory.getItem(item_id);
6122 if(item && item->getPermissions().allowModifyBy(gAgent.getID(),
6123 gAgent.getGroupID()))
6124 {
6125 return TRUE;
6126 }
6127 }
6128 return FALSE;
6129}
6130
6131BOOL LLAgent::isWearableCopyable(EWearableType type)
6132{
6133 LLUUID item_id = getWearableItem(type);
6134 if(!item_id.isNull())
6135 {
6136 LLInventoryItem* item = gInventory.getItem(item_id);
6137 if(item && item->getPermissions().allowCopyBy(gAgent.getID(),
6138 gAgent.getGroupID()))
6139 {
6140 return TRUE;
6141 }
6142 }
6143 return FALSE;
6144}
6145
6146U32 LLAgent::getWearablePermMask(EWearableType type)
6147{
6148 LLUUID item_id = getWearableItem(type);
6149 if(!item_id.isNull())
6150 {
6151 LLInventoryItem* item = gInventory.getItem(item_id);
6152 if(item)
6153 {
6154 return item->getPermissions().getMaskOwner();
6155 }
6156 }
6157 return PERM_NONE;
6158}
6159
6160LLInventoryItem* LLAgent::getWearableInventoryItem(EWearableType type)
6161{
6162 LLUUID item_id = getWearableItem(type);
6163 LLInventoryItem* item = NULL;
6164 if(item_id.notNull())
6165 {
6166 item = gInventory.getItem(item_id);
6167 }
6168 return item;
6169}
6170
6171LLWearable* LLAgent::getWearableFromWearableItem( const LLUUID& item_id )
6172{
6173 for( S32 i=0; i < WT_COUNT; i++ )
6174 {
6175 if( mWearableEntry[i].mItemID == item_id )
6176 {
6177 return mWearableEntry[i].mWearable;
6178 }
6179 }
6180 return NULL;
6181}
6182
6183
6184void LLAgent::sendAgentWearablesRequest()
6185{
6186 gMessageSystem->newMessageFast(_PREHASH_AgentWearablesRequest);
6187 gMessageSystem->nextBlockFast(_PREHASH_AgentData);
6188 gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
6189 gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID() );
6190 sendReliableMessage();
6191}
6192
6193// Used to enable/disable menu items.
6194// static
6195BOOL LLAgent::selfHasWearable( void* userdata )
6196{
6197 EWearableType type = (EWearableType)(intptr_t)userdata;
6198 return gAgent.getWearable( type ) != NULL;
6199}
6200
6201BOOL LLAgent::isWearingItem( const LLUUID& item_id )
6202{
6203 return (getWearableFromWearableItem( item_id ) != NULL);
6204}
6205
6206
6207// static
6208void LLAgent::processAgentInitialWearablesUpdate( LLMessageSystem* mesgsys, void** user_data )
6209{
6210 // We should only receive this message a single time. Ignore subsequent AgentWearablesUpdates
6211 // that may result from AgentWearablesRequest having been sent more than once.
6212 static BOOL first = TRUE;
6213 if( first )
6214 {
6215 first = FALSE;
6216 }
6217 else
6218 {
6219 return;
6220 }
6221
6222 if (gNoRender)
6223 {
6224 return;
6225 }
6226
6227 LLUUID agent_id;
6228 gMessageSystem->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id );
6229
6230 LLVOAvatar* avatar = gAgent.getAvatarObject();
6231 if( avatar && (agent_id == avatar->getID()) )
6232 {
6233 gMessageSystem->getU32Fast(_PREHASH_AgentData, _PREHASH_SerialNum, gAgent.mAgentWearablesUpdateSerialNum );
6234
6235 S32 num_wearables = gMessageSystem->getNumberOfBlocksFast(_PREHASH_WearableData);
6236 if( num_wearables < 4 )
6237 {
6238 // Transitional state. Avatars should always have at least their body parts (hair, eyes, shape and skin).
6239 // The fact that they don't have any here (only a dummy is sent) implies that this account existed
6240 // before we had wearables, or that the database has gotten messed up.
6241 // Deal with this by creating new body parts.
6242 //avatar->createStandardWearables();
6243
6244 // no, deal with it by noting that we need to choose a
6245 // gender.
6246 gAgent.setGenderChosen(FALSE);
6247 return;
6248 }
6249
6250 //lldebugs << "processAgentInitialWearablesUpdate()" << llendl;
6251 // Add wearables
6252 LLUUID asset_id_array[ WT_COUNT ];
6253 S32 i;
6254 for( i=0; i < num_wearables; i++ )
6255 {
6256 U8 type_u8 = 0;
6257 gMessageSystem->getU8Fast(_PREHASH_WearableData, _PREHASH_WearableType, type_u8, i );
6258 if( type_u8 >= WT_COUNT )
6259 {
6260 continue;
6261 }
6262 EWearableType type = (EWearableType) type_u8;
6263
6264 LLUUID item_id;
6265 gMessageSystem->getUUIDFast(_PREHASH_WearableData, _PREHASH_ItemID, item_id, i );
6266
6267 LLUUID asset_id;
6268 gMessageSystem->getUUIDFast(_PREHASH_WearableData, _PREHASH_AssetID, asset_id, i );
6269 if( asset_id.isNull() )
6270 {
6271 LLWearable::removeFromAvatar( type, FALSE );
6272 }
6273 else
6274 {
6275 LLAssetType::EType asset_type = LLWearable::typeToAssetType( type );
6276 if( asset_type == LLAssetType::AT_NONE )
6277 {
6278 continue;
6279 }
6280
6281 gAgent.mWearableEntry[type].mItemID = item_id;
6282 asset_id_array[type] = asset_id;
6283 }
6284
6285 lldebugs << " " << LLWearable::typeToTypeLabel(type) << llendl;
6286 }
6287
6288 // now that we have the asset ids...request the wearable assets
6289 for( i = 0; i < WT_COUNT; i++ )
6290 {
6291 if( !gAgent.mWearableEntry[i].mItemID.isNull() )
6292 {
6293 gWearableList.getAsset(
6294 asset_id_array[i],
6295 LLString::null,
6296 LLWearable::typeToAssetType( (EWearableType) i ),
6297 LLAgent::onInitialWearableAssetArrived, (void*)(intptr_t)i );
6298 }
6299 }
6300 }
6301}
6302
6303// A single wearable that the avatar was wearing on start-up has arrived from the database.
6304// static
6305void LLAgent::onInitialWearableAssetArrived( LLWearable* wearable, void* userdata )
6306{
6307 EWearableType type = (EWearableType)(intptr_t)userdata;
6308
6309 LLVOAvatar* avatar = gAgent.getAvatarObject();
6310 if( !avatar )
6311 {
6312 return;
6313 }
6314
6315 if( wearable )
6316 {
6317 llassert( type == wearable->getType() );
6318 gAgent.mWearableEntry[ type ].mWearable = wearable;
6319
6320 // disable composites if initial textures are baked
6321 avatar->setupComposites();
6322 gAgent.queryWearableCache();
6323
6324 wearable->writeToAvatar( FALSE );
6325 avatar->setCompositeUpdatesEnabled(TRUE);
6326 gInventory.addChangedMask( LLInventoryObserver::LABEL, gAgent.mWearableEntry[type].mItemID );
6327 }
6328 else
6329 {
6330 // Somehow the asset doesn't exist in the database.
6331 gAgent.recoverMissingWearable( type );
6332 }
6333
6334 gInventory.notifyObservers();
6335
6336 // Have all the wearables that the avatar was wearing at log-in arrived?
6337 if( !gAgent.mWearablesLoaded )
6338 {
6339 gAgent.mWearablesLoaded = TRUE;
6340 for( S32 i = 0; i < WT_COUNT; i++ )
6341 {
6342 if( !gAgent.mWearableEntry[i].mItemID.isNull() && !gAgent.mWearableEntry[i].mWearable )
6343 {
6344 gAgent.mWearablesLoaded = FALSE;
6345 break;
6346 }
6347 }
6348 }
6349
6350 if( gAgent.mWearablesLoaded )
6351 {
6352 // Make sure that the server's idea of the avatar's wearables actually match the wearables.
6353 gAgent.sendAgentSetAppearance();
6354
6355 // Check to see if there are any baked textures that we hadn't uploaded before we logged off last time.
6356 // If there are any, schedule them to be uploaded as soon as the layer textures they depend on arrive.
6357 if( !gAgent.cameraCustomizeAvatar() )
6358 {
6359 avatar->requestLayerSetUploads();
6360 }
6361 }
6362}
6363
6364// Normally, all wearables referred to "AgentWearablesUpdate" will correspond to actual assets in the
6365// database. If for some reason, we can't load one of those assets, we can try to reconstruct it so that
6366// the user isn't left without a shape, for example. (We can do that only after the inventory has loaded.)
6367void LLAgent::recoverMissingWearable( EWearableType type )
6368{
6369 // Try to recover by replacing missing wearable with a new one.
6370 LLNotifyBox::showXml("ReplacedMissingWearable");
6371 lldebugs << "Wearable " << LLWearable::typeToTypeLabel( type ) << " could not be downloaded. Replaced inventory item with default wearable." << llendl;
6372 LLWearable* new_wearable = gWearableList.createNewWearable(type);
6373
6374 S32 type_s32 = (S32) type;
6375 mWearableEntry[type_s32].mWearable = new_wearable;
6376 new_wearable->writeToAvatar( TRUE );
6377
6378 // Add a new one in the lost and found folder.
6379 // (We used to overwrite the "not found" one, but that could potentially
6380 // destory content.) JC
6381 LLUUID lost_and_found_id =
6382 gInventory.findCategoryUUIDForType(LLAssetType::AT_LOST_AND_FOUND);
6383 LLPointer<LLInventoryCallback> cb =
6384 new addWearableToAgentInventoryCallback(
6385 LLPointer<LLRefCount>(NULL),
6386 type_s32,
6387 new_wearable,
6388 addWearableToAgentInventoryCallback::CALL_RECOVERDONE);
6389 addWearableToAgentInventory( cb, new_wearable, lost_and_found_id, TRUE);
6390}
6391
6392void LLAgent::recoverMissingWearableDone()
6393{
6394 // Have all the wearables that the avatar was wearing at log-in arrived or been fabricated?
6395 mWearablesLoaded = TRUE;
6396 for( S32 i = 0; i < WT_COUNT; i++ )
6397 {
6398 if( !mWearableEntry[i].mItemID.isNull() && !mWearableEntry[i].mWearable )
6399 {
6400 mWearablesLoaded = FALSE;
6401 break;
6402 }
6403 }
6404
6405 if( mWearablesLoaded )
6406 {
6407 // Make sure that the server's idea of the avatar's wearables actually match the wearables.
6408 sendAgentSetAppearance();
6409 }
6410 else
6411 {
6412 gInventory.addChangedMask( LLInventoryObserver::LABEL, LLUUID::null );
6413 gInventory.notifyObservers();
6414 }
6415}
6416
6417void LLAgent::createStandardWearables(BOOL female)
6418{
6419 llwarns << "Creating Standard " << (female ? "female" : "male" )
6420 << " Wearables" << llendl;
6421
6422 if (mAvatarObject.isNull())
6423 {
6424 return;
6425 }
6426
6427 if(female) mAvatarObject->setSex(SEX_FEMALE);
6428 else mAvatarObject->setSex(SEX_MALE);
6429
6430 BOOL create[WT_COUNT] =
6431 {
6432 TRUE, //WT_SHAPE
6433 TRUE, //WT_SKIN
6434 TRUE, //WT_HAIR
6435 TRUE, //WT_EYES
6436 TRUE, //WT_SHIRT
6437 TRUE, //WT_PANTS
6438 TRUE, //WT_SHOES
6439 TRUE, //WT_SOCKS
6440 FALSE, //WT_JACKET
6441 FALSE, //WT_GLOVES
6442 TRUE, //WT_UNDERSHIRT
6443 TRUE, //WT_UNDERPANTS
6444 FALSE //WT_SKIRT
6445 };
6446
6447 for( S32 i=0; i < WT_COUNT; i++ )
6448 {
6449 bool once = false;
6450 LLPointer<LLRefCount> donecb = NULL;
6451 if( create[i] )
6452 {
6453 if (!once)
6454 {
6455 once = true;
6456 donecb = new createStandardWearablesAllDoneCallback;
6457 }
6458 llassert( mWearableEntry[i].mWearable == NULL );
6459 LLWearable* wearable = gWearableList.createNewWearable((EWearableType)i);
6460 mWearableEntry[i].mWearable = wearable;
6461 // no need to update here...
6462 LLPointer<LLInventoryCallback> cb =
6463 new addWearableToAgentInventoryCallback(
6464 donecb,
6465 i,
6466 wearable,
6467 addWearableToAgentInventoryCallback::CALL_CREATESTANDARDDONE);
6468 addWearableToAgentInventory(cb, wearable, LLUUID::null, FALSE);
6469 }
6470 }
6471}
6472void LLAgent::createStandardWearablesDone(S32 index)
6473{
6474 LLWearable* wearable = mWearableEntry[index].mWearable;
6475
6476 if (wearable)
6477 {
6478 wearable->writeToAvatar(TRUE);
6479 }
6480}
6481
6482void LLAgent::createStandardWearablesAllDone()
6483{
6484 // ... because sendAgentWearablesUpdate will notify inventory
6485 // observers.
6486 mWearablesLoaded = TRUE;
6487 sendAgentWearablesUpdate();
6488 sendAgentSetAppearance();
6489
6490 // Treat this as the first texture entry message, if none received yet
6491 mAvatarObject->onFirstTEMessageReceived();
6492}
6493
6494void LLAgent::makeNewOutfit(
6495 const std::string& new_folder_name,
6496 const LLDynamicArray<S32>& wearables_to_include,
6497 const LLDynamicArray<S32>& attachments_to_include,
6498 BOOL rename_clothing)
6499{
6500 if (mAvatarObject.isNull())
6501 {
6502 return;
6503 }
6504
6505 // First, make a folder in the Clothes directory.
6506 LLUUID folder_id = gInventory.createNewCategory(
6507 gInventory.findCategoryUUIDForType(LLAssetType::AT_CLOTHING),
6508 LLAssetType::AT_NONE,
6509 new_folder_name);
6510
6511 bool found_first_item = false;
6512
6513 ///////////////////
6514 // Wearables
6515
6516 if( wearables_to_include.count() )
6517 {
6518 // Then, iterate though each of the wearables and save copies of them in the folder.
6519 S32 i;
6520 S32 count = wearables_to_include.count();
6521 LLDynamicArray<LLUUID> delete_items;
6522 LLPointer<LLRefCount> cbdone = NULL;
6523 for( i = 0; i < count; ++i )
6524 {
6525 S32 index = wearables_to_include[i];
6526 LLWearable* old_wearable = mWearableEntry[ index ].mWearable;
6527 if( old_wearable )
6528 {
6529 std::string new_name;
6530 LLWearable* new_wearable;
6531 new_wearable = gWearableList.createCopy(old_wearable);
6532 if (rename_clothing)
6533 {
6534 new_name = new_folder_name;
6535 new_name.append(" ");
6536 new_name.append(old_wearable->getTypeLabel());
6537 LLString::truncate(new_name, DB_INV_ITEM_NAME_STR_LEN);
6538 new_wearable->setName(new_name);
6539 }
6540
6541 LLViewerInventoryItem* item = gInventory.getItem(mWearableEntry[index].mItemID);
6542 S32 todo = addWearableToAgentInventoryCallback::CALL_NONE;
6543 if (!found_first_item)
6544 {
6545 found_first_item = true;
6546 /* set the focus to the first item */
6547 todo |= addWearableToAgentInventoryCallback::CALL_MAKENEWOUTFITDONE;
6548 /* send the agent wearables update when done */
6549 cbdone = new sendAgentWearablesUpdateCallback;
6550 }
6551 LLPointer<LLInventoryCallback> cb =
6552 new addWearableToAgentInventoryCallback(
6553 cbdone,
6554 index,
6555 new_wearable,
6556 todo);
6557 if (isWearableCopyable((EWearableType)index))
6558 {
6559 copy_inventory_item(
6560 gAgent.getID(),
6561 item->getPermissions().getOwner(),
6562 item->getUUID(),
6563 folder_id,
6564 new_name,
6565 cb);
6566 }
6567 else
6568 {
6569 move_inventory_item(
6570 gAgent.getID(),
6571 gAgent.getSessionID(),
6572 item->getUUID(),
6573 folder_id,
6574 new_name,
6575 cb);
6576 }
6577 }
6578 }
6579 gInventory.notifyObservers();
6580 }
6581
6582
6583 ///////////////////
6584 // Attachments
6585
6586 if( attachments_to_include.count() )
6587 {
6588 BOOL msg_started = FALSE;
6589 LLMessageSystem* msg = gMessageSystem;
6590 S32 i;
6591 for( i = 0; i < attachments_to_include.count(); i++ )
6592 {
6593 S32 attachment_pt = attachments_to_include[i];
6594 LLViewerJointAttachment* attachment = mAvatarObject->mAttachmentPoints.getIfThere( attachment_pt );
6595 if(!attachment) continue;
6596 LLViewerObject* attached_object = attachment->getObject(0);
6597 if(!attached_object) continue;
6598 const LLUUID& item_id = attachment->getItemID();
6599 if(item_id.isNull()) continue;
6600 LLInventoryItem* item = gInventory.getItem(item_id);
6601 if(!item) continue;
6602 if(!msg_started)
6603 {
6604 msg_started = TRUE;
6605 msg->newMessage("CreateNewOutfitAttachments");
6606 msg->nextBlock("AgentData");
6607 msg->addUUID("AgentID", getID());
6608 msg->addUUID("SessionID", getSessionID());
6609 msg->nextBlock("HeaderData");
6610 msg->addUUID("NewFolderID", folder_id);
6611 }
6612 msg->nextBlock("ObjectData");
6613 msg->addUUID("OldItemID", item_id);
6614 msg->addUUID("OldFolderID", item->getParentUUID());
6615 }
6616
6617 if( msg_started )
6618 {
6619 sendReliableMessage();
6620 }
6621
6622 }
6623}
6624
6625void LLAgent::makeNewOutfitDone(S32 index)
6626{
6627 LLUUID first_item_id = mWearableEntry[index].mItemID;
6628 // Open the inventory and select the first item we added.
6629 if( first_item_id.notNull() )
6630 {
6631 LLInventoryView* view = LLInventoryView::getActiveInventory();
6632 if(view)
6633 {
6634 view->getPanel()->setSelection(first_item_id, TAKE_FOCUS_NO);
6635 }
6636 }
6637}
6638
6639
6640void LLAgent::addWearableToAgentInventory(
6641 LLPointer<LLInventoryCallback> cb,
6642 LLWearable* wearable,
6643 const LLUUID& category_id,
6644 BOOL notify)
6645{
6646 create_inventory_item(
6647 gAgent.getID(),
6648 gAgent.getSessionID(),
6649 category_id,
6650 wearable->getTransactionID(),
6651 wearable->getName(),
6652 wearable->getDescription(),
6653 wearable->getAssetType(),
6654 LLInventoryType::IT_WEARABLE,
6655 wearable->getType(),
6656 wearable->getPermissions().getMaskNextOwner(),
6657 cb);
6658}
6659
6660//-----------------------------------------------------------------------------
6661// sendAgentSetAppearance()
6662//-----------------------------------------------------------------------------
6663void LLAgent::sendAgentSetAppearance()
6664{
6665 if (mAvatarObject.isNull()) return;
6666
6667 if (mNumPendingQueries > 0 && !gAgent.cameraCustomizeAvatar())
6668 {
6669 return;
6670 }
6671
6672 llinfos << "TAT: Sent AgentSetAppearance: " <<
6673 (( mAvatarObject->getTEImage( LLVOAvatar::TEX_HEAD_BAKED )->getID() != IMG_DEFAULT_AVATAR ) ? "HEAD " : "head " ) <<
6674 (( mAvatarObject->getTEImage( LLVOAvatar::TEX_UPPER_BAKED )->getID() != IMG_DEFAULT_AVATAR ) ? "UPPER " : "upper " ) <<
6675 (( mAvatarObject->getTEImage( LLVOAvatar::TEX_LOWER_BAKED )->getID() != IMG_DEFAULT_AVATAR ) ? "LOWER " : "lower " ) <<
6676 (( mAvatarObject->getTEImage( LLVOAvatar::TEX_EYES_BAKED )->getID() != IMG_DEFAULT_AVATAR ) ? "EYES" : "eyes" ) << llendl;
6677 //dumpAvatarTEs( "sendAgentSetAppearance()" );
6678
6679 LLMessageSystem* msg = gMessageSystem;
6680 msg->newMessageFast(_PREHASH_AgentSetAppearance);
6681 msg->nextBlockFast(_PREHASH_AgentData);
6682 msg->addUUIDFast(_PREHASH_AgentID, getID());
6683 msg->addUUIDFast(_PREHASH_SessionID, getSessionID());
6684
6685 // correct for the collisiton tolerance (to make it look like the
6686 // agent is actually walking on the ground/object)
6687 // NOTE -- when we start correcting all of the other Havok geometry
6688 // to compensate for the COLLISION_TOLERANCE ugliness we will have
6689 // to tweak this number again
6690 LLVector3 body_size = mAvatarObject->mBodySize;
6691 msg->addVector3Fast(_PREHASH_Size, body_size);
6692
6693 // To guard against out of order packets
6694 // Note: always start by sending 1. This resets the server's count. 0 on the server means "uninitialized"
6695 mAppearanceSerialNum++;
6696 msg->addU32Fast(_PREHASH_SerialNum, mAppearanceSerialNum );
6697
6698 // is texture data current relative to wearables?
6699 // KLW - TAT this will probably need to check the local queue.
6700 BOOL textures_current = !mAvatarObject->hasPendingBakedUploads() && mWearablesLoaded;
6701
6702 S32 baked_texture_index;
6703 for( baked_texture_index = 0; baked_texture_index < BAKED_TEXTURE_COUNT; baked_texture_index++ )
6704 {
6705 S32 tex_index = LLVOAvatar::sBakedTextureIndices[baked_texture_index];
6706
6707 // if we're not wearing a skirt, we don't need the texture to be baked
6708 if (tex_index == LLVOAvatar::TEX_SKIRT_BAKED && !mAvatarObject->isWearingWearableType(WT_SKIRT))
6709 {
6710 continue;
6711 }
6712
6713 // IMG_DEFAULT_AVATAR means not baked
6714 if (mAvatarObject->getTEImage( tex_index)->getID() == IMG_DEFAULT_AVATAR)
6715 {
6716 textures_current = FALSE;
6717 break;
6718 }
6719 }
6720
6721 // only update cache entries if we have all our baked textures
6722 if (textures_current)
6723 {
6724 llinfos << "TAT: Sending cached texture data" << llendl;
6725 for (baked_texture_index = 0; baked_texture_index < BAKED_TEXTURE_COUNT; baked_texture_index++)
6726 {
6727 LLUUID hash;
6728
6729 for( S32 wearable_num = 0; wearable_num < MAX_WEARABLES_PER_LAYERSET; wearable_num++ )
6730 {
6731 EWearableType wearable_type = WEARABLE_BAKE_TEXTURE_MAP[baked_texture_index][wearable_num];
6732
6733 LLWearable* wearable = getWearable( wearable_type );
6734 if (wearable)
6735 {
6736 hash ^= wearable->getID();
6737 }
6738 }
6739
6740 if (hash.notNull())
6741 {
6742 hash ^= BAKED_TEXTURE_HASH[baked_texture_index];
6743 }
6744
6745 S32 tex_index = LLVOAvatar::sBakedTextureIndices[baked_texture_index];
6746
6747 msg->nextBlockFast(_PREHASH_WearableData);
6748 msg->addUUIDFast(_PREHASH_CacheID, hash);
6749 msg->addU8Fast(_PREHASH_TextureIndex, (U8)tex_index);
6750 }
6751 }
6752
6753 msg->nextBlockFast(_PREHASH_ObjectData);
6754 mAvatarObject->packTEMessage( gMessageSystem );
6755
6756 S32 transmitted_params = 0;
6757 for (LLViewerVisualParam* param = (LLViewerVisualParam*)mAvatarObject->getFirstVisualParam();
6758 param;
6759 param = (LLViewerVisualParam*)mAvatarObject->getNextVisualParam())
6760 {
6761 F32 param_value = param->getWeight();
6762
6763 if (param->getGroup() == VISUAL_PARAM_GROUP_TWEAKABLE)
6764 {
6765 msg->nextBlockFast(_PREHASH_VisualParam );
6766
6767 // We don't send the param ids. Instead, we assume that the receiver has the same params in the same sequence.
6768 U8 new_weight = F32_to_U8(param_value, param->getMinWeight(), param->getMaxWeight());
6769 msg->addU8Fast(_PREHASH_ParamValue, new_weight );
6770 transmitted_params++;
6771 }
6772 }
6773
6774// llinfos << "Avatar XML num VisualParams transmitted = " << transmitted_params << llendl;
6775 sendReliableMessage();
6776}
6777
6778void LLAgent::sendAgentDataUpdateRequest()
6779{
6780 gMessageSystem->newMessageFast(_PREHASH_AgentDataUpdateRequest);
6781 gMessageSystem->nextBlockFast(_PREHASH_AgentData);
6782 gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
6783 gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
6784 sendReliableMessage();
6785}
6786
6787void LLAgent::removeWearable( EWearableType type )
6788{
6789 LLWearable* old_wearable = mWearableEntry[ type ].mWearable;
6790
6791 if ( (gAgent.mAccess < SIM_ACCESS_MATURE)
6792 && (type == WT_UNDERSHIRT || type == WT_UNDERPANTS))
6793 {
6794 // Can't take off underclothing in simple UI mode or on PG accounts
6795 return;
6796 }
6797
6798 if( old_wearable )
6799 {
6800 if( old_wearable->isDirty() )
6801 {
6802 // Bring up view-modal dialog: Save changes? Yes, No, Cancel
6803 gViewerWindow->alertXml("RemoveWearableSave", LLAgent::onRemoveWearableDialog, (void*)(S32)type );
6804 return;
6805 }
6806 else
6807 {
6808 removeWearableFinal( type );
6809 }
6810 }
6811}
6812
6813// static
6814void LLAgent::onRemoveWearableDialog( S32 option, void* userdata )
6815{
6816 EWearableType type = (EWearableType)(intptr_t)userdata;
6817 switch( option )
6818 {
6819 case 0: // "Save"
6820 gAgent.saveWearable( type );
6821 gAgent.removeWearableFinal( type );
6822 break;
6823
6824 case 1: // "Don't Save"
6825 gAgent.removeWearableFinal( type );
6826 break;
6827
6828 case 2: // "Cancel"
6829 break;
6830
6831 default:
6832 llassert(0);
6833 break;
6834 }
6835}
6836
6837// Called by removeWearable() and onRemoveWearableDialog() to actually do the removal.
6838void LLAgent::removeWearableFinal( EWearableType type )
6839{
6840 LLWearable* old_wearable = mWearableEntry[ type ].mWearable;
6841
6842 gInventory.addChangedMask( LLInventoryObserver::LABEL, mWearableEntry[type].mItemID );
6843
6844 mWearableEntry[ type ].mWearable = NULL;
6845 mWearableEntry[ type ].mItemID.setNull();
6846
6847 queryWearableCache();
6848
6849 if( old_wearable )
6850 {
6851 old_wearable->removeFromAvatar( TRUE );
6852 }
6853
6854 // Update the server
6855 sendAgentWearablesUpdate();
6856 sendAgentSetAppearance();
6857 gInventory.notifyObservers();
6858}
6859
6860void LLAgent::copyWearableToInventory( EWearableType type )
6861{
6862 LLWearable* wearable = mWearableEntry[ type ].mWearable;
6863 if( wearable )
6864 {
6865 // Save the old wearable if it has changed.
6866 if( wearable->isDirty() )
6867 {
6868 wearable = gWearableList.createCopyFromAvatar( wearable );
6869 mWearableEntry[ type ].mWearable = wearable;
6870 }
6871
6872 // Make a new entry in the inventory. (Put it in the same folder as the original item if possible.)
6873 LLUUID category_id;
6874 LLInventoryItem* item = gInventory.getItem( mWearableEntry[ type ].mItemID );
6875 if( item )
6876 {
6877 category_id = item->getParentUUID();
6878 wearable->setPermissions(item->getPermissions());
6879 }
6880 LLPointer<LLInventoryCallback> cb =
6881 new addWearableToAgentInventoryCallback(
6882 LLPointer<LLRefCount>(NULL),
6883 type,
6884 wearable);
6885 addWearableToAgentInventory(cb, wearable, category_id);
6886 }
6887}
6888
6889
6890// A little struct to let setWearable() communicate more than one value with onSetWearableDialog().
6891struct LLSetWearableData
6892{
6893 LLSetWearableData( const LLUUID& new_item_id, LLWearable* new_wearable ) :
6894 mNewItemID( new_item_id ), mNewWearable( new_wearable ) {}
6895 LLUUID mNewItemID;
6896 LLWearable* mNewWearable;
6897};
6898
6899BOOL LLAgent::needsReplacement(EWearableType wearableType, S32 remove)
6900{
6901 return TRUE;
6902 /*if (remove) return TRUE;
6903
6904 return getWearable(wearableType) ? TRUE : FALSE;*/
6905}
6906
6907// Assumes existing wearables are not dirty.
6908void LLAgent::setWearableOutfit(
6909 const LLInventoryItem::item_array_t& items,
6910 const LLDynamicArray< LLWearable* >& wearables,
6911 BOOL remove )
6912{
6913 lldebugs << "setWearableOutfit() start" << llendl;
6914
6915 BOOL wearables_to_remove[WT_COUNT];
6916 wearables_to_remove[WT_SHAPE] = FALSE;
6917 wearables_to_remove[WT_SKIN] = FALSE;
6918 wearables_to_remove[WT_HAIR] = FALSE;
6919 wearables_to_remove[WT_EYES] = FALSE;
6920 wearables_to_remove[WT_SHIRT] = remove;
6921 wearables_to_remove[WT_PANTS] = remove;
6922 wearables_to_remove[WT_SHOES] = remove;
6923 wearables_to_remove[WT_SOCKS] = remove;
6924 wearables_to_remove[WT_JACKET] = remove;
6925 wearables_to_remove[WT_GLOVES] = remove;
6926 wearables_to_remove[WT_UNDERSHIRT] = (gAgent.mAccess >= SIM_ACCESS_MATURE) & remove;
6927 wearables_to_remove[WT_UNDERPANTS] = (gAgent.mAccess >= SIM_ACCESS_MATURE) & remove;
6928 wearables_to_remove[WT_SKIRT] = remove;
6929
6930 S32 count = wearables.count();
6931 llassert( items.count() == count );
6932
6933 S32 i;
6934 for( i = 0; i < count; i++ )
6935 {
6936 LLWearable* new_wearable = wearables[i];
6937 LLPointer<LLInventoryItem> new_item = items[i];
6938
6939 EWearableType type = new_wearable->getType();
6940 wearables_to_remove[type] = FALSE;
6941
6942 LLWearable* old_wearable = mWearableEntry[ type ].mWearable;
6943 if( old_wearable )
6944 {
6945 const LLUUID& old_item_id = mWearableEntry[ type ].mItemID;
6946 if( (old_wearable->getID() == new_wearable->getID()) &&
6947 (old_item_id == new_item->getUUID()) )
6948 {
6949 lldebugs << "No change to wearable asset and item: " << LLWearable::typeToTypeName( type ) << llendl;
6950 continue;
6951 }
6952
6953 gInventory.addChangedMask(LLInventoryObserver::LABEL, old_item_id);
6954
6955 // Assumes existing wearables are not dirty.
6956 if( old_wearable->isDirty() )
6957 {
6958 llassert(0);
6959 continue;
6960 }
6961 }
6962
6963 mWearableEntry[ type ].mItemID = new_item->getUUID();
6964 mWearableEntry[ type ].mWearable = new_wearable;
6965 }
6966
6967 std::vector<LLWearable*> wearables_being_removed;
6968
6969 for( i = 0; i < WT_COUNT; i++ )
6970 {
6971 if( wearables_to_remove[i] )
6972 {
6973 wearables_being_removed.push_back(mWearableEntry[ i ].mWearable);
6974 mWearableEntry[ i ].mWearable = NULL;
6975
6976 gInventory.addChangedMask(LLInventoryObserver::LABEL, mWearableEntry[ i ].mItemID);
6977 mWearableEntry[ i ].mItemID.setNull();
6978 }
6979 }
6980
6981 gInventory.notifyObservers();
6982
6983 queryWearableCache();
6984
6985 std::vector<LLWearable*>::iterator wearable_iter;
6986
6987 for( wearable_iter = wearables_being_removed.begin();
6988 wearable_iter != wearables_being_removed.end();
6989 ++wearable_iter)
6990 {
6991 LLWearable* wearablep = *wearable_iter;
6992 if (wearablep)
6993 {
6994 wearablep->removeFromAvatar( TRUE );
6995 }
6996 }
6997
6998 for( i = 0; i < count; i++ )
6999 {
7000 wearables[i]->writeToAvatar( TRUE );
7001 }
7002
7003 LLFloaterCustomize::setCurrentWearableType( WT_SHAPE );
7004
7005 // Start rendering & update the server
7006 mWearablesLoaded = TRUE;
7007 sendAgentWearablesUpdate();
7008 sendAgentSetAppearance();
7009
7010 lldebugs << "setWearableOutfit() end" << llendl;
7011}
7012
7013
7014// User has picked "wear on avatar" from a menu.
7015void LLAgent::setWearable( LLInventoryItem* new_item, LLWearable* new_wearable )
7016{
7017 EWearableType type = new_wearable->getType();
7018
7019 LLWearable* old_wearable = mWearableEntry[ type ].mWearable;
7020 if( old_wearable )
7021 {
7022 const LLUUID& old_item_id = mWearableEntry[ type ].mItemID;
7023 if( (old_wearable->getID() == new_wearable->getID()) &&
7024 (old_item_id == new_item->getUUID()) )
7025 {
7026 lldebugs << "No change to wearable asset and item: " << LLWearable::typeToTypeName( type ) << llendl;
7027 return;
7028 }
7029
7030 if( old_wearable->isDirty() )
7031 {
7032 // Bring up modal dialog: Save changes? Yes, No, Cancel
7033 gViewerWindow->alertXml( "SetWearableSave", LLAgent::onSetWearableDialog,
7034 new LLSetWearableData( new_item->getUUID(), new_wearable ));
7035 return;
7036 }
7037 }
7038
7039 setWearableFinal( new_item, new_wearable );
7040}
7041
7042// static
7043void LLAgent::onSetWearableDialog( S32 option, void* userdata )
7044{
7045 LLSetWearableData* data = (LLSetWearableData*)userdata;
7046 LLInventoryItem* new_item = gInventory.getItem( data->mNewItemID );
7047 if( !new_item )
7048 {
7049 delete data;
7050 return;
7051 }
7052
7053 switch( option )
7054 {
7055 case 0: // "Save"
7056 gAgent.saveWearable( data->mNewWearable->getType() );
7057 gAgent.setWearableFinal( new_item, data->mNewWearable );
7058 break;
7059
7060 case 1: // "Don't Save"
7061 gAgent.setWearableFinal( new_item, data->mNewWearable );
7062 break;
7063
7064 case 2: // "Cancel"
7065 break;
7066
7067 default:
7068 llassert(0);
7069 break;
7070 }
7071
7072 delete data;
7073}
7074
7075// Called from setWearable() and onSetWearableDialog() to actually set the wearable.
7076void LLAgent::setWearableFinal( LLInventoryItem* new_item, LLWearable* new_wearable )
7077{
7078 EWearableType type = new_wearable->getType();
7079
7080 // Replace the old wearable with a new one.
7081 llassert( new_item->getAssetUUID() == new_wearable->getID() );
7082 LLUUID old_item_id = mWearableEntry[ type ].mItemID;
7083 mWearableEntry[ type ].mItemID = new_item->getUUID();
7084 mWearableEntry[ type ].mWearable = new_wearable;
7085
7086 if (old_item_id.notNull())
7087 {
7088 gInventory.addChangedMask( LLInventoryObserver::LABEL, old_item_id );
7089 gInventory.notifyObservers();
7090 }
7091
7092 //llinfos << "LLVOAvatar::setWearable()" << llendl;
7093 queryWearableCache();
7094 new_wearable->writeToAvatar( TRUE );
7095
7096 // Update the server
7097 sendAgentWearablesUpdate();
7098 sendAgentSetAppearance();
7099}
7100
7101void LLAgent::queryWearableCache()
7102{
7103 if (!mWearablesLoaded)
7104 {
7105 return;
7106 }
7107
7108 // Look up affected baked textures.
7109 // If they exist:
7110 // disallow updates for affected layersets (until dataserver responds with cache request.)
7111 // If cache miss…turn updates back on and invalidate composite.
7112 // If cache hit, modify baked texture entries.
7113 //
7114 // Cache requests contain list of hashes for each baked texture entry.
7115 // Response is list of valid baked texture assets. (same message)
7116
7117 gMessageSystem->newMessageFast(_PREHASH_AgentCachedTexture);
7118 gMessageSystem->nextBlockFast(_PREHASH_AgentData);
7119 gMessageSystem->addUUIDFast(_PREHASH_AgentID, getID());
7120 gMessageSystem->addUUIDFast(_PREHASH_SessionID, getSessionID());
7121 gMessageSystem->addS32Fast(_PREHASH_SerialNum, mTextureCacheQueryID);
7122
7123 S32 num_queries = 0;
7124 for (S32 baked_texture_index = 0; baked_texture_index < BAKED_TEXTURE_COUNT; baked_texture_index++)
7125 {
7126 LLUUID hash;
7127 for (S32 wearable_num = 0; wearable_num < MAX_WEARABLES_PER_LAYERSET; wearable_num++)
7128 {
7129 EWearableType wearable_type = WEARABLE_BAKE_TEXTURE_MAP[baked_texture_index][wearable_num];
7130
7131 LLWearable* wearable = getWearable( wearable_type );
7132 if (wearable)
7133 {
7134 hash ^= wearable->getID();
7135 }
7136 }
7137 if (hash.notNull())
7138 {
7139 hash ^= BAKED_TEXTURE_HASH[baked_texture_index];
7140 num_queries++;
7141 // *NOTE: make sure at least one request gets packed
7142
7143 //llinfos << "Requesting texture for hash " << hash << " in baked texture slot " << baked_texture_index << llendl;
7144 gMessageSystem->nextBlockFast(_PREHASH_WearableData);
7145 gMessageSystem->addUUIDFast(_PREHASH_ID, hash);
7146 gMessageSystem->addU8Fast(_PREHASH_TextureIndex, (U8)baked_texture_index);
7147 }
7148
7149 mActiveCacheQueries[ baked_texture_index ] = mTextureCacheQueryID;
7150 }
7151
7152 llinfos << "Requesting texture cache entry for " << num_queries << " baked textures" << llendl;
7153 gMessageSystem->sendReliable(getRegion()->getHost());
7154 mNumPendingQueries++;
7155 mTextureCacheQueryID++;
7156}
7157
7158// User has picked "remove from avatar" from a menu.
7159// static
7160void LLAgent::userRemoveWearable( void* userdata )
7161{
7162 EWearableType type = (EWearableType)(intptr_t)userdata;
7163
7164 if( !(type==WT_SHAPE || type==WT_SKIN || type==WT_HAIR ) ) //&&
7165 //!((gAgent.mAccess >= SIM_ACCESS_MATURE) && ( type==WT_UNDERPANTS || type==WT_UNDERSHIRT )) )
7166 {
7167 gAgent.removeWearable( type );
7168 }
7169}
7170
7171void LLAgent::userRemoveAllClothes( void* userdata )
7172{
7173 // We have to do this up front to avoid having to deal with the case of multiple wearables being dirty.
7174 if( gFloaterCustomize )
7175 {
7176 gFloaterCustomize->askToSaveAllIfDirty( LLAgent::userRemoveAllClothesStep2, NULL );
7177 }
7178 else
7179 {
7180 LLAgent::userRemoveAllClothesStep2( TRUE, NULL );
7181 }
7182}
7183
7184void LLAgent::userRemoveAllClothesStep2( BOOL proceed, void* userdata )
7185{
7186 if( proceed )
7187 {
7188 gAgent.removeWearable( WT_SHIRT );
7189 gAgent.removeWearable( WT_PANTS );
7190 gAgent.removeWearable( WT_SHOES );
7191 gAgent.removeWearable( WT_SOCKS );
7192 gAgent.removeWearable( WT_JACKET );
7193 gAgent.removeWearable( WT_GLOVES );
7194 gAgent.removeWearable( WT_UNDERSHIRT );
7195 gAgent.removeWearable( WT_UNDERPANTS );
7196 gAgent.removeWearable( WT_SKIRT );
7197 }
7198}
7199
7200void LLAgent::userRemoveAllAttachments( void* userdata )
7201{
7202 LLVOAvatar* avatarp = gAgent.getAvatarObject();
7203 if(!avatarp)
7204 {
7205 llwarns << "No avatar found." << llendl;
7206 return;
7207 }
7208
7209 gMessageSystem->newMessage("ObjectDetach");
7210 gMessageSystem->nextBlockFast(_PREHASH_AgentData);
7211 gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
7212 gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
7213
7214 LLViewerJointAttachment* attachment;
7215 for (attachment = avatarp->mAttachmentPoints.getFirstData();
7216 attachment;
7217 attachment = avatarp->mAttachmentPoints.getNextData())
7218 {
7219 LLViewerObject* objectp = attachment->getObject(0);
7220 if (objectp)
7221 {
7222 gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
7223 gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, objectp->getLocalID());
7224 }
7225 }
7226 gMessageSystem->sendReliable( gAgent.getRegionHost() );
7227}
7228
7229bool LLAgent::LLHideGroupTitleListener::handleEvent(LLPointer<LLEvent> event, const LLSD &userdata)
7230{
7231 gAgent.setHideGroupTitle(event->getValue());
7232 return true;
7233
7234}
7235
7236bool LLAgent::LLEffectColorListener::handleEvent(LLPointer<LLEvent> event, const LLSD &userdata)
7237{
7238 gAgent.setEffectColor(LLColor4(event->getValue()));
7239 return true;
7240}
7241
7242void LLAgent::observeFriends()
7243{
7244 if(!mFriendObserver)
7245 {
7246 mFriendObserver = new LLAgentFriendObserver;
7247 LLAvatarTracker::instance().addObserver(mFriendObserver);
7248 friendsChanged();
7249 }
7250}
7251
7252// EOF