diff options
author | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
---|---|---|
committer | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
commit | 38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch) | |
tree | adca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/newview/llagent.cpp | |
parent | README.txt (diff) | |
download | meta-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.cpp | 7252 |
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 | |||
124 | extern LLMenuBarGL* gMenuBarView; | ||
125 | extern F32 gMinObjectDistance; | ||
126 | extern U8 gLastPickAlpha; | ||
127 | extern F32 gFrameDTClamped; | ||
128 | |||
129 | //drone wandering constants | ||
130 | const F32 MAX_WANDER_TIME = 20.f; // seconds | ||
131 | const F32 MAX_HEADING_HALF_ERROR = 0.2f; // radians | ||
132 | const F32 WANDER_MAX_SLEW_RATE = 2.f * DEG_TO_RAD; // radians / frame | ||
133 | const F32 WANDER_TARGET_MIN_DISTANCE = 10.f; // meters | ||
134 | |||
135 | // Autopilot constants | ||
136 | const F32 AUTOPILOT_HEADING_HALF_ERROR = 10.f * DEG_TO_RAD; // radians | ||
137 | const F32 AUTOPILOT_MAX_SLEW_RATE = 1.f * DEG_TO_RAD; // radians / frame | ||
138 | const F32 AUTOPILOT_STOP_DISTANCE = 2.f; // meters | ||
139 | const F32 AUTOPILOT_HEIGHT_ADJUST_DISTANCE = 8.f; // meters | ||
140 | const F32 AUTOPILOT_MIN_TARGET_HEIGHT_OFF_GROUND = 1.f; // meters | ||
141 | const F32 AUTOPILOT_MAX_TIME_NO_PROGRESS = 1.5f; // seconds | ||
142 | |||
143 | // face editing constants | ||
144 | const LLVector3d FACE_EDIT_CAMERA_OFFSET(0.4f, -0.05f, 0.07f); | ||
145 | const LLVector3d FACE_EDIT_TARGET_OFFSET(0.f, 0.f, 0.05f); | ||
146 | |||
147 | // Mousewheel camera zoom | ||
148 | const F32 MIN_ZOOM_FRACTION = 0.25f; | ||
149 | const F32 INITIAL_ZOOM_FRACTION = 1.f; | ||
150 | const F32 MAX_ZOOM_FRACTION = 8.f; | ||
151 | const F32 METERS_PER_WHEEL_CLICK = 1.f; | ||
152 | |||
153 | const F32 MAX_TIME_DELTA = 1.f; | ||
154 | |||
155 | const F32 CAMERA_ZOOM_HALF_LIFE = 0.07f; // seconds | ||
156 | const F32 FOV_ZOOM_HALF_LIFE = 0.07f; // seconds | ||
157 | |||
158 | const F32 CAMERA_FOCUS_HALF_LIFE = 0.f;//0.02f; | ||
159 | const F32 CAMERA_LAG_HALF_LIFE = 0.25f; | ||
160 | const F32 MIN_CAMERA_LAG = 0.5f; | ||
161 | const F32 MAX_CAMERA_LAG = 5.f; | ||
162 | |||
163 | const F32 CAMERA_COLLIDE_EPSILON = 0.1f; | ||
164 | const F32 MIN_CAMERA_DISTANCE = 0.1f; | ||
165 | const F32 AVATAR_ZOOM_MIN_X_FACTOR = 0.55f; | ||
166 | const F32 AVATAR_ZOOM_MIN_Y_FACTOR = 0.7f; | ||
167 | const F32 AVATAR_ZOOM_MIN_Z_FACTOR = 1.15f; | ||
168 | |||
169 | const F32 MAX_CAMERA_DISTANCE_FROM_AGENT = 50.f; | ||
170 | |||
171 | const F32 HEAD_BUFFER_SIZE = 0.3f; | ||
172 | const F32 CUSTOMIZE_AVATAR_CAMERA_ANIM_SLOP = 0.2f; | ||
173 | |||
174 | const F32 LAND_MIN_ZOOM = 0.15f; | ||
175 | const F32 AVATAR_MIN_ZOOM = 0.5f; | ||
176 | const F32 OBJECT_MIN_ZOOM = 0.02f; | ||
177 | |||
178 | const F32 APPEARANCE_MIN_ZOOM = 0.39f; | ||
179 | const F32 APPEARANCE_MAX_ZOOM = 8.f; | ||
180 | |||
181 | // fidget constants | ||
182 | const F32 MIN_FIDGET_TIME = 8.f; // seconds | ||
183 | const F32 MAX_FIDGET_TIME = 20.f; // seconds | ||
184 | |||
185 | const S32 MAX_NUM_CHAT_POSITIONS = 10; | ||
186 | const F32 GROUND_TO_AIR_CAMERA_TRANSITION_TIME = 0.5f; | ||
187 | const F32 GROUND_TO_AIR_CAMERA_TRANSITION_START_TIME = 0.5f; | ||
188 | |||
189 | const F32 MAX_VELOCITY_AUTO_LAND_SQUARED = 4.f * 4.f; | ||
190 | |||
191 | const F32 MAX_FOCUS_OFFSET = 20.f; | ||
192 | |||
193 | const F32 OBJECT_EXTENTS_PADDING = 0.5f; | ||
194 | |||
195 | const F32 MIN_RADIUS_ALPHA_SIZZLE = 0.5f; | ||
196 | |||
197 | const F64 CHAT_AGE_FAST_RATE = 3.0; | ||
198 | |||
199 | const S32 MAX_WEARABLES_PER_LAYERSET = 7; | ||
200 | |||
201 | const 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 | |||
210 | const 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 | // | ||
222 | BOOL LLAgent::sDebugDisplayTarget = FALSE; | ||
223 | |||
224 | const F32 LLAgent::TYPING_TIMEOUT_SECS = 5.f; | ||
225 | |||
226 | class LLAgentFriendObserver : public LLFriendObserver | ||
227 | { | ||
228 | public: | ||
229 | LLAgentFriendObserver() {} | ||
230 | virtual ~LLAgentFriendObserver() {} | ||
231 | virtual void changed(U32 mask); | ||
232 | }; | ||
233 | |||
234 | void 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 | //----------------------------------------------------------------------------- | ||
258 | LLAgent::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 | //----------------------------------------------------------------------------- | ||
408 | void 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 | //----------------------------------------------------------------------------- | ||
445 | void 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 | //----------------------------------------------------------------------------- | ||
459 | LLAgent::~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 | //----------------------------------------------------------------------------- | ||
475 | void 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 | |||
517 | void 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 | //----------------------------------------------------------------------------- | ||
532 | void 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 | //----------------------------------------------------------------------------- | ||
548 | void 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 | //----------------------------------------------------------------------------- | ||
570 | void 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 | //----------------------------------------------------------------------------- | ||
592 | void 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 | //----------------------------------------------------------------------------- | ||
614 | void 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 | //----------------------------------------------------------------------------- | ||
636 | void 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 | //----------------------------------------------------------------------------- | ||
658 | void 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 | //----------------------------------------------------------------------------- | ||
677 | void 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? | ||
693 | BOOL 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 | //----------------------------------------------------------------------------- | ||
718 | void 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 | //----------------------------------------------------------------------------- | ||
768 | void LLAgent::toggleFlying() | ||
769 | { | ||
770 | BOOL fly = !(mControlFlags & AGENT_CONTROL_FLY); | ||
771 | |||
772 | setFlying( fly ); | ||
773 | resetView(); | ||
774 | } | ||
775 | |||
776 | |||
777 | //----------------------------------------------------------------------------- | ||
778 | // setRegion() | ||
779 | //----------------------------------------------------------------------------- | ||
780 | void 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 | //----------------------------------------------------------------------------- | ||
859 | LLViewerRegion *LLAgent::getRegion() const | ||
860 | { | ||
861 | return mRegionp; | ||
862 | } | ||
863 | |||
864 | |||
865 | const 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 | //----------------------------------------------------------------------------- | ||
881 | BOOL LLAgent::inPrelude() | ||
882 | { | ||
883 | return mRegionp && mRegionp->isPrelude(); | ||
884 | } | ||
885 | |||
886 | |||
887 | //----------------------------------------------------------------------------- | ||
888 | // canManageEstate() | ||
889 | //----------------------------------------------------------------------------- | ||
890 | |||
891 | BOOL LLAgent::canManageEstate() const | ||
892 | { | ||
893 | return mRegionp && mRegionp->canManageEstate(); | ||
894 | } | ||
895 | //----------------------------------------------------------------------------- | ||
896 | // sendMessage() | ||
897 | //----------------------------------------------------------------------------- | ||
898 | void 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 | //----------------------------------------------------------------------------- | ||
916 | void 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 | //----------------------------------------------------------------------------- | ||
934 | LLVector3 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 | //----------------------------------------------------------------------------- | ||
950 | void 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 | //----------------------------------------------------------------------------- | ||
982 | void 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 | //----------------------------------------------------------------------------- | ||
993 | const 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 | //----------------------------------------------------------------------------- | ||
1010 | const 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 | //----------------------------------------------------------------------------- | ||
1023 | const S32 LLAgent::getRegionsVisited() const | ||
1024 | { | ||
1025 | return mRegionsVisited.size(); | ||
1026 | } | ||
1027 | |||
1028 | //----------------------------------------------------------------------------- | ||
1029 | // getDistanceTraveled() | ||
1030 | //----------------------------------------------------------------------------- | ||
1031 | const F64 LLAgent::getDistanceTraveled() const | ||
1032 | { | ||
1033 | return mDistanceTraveled; | ||
1034 | } | ||
1035 | |||
1036 | |||
1037 | //----------------------------------------------------------------------------- | ||
1038 | // getPosAgentFromGlobal() | ||
1039 | //----------------------------------------------------------------------------- | ||
1040 | LLVector3 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 | //----------------------------------------------------------------------------- | ||
1051 | LLVector3d 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 | //----------------------------------------------------------------------------- | ||
1062 | void 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 | //----------------------------------------------------------------------------- | ||
1073 | void 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 | //----------------------------------------------------------------------------- | ||
1100 | void LLAgent::rotate(F32 angle, const LLVector3 &axis) | ||
1101 | { | ||
1102 | mFrameAgent.rotate(angle, axis); | ||
1103 | } | ||
1104 | |||
1105 | |||
1106 | //----------------------------------------------------------------------------- | ||
1107 | // rotate() | ||
1108 | //----------------------------------------------------------------------------- | ||
1109 | void 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 | //----------------------------------------------------------------------------- | ||
1118 | void LLAgent::rotate(const LLMatrix3 &matrix) | ||
1119 | { | ||
1120 | mFrameAgent.rotate(matrix); | ||
1121 | } | ||
1122 | |||
1123 | |||
1124 | //----------------------------------------------------------------------------- | ||
1125 | // rotate() | ||
1126 | //----------------------------------------------------------------------------- | ||
1127 | void LLAgent::rotate(const LLQuaternion &quaternion) | ||
1128 | { | ||
1129 | mFrameAgent.rotate(quaternion); | ||
1130 | } | ||
1131 | |||
1132 | |||
1133 | //----------------------------------------------------------------------------- | ||
1134 | // getReferenceUpVector() | ||
1135 | //----------------------------------------------------------------------------- | ||
1136 | LLVector3 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 | //----------------------------------------------------------------------------- | ||
1166 | void 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 | //----------------------------------------------------------------------------- | ||
1207 | void LLAgent::roll(F32 angle) | ||
1208 | { | ||
1209 | mFrameAgent.roll(angle); | ||
1210 | } | ||
1211 | |||
1212 | |||
1213 | //----------------------------------------------------------------------------- | ||
1214 | // yaw() | ||
1215 | //----------------------------------------------------------------------------- | ||
1216 | void 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 | //----------------------------------------------------------------------------- | ||
1229 | LLQuaternion LLAgent::getQuat() const | ||
1230 | { | ||
1231 | return mFrameAgent.getQuaternion(); | ||
1232 | } | ||
1233 | |||
1234 | |||
1235 | //----------------------------------------------------------------------------- | ||
1236 | // calcFocusOffset() | ||
1237 | //----------------------------------------------------------------------------- | ||
1238 | LLVector3d 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 | //----------------------------------------------------------------------------- | ||
1407 | BOOL 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 | |||
1583 | F32 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 | |||
1630 | void 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 | //----------------------------------------------------------------------------- | ||
1682 | void 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 | //----------------------------------------------------------------------------- | ||
1704 | void 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 | //----------------------------------------------------------------------------- | ||
1733 | void 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 | //----------------------------------------------------------------------------- | ||
1800 | void 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 | //----------------------------------------------------------------------------- | ||
1868 | void 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 | //----------------------------------------------------------------------------- | ||
1882 | void 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 | //----------------------------------------------------------------------------- | ||
1896 | void 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 | //----------------------------------------------------------------------------- | ||
1910 | void 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 | //----------------------------------------------------------------------------- | ||
1930 | U32 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 | //----------------------------------------------------------------------------- | ||
1949 | void LLAgent::setControlFlags(U32 mask) | ||
1950 | { | ||
1951 | mControlFlags |= mask; | ||
1952 | mbFlagsDirty = TRUE; | ||
1953 | } | ||
1954 | |||
1955 | |||
1956 | //----------------------------------------------------------------------------- | ||
1957 | // clearControlFlags() | ||
1958 | //----------------------------------------------------------------------------- | ||
1959 | void 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 | //----------------------------------------------------------------------------- | ||
1972 | BOOL LLAgent::controlFlagsDirty() const | ||
1973 | { | ||
1974 | return mbFlagsDirty; | ||
1975 | } | ||
1976 | |||
1977 | //----------------------------------------------------------------------------- | ||
1978 | // enableControlFlagReset() | ||
1979 | //----------------------------------------------------------------------------- | ||
1980 | void LLAgent::enableControlFlagReset() | ||
1981 | { | ||
1982 | mbFlagsNeedReset = TRUE; | ||
1983 | } | ||
1984 | |||
1985 | //----------------------------------------------------------------------------- | ||
1986 | // resetControlFlags() | ||
1987 | //----------------------------------------------------------------------------- | ||
1988 | void 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 | //----------------------------------------------------------------------------- | ||
2003 | void 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 | //----------------------------------------------------------------------------- | ||
2037 | void 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 | //----------------------------------------------------------------------------- | ||
2060 | BOOL LLAgent::getAFK() const | ||
2061 | { | ||
2062 | return (mControlFlags & AGENT_CONTROL_AWAY) != 0; | ||
2063 | } | ||
2064 | |||
2065 | //----------------------------------------------------------------------------- | ||
2066 | // setBusy() | ||
2067 | //----------------------------------------------------------------------------- | ||
2068 | void 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 | //----------------------------------------------------------------------------- | ||
2085 | void 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 | //----------------------------------------------------------------------------- | ||
2102 | BOOL LLAgent::getBusy() const | ||
2103 | { | ||
2104 | return mIsBusy; | ||
2105 | } | ||
2106 | |||
2107 | |||
2108 | //----------------------------------------------------------------------------- | ||
2109 | // updateWanderTarget() | ||
2110 | //----------------------------------------------------------------------------- | ||
2111 | void 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 | //----------------------------------------------------------------------------- | ||
2141 | void LLAgent::startAutoPilotGlobal(const LLVector3d &target_global, const std::string& behavior_name, const LLQuaternion *target_rotation, void (*finish_callback)(BOOL, void *), void *callback_data, F32 stop_distance, F32 rot_threshold) | ||
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 | //----------------------------------------------------------------------------- | ||
2228 | void 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 | //----------------------------------------------------------------------------- | ||
2249 | void 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 | //----------------------------------------------------------------------------- | ||
2291 | void 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 | //----------------------------------------------------------------------------- | ||
2448 | void 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 | //----------------------------------------------------------------------------- | ||
2500 | void 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 | //----------------------------------------------------------------------------- | ||
2518 | void 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 | |||
2586 | std::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 | //----------------------------------------------------------------------------- | ||
2605 | void 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 | //----------------------------------------------------------------------------- | ||
2641 | BOOL 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. | ||
2652 | BOOL LLAgent::needsRenderHead() | ||
2653 | { | ||
2654 | return mShowAvatar && !cameraMouselook(); | ||
2655 | } | ||
2656 | |||
2657 | //----------------------------------------------------------------------------- | ||
2658 | // startTyping() | ||
2659 | //----------------------------------------------------------------------------- | ||
2660 | void 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 | //----------------------------------------------------------------------------- | ||
2690 | void 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 | //----------------------------------------------------------------------------- | ||
2703 | void LLAgent::setRenderState(U8 newstate) | ||
2704 | { | ||
2705 | mRenderState |= newstate; | ||
2706 | } | ||
2707 | |||
2708 | //----------------------------------------------------------------------------- | ||
2709 | // clearRenderState() | ||
2710 | //----------------------------------------------------------------------------- | ||
2711 | void LLAgent::clearRenderState(U8 clearstate) | ||
2712 | { | ||
2713 | mRenderState &= ~clearstate; | ||
2714 | } | ||
2715 | |||
2716 | |||
2717 | //----------------------------------------------------------------------------- | ||
2718 | // getRenderState() | ||
2719 | //----------------------------------------------------------------------------- | ||
2720 | U8 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 | |||
2750 | static 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 | //----------------------------------------------------------------------------- | ||
2760 | void 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 | //----------------------------------------------------------------------------- | ||
2963 | void 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 | |||
3354 | void 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 | |||
3364 | void 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 | //----------------------------------------------------------------------------- | ||
3378 | F32 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 | //----------------------------------------------------------------------------- | ||
3410 | LLVector3d 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 | |||
3509 | void 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 | //----------------------------------------------------------------------------- | ||
3526 | const LLVector3 &LLAgent::getCameraPositionAgent() const | ||
3527 | { | ||
3528 | return gCamera->getOrigin(); | ||
3529 | } | ||
3530 | |||
3531 | //----------------------------------------------------------------------------- | ||
3532 | // getCameraPositionGlobal() | ||
3533 | //----------------------------------------------------------------------------- | ||
3534 | LLVector3d 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 | //----------------------------------------------------------------------------- | ||
3549 | F32 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 | //----------------------------------------------------------------------------- | ||
3582 | LLVector3d 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 | //----------------------------------------------------------------------------- | ||
3861 | void 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 | //----------------------------------------------------------------------------- | ||
3908 | F32 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 | //----------------------------------------------------------------------------- | ||
3931 | void 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 | //----------------------------------------------------------------------------- | ||
3947 | void 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 | //----------------------------------------------------------------------------- | ||
4004 | void 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 | //----------------------------------------------------------------------------- | ||
4021 | void 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 | //----------------------------------------------------------------------------- | ||
4085 | void 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 | //----------------------------------------------------------------------------- | ||
4172 | void 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 | //----------------------------------------------------------------------------- | ||
4247 | void 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 | //----------------------------------------------------------------------------- | ||
4259 | void LLAgent::stopCameraAnimation() | ||
4260 | { | ||
4261 | mCameraAnimating = FALSE; | ||
4262 | } | ||
4263 | |||
4264 | void LLAgent::clearFocusObject() | ||
4265 | { | ||
4266 | if (mFocusObject.notNull()) | ||
4267 | { | ||
4268 | startCameraAnimation(); | ||
4269 | |||
4270 | setFocusObject(NULL); | ||
4271 | mFocusObjectOffset.clearVec(); | ||
4272 | } | ||
4273 | } | ||
4274 | |||
4275 | void 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 | //----------------------------------------------------------------------------- | ||
4297 | void 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 | //----------------------------------------------------------------------------- | ||
4385 | void 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 | //----------------------------------------------------------------------------- | ||
4438 | void 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 | //----------------------------------------------------------------------------- | ||
4466 | void 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 | //----------------------------------------------------------------------------- | ||
4514 | void 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 | //----------------------------------------------------------------------------- | ||
4531 | void 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 | |||
4605 | const F32 SIT_POINT_EXTENTS = 0.2f; | ||
4606 | |||
4607 | // Grabs current position | ||
4608 | void 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 | |||
4671 | void 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 | |||
4698 | BOOL 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 | |||
4708 | U8 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 | |||
4719 | void LLAgent::buildFullname(std::string& name) const | ||
4720 | { | ||
4721 | if (mAvatarObject) | ||
4722 | { | ||
4723 | name = mAvatarObject->getFullname(); | ||
4724 | } | ||
4725 | } | ||
4726 | |||
4727 | void 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 | |||
4745 | BOOL 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 | ||
4759 | BOOL 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 | |||
4775 | BOOL LLAgent::hasPowerInActiveGroup(U64 power) const | ||
4776 | { | ||
4777 | return (mGroupID.notNull() && (hasPowerInGroup(mGroupID, power))); | ||
4778 | } | ||
4779 | |||
4780 | U64 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 | |||
4794 | BOOL 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 | |||
4808 | S32 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 | |||
4822 | BOOL 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 | |||
4845 | BOOL 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 | ||
4869 | void 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 | |||
4916 | LLQuaternion 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 | |||
4942 | void 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 | |||
4975 | void 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 | |||
4995 | void LLAgent::friendsChanged() | ||
4996 | { | ||
4997 | LLCollectProxyBuddies collector; | ||
4998 | LLAvatarTracker::instance().applyFunctor(collector); | ||
4999 | mProxyForAgents = collector.mProxy; | ||
5000 | } | ||
5001 | |||
5002 | BOOL LLAgent::isGrantedProxy(const LLPermissions& perm) | ||
5003 | { | ||
5004 | return (mProxyForAgents.count(perm.getOwner()) > 0); | ||
5005 | } | ||
5006 | |||
5007 | BOOL 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 | |||
5060 | void 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 | |||
5084 | const LLColor4 &LLAgent::getEffectColor() | ||
5085 | { | ||
5086 | return mEffectColor; | ||
5087 | } | ||
5088 | |||
5089 | void LLAgent::setEffectColor(const LLColor4 &color) | ||
5090 | { | ||
5091 | mEffectColor = color; | ||
5092 | } | ||
5093 | |||
5094 | void LLAgent::initOriginGlobal(const LLVector3d &origin_global) | ||
5095 | { | ||
5096 | mAgentOriginGlobal = origin_global; | ||
5097 | } | ||
5098 | |||
5099 | void 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 | ||
5126 | void 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 | ||
5171 | void 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 | ||
5218 | void 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 | ||
5254 | void 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 | ||
5325 | void 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 | ||
5358 | void 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 | ||
5392 | void 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 | |||
5448 | BOOL 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 | |||
5461 | BOOL LLAgent::isControlGrabbed(S32 control_index) const | ||
5462 | { | ||
5463 | return mControlsTakenCount[control_index] > 0; | ||
5464 | } | ||
5465 | |||
5466 | void 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 | |||
5475 | void LLAgent::setHomePosRegion( const U64& region_handle, const LLVector3& pos_region) | ||
5476 | { | ||
5477 | mHaveHomePosition = TRUE; | ||
5478 | mHomeRegionHandle = region_handle; | ||
5479 | mHomePosRegion = pos_region; | ||
5480 | } | ||
5481 | |||
5482 | BOOL 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 | |||
5495 | void 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 | ||
5511 | bool 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 | |||
5542 | void 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 | ||
5566 | void 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 | |||
5581 | void 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 | ||
5611 | void 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 | |||
5629 | void 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 | |||
5671 | void LLAgent::setTeleportState(ETeleportState state) | ||
5672 | { | ||
5673 | mTeleportState = state; | ||
5674 | if (mTeleportState > TELEPORT_NONE && gSavedSettings.getBOOL("FreezeTime")) | ||
5675 | { | ||
5676 | LLFloaterSnapshot::hide(0); | ||
5677 | } | ||
5678 | } | ||
5679 | |||
5680 | void 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 | |||
5727 | void 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 | |||
5739 | void 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 | |||
5755 | void 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 | ||
5772 | LLAgent::createStandardWearablesAllDoneCallback::~createStandardWearablesAllDoneCallback() | ||
5773 | { | ||
5774 | gAgent.createStandardWearablesAllDone(); | ||
5775 | } | ||
5776 | |||
5777 | LLAgent::sendAgentWearablesUpdateCallback::~sendAgentWearablesUpdateCallback() | ||
5778 | { | ||
5779 | gAgent.sendAgentWearablesUpdate(); | ||
5780 | } | ||
5781 | |||
5782 | LLAgent::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 | |||
5791 | void 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 | |||
5819 | void 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 | |||
5847 | void 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 | |||
5909 | void 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 | |||
5962 | void 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 | |||
6056 | void 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 | |||
6066 | void LLAgent::revertAllWearables() | ||
6067 | { | ||
6068 | for( S32 i=0; i < WT_COUNT; i++ ) | ||
6069 | { | ||
6070 | revertWearable( (EWearableType)i ); | ||
6071 | } | ||
6072 | } | ||
6073 | |||
6074 | void 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. | ||
6089 | void 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 | |||
6116 | BOOL 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 | |||
6131 | BOOL 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 | |||
6146 | U32 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 | |||
6160 | LLInventoryItem* 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 | |||
6171 | LLWearable* 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 | |||
6184 | void 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 | ||
6195 | BOOL LLAgent::selfHasWearable( void* userdata ) | ||
6196 | { | ||
6197 | EWearableType type = (EWearableType)(intptr_t)userdata; | ||
6198 | return gAgent.getWearable( type ) != NULL; | ||
6199 | } | ||
6200 | |||
6201 | BOOL LLAgent::isWearingItem( const LLUUID& item_id ) | ||
6202 | { | ||
6203 | return (getWearableFromWearableItem( item_id ) != NULL); | ||
6204 | } | ||
6205 | |||
6206 | |||
6207 | // static | ||
6208 | void 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 | ||
6305 | void 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.) | ||
6367 | void 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 | |||
6392 | void 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 | |||
6417 | void 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 | } | ||
6472 | void LLAgent::createStandardWearablesDone(S32 index) | ||
6473 | { | ||
6474 | LLWearable* wearable = mWearableEntry[index].mWearable; | ||
6475 | |||
6476 | if (wearable) | ||
6477 | { | ||
6478 | wearable->writeToAvatar(TRUE); | ||
6479 | } | ||
6480 | } | ||
6481 | |||
6482 | void 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 | |||
6494 | void 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 | |||
6625 | void 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 | |||
6640 | void 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 | //----------------------------------------------------------------------------- | ||
6663 | void 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 | |||
6778 | void 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 | |||
6787 | void 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 | ||
6814 | void 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. | ||
6838 | void 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 | |||
6860 | void 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(). | ||
6891 | struct 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 | |||
6899 | BOOL 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. | ||
6908 | void 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. | ||
7015 | void 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 | ||
7043 | void 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. | ||
7076 | void 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 | |||
7101 | void 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 | ||
7160 | void 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 | |||
7171 | void 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 | |||
7184 | void 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 | |||
7200 | void 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 | |||
7229 | bool LLAgent::LLHideGroupTitleListener::handleEvent(LLPointer<LLEvent> event, const LLSD &userdata) | ||
7230 | { | ||
7231 | gAgent.setHideGroupTitle(event->getValue()); | ||
7232 | return true; | ||
7233 | |||
7234 | } | ||
7235 | |||
7236 | bool LLAgent::LLEffectColorListener::handleEvent(LLPointer<LLEvent> event, const LLSD &userdata) | ||
7237 | { | ||
7238 | gAgent.setEffectColor(LLColor4(event->getValue())); | ||
7239 | return true; | ||
7240 | } | ||
7241 | |||
7242 | void LLAgent::observeFriends() | ||
7243 | { | ||
7244 | if(!mFriendObserver) | ||
7245 | { | ||
7246 | mFriendObserver = new LLAgentFriendObserver; | ||
7247 | LLAvatarTracker::instance().addObserver(mFriendObserver); | ||
7248 | friendsChanged(); | ||
7249 | } | ||
7250 | } | ||
7251 | |||
7252 | // EOF | ||