aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/newview/llhudeffectlookat.cpp
diff options
context:
space:
mode:
authorJacek Antonelli2008-08-15 23:44:46 -0500
committerJacek Antonelli2008-08-15 23:44:46 -0500
commit38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch)
treeadca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/newview/llhudeffectlookat.cpp
parentREADME.txt (diff)
downloadmeta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.zip
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.gz
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.bz2
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.xz
Second Life viewer sources 1.13.2.12
Diffstat (limited to 'linden/indra/newview/llhudeffectlookat.cpp')
-rw-r--r--linden/indra/newview/llhudeffectlookat.cpp522
1 files changed, 522 insertions, 0 deletions
diff --git a/linden/indra/newview/llhudeffectlookat.cpp b/linden/indra/newview/llhudeffectlookat.cpp
new file mode 100644
index 0000000..99ae239
--- /dev/null
+++ b/linden/indra/newview/llhudeffectlookat.cpp
@@ -0,0 +1,522 @@
1/**
2 * @file llhudeffectlookat.cpp
3 * @brief LLHUDEffectLookAt class implementation
4 *
5 * Copyright (c) 2002-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 "llhudeffectlookat.h"
31
32#include "message.h"
33#include "llagent.h"
34#include "llvoavatar.h"
35#include "lldrawable.h"
36#include "llviewerobjectlist.h"
37#include "llsphere.h"
38#include "llselectmgr.h"
39#include "llglheaders.h"
40
41BOOL LLHUDEffectLookAt::sDebugLookAt = FALSE;
42
43// packet layout
44const S32 SOURCE_AVATAR = 0;
45const S32 TARGET_OBJECT = 16;
46const S32 TARGET_POS = 32;
47const S32 LOOKAT_TYPE = 56;
48const S32 PKT_SIZE = 57;
49
50// throttle
51const F32 MAX_SENDS_PER_SEC = 4.f;
52
53const F32 MIN_DELTAPOS_FOR_UPDATE = 0.05f;
54const F32 MIN_TARGET_OFFSET_SQUARED = 0.0001f;
55
56// timeouts
57// can't use actual F32_MAX, because we add this to the current frametime
58const F32 MAX_TIMEOUT = F32_MAX / 2.f;
59
60const F32 LOOKAT_TIMEOUTS[LOOKAT_NUM_TARGETS] =
61{
62 MAX_TIMEOUT, //LOOKAT_TARGET_NONE
63 3.f, //LOOKAT_TARGET_IDLE
64 4.f, //LOOKAT_TARGET_AUTO_LISTEN
65 2.f, //LOOKAT_TARGET_FREELOOK
66 4.f, //LOOKAT_TARGET_RESPOND
67 1.f, //LOOKAT_TARGET_HOVER
68 MAX_TIMEOUT, //LOOKAT_TARGET_CONVERSATION
69 MAX_TIMEOUT, //LOOKAT_TARGET_SELECT
70 MAX_TIMEOUT, //LOOKAT_TARGET_FOCUS
71 MAX_TIMEOUT, //LOOKAT_TARGET_MOUSELOOK
72 0.f, //LOOKAT_TARGET_CLEAR
73};
74
75const S32 LOOKAT_PRIORITIES[LOOKAT_NUM_TARGETS] =
76{
77 0, //LOOKAT_TARGET_NONE
78 1, //LOOKAT_TARGET_IDLE
79 3, //LOOKAT_TARGET_AUTO_LISTEN
80 2, //LOOKAT_TARGET_FREELOOK
81 3, //LOOKAT_TARGET_RESPOND
82 4, //LOOKAT_TARGET_HOVER
83 5, //LOOKAT_TARGET_CONVERSATION
84 6, //LOOKAT_TARGET_SELECT
85 6, //LOOKAT_TARGET_FOCUS
86 7, //LOOKAT_TARGET_MOUSELOOK
87 8, //LOOKAT_TARGET_CLEAR
88};
89
90const char *LOOKAT_STRINGS[] =
91{
92 "None", //LOOKAT_TARGET_NONE
93 "Idle", //LOOKAT_TARGET_IDLE
94 "AutoListen", //LOOKAT_TARGET_AUTO_LISTEN
95 "FreeLook", //LOOKAT_TARGET_FREELOOK
96 "Respond", //LOOKAT_TARGET_RESPOND
97 "Hover", //LOOKAT_TARGET_HOVER
98 "Conversation", //LOOKAT_TARGET_CONVERSATION
99 "Select", //LOOKAT_TARGET_SELECT
100 "Focus", //LOOKAT_TARGET_FOCUS
101 "Mouselook", //LOOKAT_TARGET_MOUSELOOK
102 "Clear", //LOOKAT_TARGET_CLEAR
103};
104
105const LLColor3 LOOKAT_COLORS[LOOKAT_NUM_TARGETS] =
106{
107 LLColor3(0.3f, 0.3f, 0.3f), //LOOKAT_TARGET_NONE
108 LLColor3(0.5f, 0.5f, 0.5f), //LOOKAT_TARGET_IDLE
109 LLColor3(0.5f, 0.5f, 0.5f), //LOOKAT_TARGET_AUTO_LISTEN
110 LLColor3(0.5f, 0.5f, 0.9f), //LOOKAT_TARGET_FREELOOK
111 LLColor3(0.f, 0.f, 0.f), //LOOKAT_TARGET_RESPOND
112 LLColor3(0.5f, 0.9f, 0.5f), //LOOKAT_TARGET_HOVER
113 LLColor3(0.1f, 0.1f, 0.5f), //LOOKAT_TARGET_CONVERSATION
114 LLColor3(0.9f, 0.5f, 0.5f), //LOOKAT_TARGET_SELECT
115 LLColor3(0.9f, 0.5f, 0.9f), //LOOKAT_TARGET_FOCUS
116 LLColor3(0.9f, 0.9f, 0.5f), //LOOKAT_TARGET_MOUSELOOK
117 LLColor3(1.f, 1.f, 1.f), //LOOKAT_TARGET_CLEAR
118};
119
120//-----------------------------------------------------------------------------
121// LLHUDEffectLookAt()
122//-----------------------------------------------------------------------------
123LLHUDEffectLookAt::LLHUDEffectLookAt(const U8 type) :
124 LLHUDEffect(type),
125 mKillTime(0.f),
126 mLastSendTime(0.f)
127{
128 clearLookAtTarget();
129}
130
131//-----------------------------------------------------------------------------
132// ~LLHUDEffectLookAt()
133//-----------------------------------------------------------------------------
134LLHUDEffectLookAt::~LLHUDEffectLookAt()
135{
136}
137
138//-----------------------------------------------------------------------------
139// packData()
140//-----------------------------------------------------------------------------
141void LLHUDEffectLookAt::packData(LLMessageSystem *mesgsys)
142{
143 // Pack the default data
144 LLHUDEffect::packData(mesgsys);
145
146 // Pack the type-specific data. Uses a fun packed binary format. Whee!
147 U8 packed_data[PKT_SIZE];
148 memset(packed_data, 0, PKT_SIZE);
149
150 if (mSourceObject)
151 {
152 htonmemcpy(&(packed_data[SOURCE_AVATAR]), mSourceObject->mID.mData, MVT_LLUUID, 16);
153 }
154 else
155 {
156 htonmemcpy(&(packed_data[SOURCE_AVATAR]), LLUUID::null.mData, MVT_LLUUID, 16);
157 }
158
159 // pack both target object and position
160 // position interpreted as offset if target object is non-null
161 if (mTargetObject)
162 {
163 htonmemcpy(&(packed_data[TARGET_OBJECT]), mTargetObject->mID.mData, MVT_LLUUID, 16);
164 }
165 else
166 {
167 htonmemcpy(&(packed_data[TARGET_OBJECT]), LLUUID::null.mData, MVT_LLUUID, 16);
168 }
169
170 htonmemcpy(&(packed_data[TARGET_POS]), mTargetOffsetGlobal.mdV, MVT_LLVector3d, 24);
171
172 U8 lookAtTypePacked = (U8)mTargetType;
173
174 htonmemcpy(&(packed_data[LOOKAT_TYPE]), &lookAtTypePacked, MVT_U8, 1);
175
176 mesgsys->addBinaryDataFast(_PREHASH_TypeData, packed_data, PKT_SIZE);
177
178 mLastSendTime = mTimer.getElapsedTimeF32();
179}
180
181//-----------------------------------------------------------------------------
182// unpackData()
183//-----------------------------------------------------------------------------
184void LLHUDEffectLookAt::unpackData(LLMessageSystem *mesgsys, S32 blocknum)
185{
186 LLVector3d new_target;
187 U8 packed_data[PKT_SIZE];
188
189 LLUUID dataId;
190 mesgsys->getUUIDFast(_PREHASH_Effect, _PREHASH_ID, dataId, blocknum);
191
192 if (!gAgent.mLookAt.isNull() && dataId == gAgent.mLookAt->getID())
193 {
194 return;
195 }
196
197 LLHUDEffect::unpackData(mesgsys, blocknum);
198 LLUUID source_id;
199 LLUUID target_id;
200 S32 size = mesgsys->getSizeFast(_PREHASH_Effect, blocknum, _PREHASH_TypeData);
201 if (size != PKT_SIZE)
202 {
203 llwarns << "LookAt effect with bad size " << size << llendl;
204 return;
205 }
206 mesgsys->getBinaryDataFast(_PREHASH_Effect, _PREHASH_TypeData, packed_data, PKT_SIZE, blocknum);
207
208 htonmemcpy(source_id.mData, &(packed_data[SOURCE_AVATAR]), MVT_LLUUID, 16);
209
210 LLViewerObject *objp = gObjectList.findObject(source_id);
211 if (objp && objp->isAvatar())
212 {
213 setSourceObject(objp);
214 }
215 else
216 {
217 //llwarns << "Could not find source avatar for lookat effect" << llendl;
218 return;
219 }
220
221 htonmemcpy(target_id.mData, &(packed_data[TARGET_OBJECT]), MVT_LLUUID, 16);
222
223 objp = gObjectList.findObject(target_id);
224
225 htonmemcpy(new_target.mdV, &(packed_data[TARGET_POS]), MVT_LLVector3d, 24);
226
227 if (objp)
228 {
229 setTargetObjectAndOffset(objp, new_target);
230 }
231 else if (target_id.isNull())
232 {
233 setTargetPosGlobal(new_target);
234 }
235 else
236 {
237 //llwarns << "Could not find target object for lookat effect" << llendl;
238 }
239
240 U8 lookAtTypeUnpacked = 0;
241 htonmemcpy(&lookAtTypeUnpacked, &(packed_data[LOOKAT_TYPE]), MVT_U8, 1);
242 mTargetType = (ELookAtType)lookAtTypeUnpacked;
243
244 if (mTargetType == LOOKAT_TARGET_NONE)
245 {
246 clearLookAtTarget();
247 }
248}
249
250//-----------------------------------------------------------------------------
251// setTargetObjectAndOffset()
252//-----------------------------------------------------------------------------
253void LLHUDEffectLookAt::setTargetObjectAndOffset(LLViewerObject *objp, LLVector3d offset)
254{
255 mTargetObject = objp;
256 mTargetOffsetGlobal = offset;
257}
258
259//-----------------------------------------------------------------------------
260// setTargetPosGlobal()
261//-----------------------------------------------------------------------------
262void LLHUDEffectLookAt::setTargetPosGlobal(const LLVector3d &target_pos_global)
263{
264 mTargetObject = NULL;
265 mTargetOffsetGlobal = target_pos_global;
266}
267
268//-----------------------------------------------------------------------------
269// setLookAt()
270// called by agent logic to set look at behavior locally, and propagate to sim
271//-----------------------------------------------------------------------------
272BOOL LLHUDEffectLookAt::setLookAt(ELookAtType target_type, LLViewerObject *object, LLVector3 position)
273{
274 if (!mSourceObject)
275 {
276 return FALSE;
277 }
278
279 llassert(target_type < LOOKAT_NUM_TARGETS);
280
281 // must be same or higher priority than existing effect
282 if (LOOKAT_PRIORITIES[target_type] < LOOKAT_PRIORITIES[mTargetType])
283 {
284 return FALSE;
285 }
286
287 F32 current_time = mTimer.getElapsedTimeF32();
288
289 // type of lookat behavior or target object has changed
290 BOOL lookAtChanged = (target_type != mTargetType) ||
291 (object != mTargetObject);
292
293 // lookat position has moved a certain amount and we haven't just sent an update
294 lookAtChanged = lookAtChanged || (dist_vec(position, mLastSentOffsetGlobal) > MIN_DELTAPOS_FOR_UPDATE) &&
295 ((current_time - mLastSendTime) > (1.f / MAX_SENDS_PER_SEC));
296
297 if (lookAtChanged)
298 {
299 mLastSentOffsetGlobal = position;
300 setDuration(LOOKAT_TIMEOUTS[target_type]);
301 setNeedsSendToSim(TRUE);
302 }
303
304 if (target_type == LOOKAT_TARGET_CLEAR)
305 {
306 clearLookAtTarget();
307 }
308 else
309 {
310 mTargetType = target_type;
311 mTargetObject = object;
312 if (object)
313 {
314 mTargetOffsetGlobal.setVec(position);
315 }
316 else
317 {
318 mTargetOffsetGlobal = gAgent.getPosGlobalFromAgent(position);
319 }
320 mKillTime = mTimer.getElapsedTimeF32() + mDuration;
321
322 update();
323 }
324 return TRUE;
325}
326
327//-----------------------------------------------------------------------------
328// clearLookAtTarget()
329//-----------------------------------------------------------------------------
330void LLHUDEffectLookAt::clearLookAtTarget()
331{
332 mTargetObject = NULL;
333 mTargetOffsetGlobal.clearVec();
334 mTargetType = LOOKAT_TARGET_NONE;
335 if (mSourceObject.notNull())
336 {
337 ((LLVOAvatar*)(LLViewerObject*)mSourceObject)->stopMotion(ANIM_AGENT_HEAD_ROT);
338 }
339}
340
341//-----------------------------------------------------------------------------
342// markDead()
343//-----------------------------------------------------------------------------
344void LLHUDEffectLookAt::markDead()
345{
346 if (mSourceObject.notNull())
347 {
348 ((LLVOAvatar*)(LLViewerObject*)mSourceObject)->removeAnimationData("LookAtPoint");
349 }
350
351 mSourceObject = NULL;
352 clearLookAtTarget();
353 LLHUDEffect::markDead();
354}
355
356void LLHUDEffectLookAt::setSourceObject(LLViewerObject* objectp)
357{
358 // restrict source objects to avatars
359 if (objectp && objectp->isAvatar())
360 {
361 LLHUDEffect::setSourceObject(objectp);
362 }
363}
364
365//-----------------------------------------------------------------------------
366// render()
367//-----------------------------------------------------------------------------
368void LLHUDEffectLookAt::render()
369{
370 if (sDebugLookAt && mSourceObject.notNull())
371 {
372 LLGLSNoTexture gls_no_texture;
373
374 LLVector3 target = mTargetPos + ((LLVOAvatar*)(LLViewerObject*)mSourceObject)->mHeadp->getWorldPosition();
375 glMatrixMode(GL_MODELVIEW);
376 glPushMatrix();
377 glTranslatef(target.mV[VX], target.mV[VY], target.mV[VZ]);
378 glScalef(0.3f, 0.3f, 0.3f);
379 glBegin(GL_LINES);
380 {
381 LLColor3 color = LOOKAT_COLORS[mTargetType];
382 glColor3f(color.mV[VRED], color.mV[VGREEN], color.mV[VBLUE]);
383 glVertex3f(-1.f, 0.f, 0.f);
384 glVertex3f(1.f, 0.f, 0.f);
385
386 glVertex3f(0.f, -1.f, 0.f);
387 glVertex3f(0.f, 1.f, 0.f);
388
389 glVertex3f(0.f, 0.f, -1.f);
390 glVertex3f(0.f, 0.f, 1.f);
391 } glEnd();
392 glPopMatrix();
393 }
394}
395
396//-----------------------------------------------------------------------------
397// update()
398//-----------------------------------------------------------------------------
399void LLHUDEffectLookAt::update()
400{
401 // If the target object is dead, set the target object to NULL
402 if (!mTargetObject.isNull() && mTargetObject->isDead())
403 {
404 clearLookAtTarget();
405 }
406
407 // if source avatar is null or dead, mark self as dead and return
408 if (mSourceObject.isNull() || mSourceObject->isDead())
409 {
410 markDead();
411 return;
412 }
413
414 F32 time = mTimer.getElapsedTimeF32();
415
416 // clear out the effect if time is up
417 if (mKillTime != 0.f && time > mKillTime)
418 {
419 if (mTargetType != LOOKAT_TARGET_NONE)
420 {
421 clearLookAtTarget();
422 // look at timed out (only happens on own avatar), so tell everyone
423 setNeedsSendToSim(TRUE);
424 }
425 }
426
427 if (mTargetType != LOOKAT_TARGET_NONE)
428 {
429 calcTargetPosition();
430
431 LLMotion* head_motion = ((LLVOAvatar*)(LLViewerObject*)mSourceObject)->findMotion(ANIM_AGENT_HEAD_ROT);
432 if (!head_motion || head_motion->isStopped())
433 {
434 ((LLVOAvatar*)(LLViewerObject*)mSourceObject)->startMotion(ANIM_AGENT_HEAD_ROT);
435 }
436 }
437
438 if (sDebugLookAt)
439 {
440 ((LLVOAvatar*)(LLViewerObject*)mSourceObject)->addDebugText(LOOKAT_STRINGS[mTargetType]);
441 }
442}
443
444void LLHUDEffectLookAt::calcTargetPosition()
445{
446 LLViewerObject *targetObject = (LLViewerObject *)mTargetObject;
447 LLVector3 local_offset;
448
449 if (targetObject)
450 {
451 local_offset.setVec(mTargetOffsetGlobal);
452 }
453 else
454 {
455 local_offset = gAgent.getPosAgentFromGlobal(mTargetOffsetGlobal);
456 }
457
458 if (gNoRender)
459 {
460 return;
461 }
462 LLVector3 head_position = ((LLVOAvatar*)(LLViewerObject*)mSourceObject)->mHeadp->getWorldPosition();
463
464 if (targetObject && targetObject->mDrawable.notNull())
465 {
466 LLQuaternion objRot;
467 if (targetObject->isAvatar())
468 {
469 LLVOAvatar *avatarp = (LLVOAvatar *)targetObject;
470
471 BOOL looking_at_self = ((LLVOAvatar*)(LLViewerObject*)mSourceObject)->isSelf() && avatarp->isSelf();
472
473 // if selecting self, stare forward
474 if (looking_at_self && mTargetOffsetGlobal.magVecSquared() < MIN_TARGET_OFFSET_SQUARED)
475 {
476 //sets the lookat point in front of the avatar
477 mTargetOffsetGlobal.setVec(5.0, 0.0, 0.0);
478 }
479
480 mTargetPos = avatarp->mHeadp->getWorldPosition();
481 if (mTargetType == LOOKAT_TARGET_MOUSELOOK || mTargetType == LOOKAT_TARGET_FREELOOK)
482 {
483 // mouselook and freelook target offsets are absolute
484 objRot = LLQuaternion::DEFAULT;
485 }
486 else if (looking_at_self && gAgent.cameraCustomizeAvatar())
487 {
488 // *NOTE: We have to do this because animation
489 // overrides do not set lookat behavior.
490 // *TODO: animation overrides for lookat behavior.
491 objRot = avatarp->mPelvisp->getWorldRotation();
492 }
493 else
494 {
495 objRot = avatarp->mRoot.getWorldRotation();
496 }
497 }
498 else
499 {
500 if (targetObject->mDrawable->getGeneration() == -1)
501 {
502 mTargetPos = targetObject->getPositionAgent();
503 objRot = targetObject->getWorldRotation();
504 }
505 else
506 {
507 mTargetPos = targetObject->getRenderPosition();
508 objRot = targetObject->getRenderRotation();
509 }
510 }
511
512 mTargetPos += (local_offset * objRot);
513 }
514 else
515 {
516 mTargetPos = local_offset;
517 }
518
519 mTargetPos -= head_position;
520
521 ((LLVOAvatar*)(LLViewerObject*)mSourceObject)->setAnimationData("LookAtPoint", (void *)&mTargetPos);
522}