/indra/newview/llhudeffectlookat.cpp

https://bitbucket.org/lindenlab/viewer-beta/ · C++ · 671 lines · 463 code · 90 blank · 118 comment · 109 complexity · 058b700f5f821c053c24ae1d45bcec6b MD5 · raw file

  1. /**
  2. * @file llhudeffectlookat.cpp
  3. * @brief LLHUDEffectLookAt class implementation
  4. *
  5. * $LicenseInfo:firstyear=2002&license=viewerlgpl$
  6. * Second Life Viewer Source Code
  7. * Copyright (C) 2010, Linden Research, Inc.
  8. *
  9. * This library is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU Lesser General Public
  11. * License as published by the Free Software Foundation;
  12. * version 2.1 of the License only.
  13. *
  14. * This library is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public
  20. * License along with this library; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  22. *
  23. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  24. * $/LicenseInfo$
  25. */
  26. #include "llviewerprecompiledheaders.h"
  27. #include "llhudeffectlookat.h"
  28. #include "llrender.h"
  29. #include "message.h"
  30. #include "llagent.h"
  31. #include "llagentcamera.h"
  32. #include "llvoavatar.h"
  33. #include "lldrawable.h"
  34. #include "llviewerobjectlist.h"
  35. #include "llrendersphere.h"
  36. #include "llselectmgr.h"
  37. #include "llglheaders.h"
  38. #include "llxmltree.h"
  39. BOOL LLHUDEffectLookAt::sDebugLookAt = FALSE;
  40. // packet layout
  41. const S32 SOURCE_AVATAR = 0;
  42. const S32 TARGET_OBJECT = 16;
  43. const S32 TARGET_POS = 32;
  44. const S32 LOOKAT_TYPE = 56;
  45. const S32 PKT_SIZE = 57;
  46. // throttle
  47. const F32 MAX_SENDS_PER_SEC = 4.f;
  48. const F32 MIN_DELTAPOS_FOR_UPDATE_SQUARED = 0.05f * 0.05f;
  49. const F32 MIN_TARGET_OFFSET_SQUARED = 0.0001f;
  50. // can't use actual F32_MAX, because we add this to the current frametime
  51. const F32 MAX_TIMEOUT = F32_MAX / 2.f;
  52. /**
  53. * Simple data class holding values for a particular type of attention.
  54. */
  55. class LLAttention
  56. {
  57. public:
  58. LLAttention()
  59. : mTimeout(0.f),
  60. mPriority(0.f)
  61. {}
  62. LLAttention(F32 timeout, F32 priority, const std::string& name, LLColor3 color) :
  63. mTimeout(timeout), mPriority(priority), mName(name), mColor(color)
  64. {
  65. }
  66. F32 mTimeout, mPriority;
  67. std::string mName;
  68. LLColor3 mColor;
  69. };
  70. /**
  71. * Simple data class holding a list of attentions, one for every type.
  72. */
  73. class LLAttentionSet
  74. {
  75. public:
  76. LLAttentionSet(const LLAttention attentions[])
  77. {
  78. for(int i=0; i<LOOKAT_NUM_TARGETS; i++)
  79. {
  80. mAttentions[i] = attentions[i];
  81. }
  82. }
  83. LLAttention mAttentions[LOOKAT_NUM_TARGETS];
  84. LLAttention& operator[](int idx) { return mAttentions[idx]; }
  85. };
  86. // Default attribute set data.
  87. // Used to initialize the global attribute set objects, one of which will be
  88. // refered to by the hud object at any given time.
  89. // Note that the values below are only the default values and that any or all of them
  90. // can be overwritten with customizing data from the XML file. The actual values below
  91. // are those that will give exactly the same look-at behavior as before the ability
  92. // to customize was added. - MG
  93. static const
  94. LLAttention
  95. BOY_ATTS[] = { // default set of masculine attentions
  96. LLAttention(MAX_TIMEOUT, 0, "None", LLColor3(0.3f, 0.3f, 0.3f)), // LOOKAT_TARGET_NONE
  97. LLAttention(3.f, 1, "Idle", LLColor3(0.5f, 0.5f, 0.5f)), // LOOKAT_TARGET_IDLE
  98. LLAttention(4.f, 3, "AutoListen", LLColor3(0.5f, 0.5f, 0.5f)), // LOOKAT_TARGET_AUTO_LISTEN
  99. LLAttention(2.f, 2, "FreeLook", LLColor3(0.5f, 0.5f, 0.9f)), // LOOKAT_TARGET_FREELOOK
  100. LLAttention(4.f, 3, "Respond", LLColor3(0.0f, 0.0f, 0.0f)), // LOOKAT_TARGET_RESPOND
  101. LLAttention(1.f, 4, "Hover", LLColor3(0.5f, 0.9f, 0.5f)), // LOOKAT_TARGET_HOVER
  102. LLAttention(MAX_TIMEOUT, 0, "Conversation", LLColor3(0.1f, 0.1f, 0.5f)), // LOOKAT_TARGET_CONVERSATION
  103. LLAttention(MAX_TIMEOUT, 6, "Select", LLColor3(0.9f, 0.5f, 0.5f)), // LOOKAT_TARGET_SELECT
  104. LLAttention(MAX_TIMEOUT, 6, "Focus", LLColor3(0.9f, 0.5f, 0.9f)), // LOOKAT_TARGET_FOCUS
  105. LLAttention(MAX_TIMEOUT, 7, "Mouselook", LLColor3(0.9f, 0.9f, 0.5f)), // LOOKAT_TARGET_MOUSELOOK
  106. LLAttention(0.f, 8, "Clear", LLColor3(1.0f, 1.0f, 1.0f)), // LOOKAT_TARGET_CLEAR
  107. },
  108. GIRL_ATTS[] = { // default set of feminine attentions
  109. LLAttention(MAX_TIMEOUT, 0, "None", LLColor3(0.3f, 0.3f, 0.3f)), // LOOKAT_TARGET_NONE
  110. LLAttention(3.f, 1, "Idle", LLColor3(0.5f, 0.5f, 0.5f)), // LOOKAT_TARGET_IDLE
  111. LLAttention(4.f, 3, "AutoListen", LLColor3(0.5f, 0.5f, 0.5f)), // LOOKAT_TARGET_AUTO_LISTEN
  112. LLAttention(2.f, 2, "FreeLook", LLColor3(0.5f, 0.5f, 0.9f)), // LOOKAT_TARGET_FREELOOK
  113. LLAttention(4.f, 3, "Respond", LLColor3(0.0f, 0.0f, 0.0f)), // LOOKAT_TARGET_RESPOND
  114. LLAttention(1.f, 4, "Hover", LLColor3(0.5f, 0.9f, 0.5f)), // LOOKAT_TARGET_HOVER
  115. LLAttention(MAX_TIMEOUT, 0, "Conversation", LLColor3(0.1f, 0.1f, 0.5f)), // LOOKAT_TARGET_CONVERSATION
  116. LLAttention(MAX_TIMEOUT, 6, "Select", LLColor3(0.9f, 0.5f, 0.5f)), // LOOKAT_TARGET_SELECT
  117. LLAttention(MAX_TIMEOUT, 6, "Focus", LLColor3(0.9f, 0.5f, 0.9f)), // LOOKAT_TARGET_FOCUS
  118. LLAttention(MAX_TIMEOUT, 7, "Mouselook", LLColor3(0.9f, 0.9f, 0.5f)), // LOOKAT_TARGET_MOUSELOOK
  119. LLAttention(0.f, 8, "Clear", LLColor3(1.0f, 1.0f, 1.0f)), // LOOKAT_TARGET_CLEAR
  120. };
  121. static LLAttentionSet
  122. gBoyAttentions(BOY_ATTS),
  123. gGirlAttentions(GIRL_ATTS);
  124. static BOOL loadGender(LLXmlTreeNode* gender)
  125. {
  126. if( !gender)
  127. {
  128. return FALSE;
  129. }
  130. std::string str;
  131. gender->getAttributeString("name", str);
  132. LLAttentionSet& attentions = (str.compare("Masculine") == 0) ? gBoyAttentions : gGirlAttentions;
  133. for (LLXmlTreeNode* attention_node = gender->getChildByName( "param" );
  134. attention_node;
  135. attention_node = gender->getNextNamedChild())
  136. {
  137. attention_node->getAttributeString("attention", str);
  138. LLAttention* attention;
  139. if (str == "idle") attention = &attentions[LOOKAT_TARGET_IDLE];
  140. else if(str == "auto_listen") attention = &attentions[LOOKAT_TARGET_AUTO_LISTEN];
  141. else if(str == "freelook") attention = &attentions[LOOKAT_TARGET_FREELOOK];
  142. else if(str == "respond") attention = &attentions[LOOKAT_TARGET_RESPOND];
  143. else if(str == "hover") attention = &attentions[LOOKAT_TARGET_HOVER];
  144. else if(str == "conversation") attention = &attentions[LOOKAT_TARGET_CONVERSATION];
  145. else if(str == "select") attention = &attentions[LOOKAT_TARGET_SELECT];
  146. else if(str == "focus") attention = &attentions[LOOKAT_TARGET_FOCUS];
  147. else if(str == "mouselook") attention = &attentions[LOOKAT_TARGET_MOUSELOOK];
  148. else return FALSE;
  149. F32 priority, timeout;
  150. attention_node->getAttributeF32("priority", priority);
  151. attention_node->getAttributeF32("timeout", timeout);
  152. if(timeout < 0) timeout = MAX_TIMEOUT;
  153. attention->mPriority = priority;
  154. attention->mTimeout = timeout;
  155. }
  156. return TRUE;
  157. }
  158. static BOOL loadAttentions()
  159. {
  160. static BOOL first_time = TRUE;
  161. if( ! first_time)
  162. {
  163. return TRUE; // maybe not ideal but otherwise it can continue to fail forever.
  164. }
  165. first_time = FALSE;
  166. std::string filename;
  167. filename = gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,"attentions.xml");
  168. LLXmlTree xml_tree;
  169. BOOL success = xml_tree.parseFile( filename, FALSE );
  170. if( !success )
  171. {
  172. return FALSE;
  173. }
  174. LLXmlTreeNode* root = xml_tree.getRoot();
  175. if( !root )
  176. {
  177. return FALSE;
  178. }
  179. //-------------------------------------------------------------------------
  180. // <linden_attentions version="1.0"> (root)
  181. //-------------------------------------------------------------------------
  182. if( !root->hasName( "linden_attentions" ) )
  183. {
  184. llwarns << "Invalid linden_attentions file header: " << filename << llendl;
  185. return FALSE;
  186. }
  187. std::string version;
  188. static LLStdStringHandle version_string = LLXmlTree::addAttributeString("version");
  189. if( !root->getFastAttributeString( version_string, version ) || (version != "1.0") )
  190. {
  191. llwarns << "Invalid linden_attentions file version: " << version << llendl;
  192. return FALSE;
  193. }
  194. //-------------------------------------------------------------------------
  195. // <gender>
  196. //-------------------------------------------------------------------------
  197. for (LLXmlTreeNode* child = root->getChildByName( "gender" );
  198. child;
  199. child = root->getNextNamedChild())
  200. {
  201. if( !loadGender( child ) )
  202. {
  203. return FALSE;
  204. }
  205. }
  206. return TRUE;
  207. }
  208. //-----------------------------------------------------------------------------
  209. // LLHUDEffectLookAt()
  210. //-----------------------------------------------------------------------------
  211. LLHUDEffectLookAt::LLHUDEffectLookAt(const U8 type) :
  212. LLHUDEffect(type),
  213. mKillTime(0.f),
  214. mLastSendTime(0.f)
  215. {
  216. clearLookAtTarget();
  217. // parse the default sets
  218. loadAttentions();
  219. // initialize current attention set. switches when avatar sex changes.
  220. mAttentions = &gGirlAttentions;
  221. }
  222. //-----------------------------------------------------------------------------
  223. // ~LLHUDEffectLookAt()
  224. //-----------------------------------------------------------------------------
  225. LLHUDEffectLookAt::~LLHUDEffectLookAt()
  226. {
  227. }
  228. //-----------------------------------------------------------------------------
  229. // packData()
  230. //-----------------------------------------------------------------------------
  231. void LLHUDEffectLookAt::packData(LLMessageSystem *mesgsys)
  232. {
  233. // Pack the default data
  234. LLHUDEffect::packData(mesgsys);
  235. // Pack the type-specific data. Uses a fun packed binary format. Whee!
  236. U8 packed_data[PKT_SIZE];
  237. memset(packed_data, 0, PKT_SIZE);
  238. if (mSourceObject)
  239. {
  240. htonmemcpy(&(packed_data[SOURCE_AVATAR]), mSourceObject->mID.mData, MVT_LLUUID, 16);
  241. }
  242. else
  243. {
  244. htonmemcpy(&(packed_data[SOURCE_AVATAR]), LLUUID::null.mData, MVT_LLUUID, 16);
  245. }
  246. // pack both target object and position
  247. // position interpreted as offset if target object is non-null
  248. if (mTargetObject)
  249. {
  250. htonmemcpy(&(packed_data[TARGET_OBJECT]), mTargetObject->mID.mData, MVT_LLUUID, 16);
  251. }
  252. else
  253. {
  254. htonmemcpy(&(packed_data[TARGET_OBJECT]), LLUUID::null.mData, MVT_LLUUID, 16);
  255. }
  256. htonmemcpy(&(packed_data[TARGET_POS]), mTargetOffsetGlobal.mdV, MVT_LLVector3d, 24);
  257. U8 lookAtTypePacked = (U8)mTargetType;
  258. htonmemcpy(&(packed_data[LOOKAT_TYPE]), &lookAtTypePacked, MVT_U8, 1);
  259. mesgsys->addBinaryDataFast(_PREHASH_TypeData, packed_data, PKT_SIZE);
  260. mLastSendTime = mTimer.getElapsedTimeF32();
  261. }
  262. //-----------------------------------------------------------------------------
  263. // unpackData()
  264. //-----------------------------------------------------------------------------
  265. void LLHUDEffectLookAt::unpackData(LLMessageSystem *mesgsys, S32 blocknum)
  266. {
  267. LLVector3d new_target;
  268. U8 packed_data[PKT_SIZE];
  269. LLUUID dataId;
  270. mesgsys->getUUIDFast(_PREHASH_Effect, _PREHASH_ID, dataId, blocknum);
  271. if (!gAgentCamera.mLookAt.isNull() && dataId == gAgentCamera.mLookAt->getID())
  272. {
  273. return;
  274. }
  275. LLHUDEffect::unpackData(mesgsys, blocknum);
  276. LLUUID source_id;
  277. LLUUID target_id;
  278. S32 size = mesgsys->getSizeFast(_PREHASH_Effect, blocknum, _PREHASH_TypeData);
  279. if (size != PKT_SIZE)
  280. {
  281. llwarns << "LookAt effect with bad size " << size << llendl;
  282. return;
  283. }
  284. mesgsys->getBinaryDataFast(_PREHASH_Effect, _PREHASH_TypeData, packed_data, PKT_SIZE, blocknum);
  285. htonmemcpy(source_id.mData, &(packed_data[SOURCE_AVATAR]), MVT_LLUUID, 16);
  286. LLViewerObject *objp = gObjectList.findObject(source_id);
  287. if (objp && objp->isAvatar())
  288. {
  289. setSourceObject(objp);
  290. }
  291. else
  292. {
  293. //llwarns << "Could not find source avatar for lookat effect" << llendl;
  294. return;
  295. }
  296. htonmemcpy(target_id.mData, &(packed_data[TARGET_OBJECT]), MVT_LLUUID, 16);
  297. objp = gObjectList.findObject(target_id);
  298. htonmemcpy(new_target.mdV, &(packed_data[TARGET_POS]), MVT_LLVector3d, 24);
  299. if (objp)
  300. {
  301. setTargetObjectAndOffset(objp, new_target);
  302. }
  303. else if (target_id.isNull())
  304. {
  305. setTargetPosGlobal(new_target);
  306. }
  307. else
  308. {
  309. //llwarns << "Could not find target object for lookat effect" << llendl;
  310. }
  311. U8 lookAtTypeUnpacked = 0;
  312. htonmemcpy(&lookAtTypeUnpacked, &(packed_data[LOOKAT_TYPE]), MVT_U8, 1);
  313. mTargetType = (ELookAtType)lookAtTypeUnpacked;
  314. if (mTargetType == LOOKAT_TARGET_NONE)
  315. {
  316. clearLookAtTarget();
  317. }
  318. }
  319. //-----------------------------------------------------------------------------
  320. // setTargetObjectAndOffset()
  321. //-----------------------------------------------------------------------------
  322. void LLHUDEffectLookAt::setTargetObjectAndOffset(LLViewerObject *objp, LLVector3d offset)
  323. {
  324. mTargetObject = objp;
  325. mTargetOffsetGlobal = offset;
  326. }
  327. //-----------------------------------------------------------------------------
  328. // setTargetPosGlobal()
  329. //-----------------------------------------------------------------------------
  330. void LLHUDEffectLookAt::setTargetPosGlobal(const LLVector3d &target_pos_global)
  331. {
  332. mTargetObject = NULL;
  333. mTargetOffsetGlobal = target_pos_global;
  334. }
  335. //-----------------------------------------------------------------------------
  336. // setLookAt()
  337. // called by agent logic to set look at behavior locally, and propagate to sim
  338. //-----------------------------------------------------------------------------
  339. BOOL LLHUDEffectLookAt::setLookAt(ELookAtType target_type, LLViewerObject *object, LLVector3 position)
  340. {
  341. if (!mSourceObject)
  342. {
  343. return FALSE;
  344. }
  345. if (target_type >= LOOKAT_NUM_TARGETS)
  346. {
  347. llwarns << "Bad target_type " << (int)target_type << " - ignoring." << llendl;
  348. return FALSE;
  349. }
  350. // must be same or higher priority than existing effect
  351. if ((*mAttentions)[target_type].mPriority < (*mAttentions)[mTargetType].mPriority)
  352. {
  353. return FALSE;
  354. }
  355. F32 current_time = mTimer.getElapsedTimeF32();
  356. // type of lookat behavior or target object has changed
  357. BOOL lookAtChanged = (target_type != mTargetType) || (object != mTargetObject);
  358. // lookat position has moved a certain amount and we haven't just sent an update
  359. lookAtChanged = lookAtChanged || ((dist_vec_squared(position, mLastSentOffsetGlobal) > MIN_DELTAPOS_FOR_UPDATE_SQUARED) &&
  360. ((current_time - mLastSendTime) > (1.f / MAX_SENDS_PER_SEC)));
  361. if (lookAtChanged)
  362. {
  363. mLastSentOffsetGlobal = position;
  364. F32 timeout = (*mAttentions)[target_type].mTimeout;
  365. setDuration(timeout);
  366. setNeedsSendToSim(TRUE);
  367. }
  368. if (target_type == LOOKAT_TARGET_CLEAR)
  369. {
  370. clearLookAtTarget();
  371. }
  372. else
  373. {
  374. mTargetType = target_type;
  375. mTargetObject = object;
  376. if (object)
  377. {
  378. mTargetOffsetGlobal.setVec(position);
  379. }
  380. else
  381. {
  382. mTargetOffsetGlobal = gAgent.getPosGlobalFromAgent(position);
  383. }
  384. mKillTime = mTimer.getElapsedTimeF32() + mDuration;
  385. update();
  386. }
  387. return TRUE;
  388. }
  389. //-----------------------------------------------------------------------------
  390. // clearLookAtTarget()
  391. //-----------------------------------------------------------------------------
  392. void LLHUDEffectLookAt::clearLookAtTarget()
  393. {
  394. mTargetObject = NULL;
  395. mTargetOffsetGlobal.clearVec();
  396. mTargetType = LOOKAT_TARGET_NONE;
  397. if (mSourceObject.notNull())
  398. {
  399. ((LLVOAvatar*)(LLViewerObject*)mSourceObject)->stopMotion(ANIM_AGENT_HEAD_ROT);
  400. }
  401. }
  402. //-----------------------------------------------------------------------------
  403. // markDead()
  404. //-----------------------------------------------------------------------------
  405. void LLHUDEffectLookAt::markDead()
  406. {
  407. if (mSourceObject.notNull())
  408. {
  409. ((LLVOAvatar*)(LLViewerObject*)mSourceObject)->removeAnimationData("LookAtPoint");
  410. }
  411. mSourceObject = NULL;
  412. clearLookAtTarget();
  413. LLHUDEffect::markDead();
  414. }
  415. void LLHUDEffectLookAt::setSourceObject(LLViewerObject* objectp)
  416. {
  417. // restrict source objects to avatars
  418. if (objectp && objectp->isAvatar())
  419. {
  420. LLHUDEffect::setSourceObject(objectp);
  421. }
  422. }
  423. //-----------------------------------------------------------------------------
  424. // render()
  425. //-----------------------------------------------------------------------------
  426. void LLHUDEffectLookAt::render()
  427. {
  428. if (sDebugLookAt && mSourceObject.notNull())
  429. {
  430. gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
  431. LLVector3 target = mTargetPos + ((LLVOAvatar*)(LLViewerObject*)mSourceObject)->mHeadp->getWorldPosition();
  432. gGL.matrixMode(LLRender::MM_MODELVIEW);
  433. gGL.pushMatrix();
  434. gGL.translatef(target.mV[VX], target.mV[VY], target.mV[VZ]);
  435. gGL.scalef(0.3f, 0.3f, 0.3f);
  436. gGL.begin(LLRender::LINES);
  437. {
  438. LLColor3 color = (*mAttentions)[mTargetType].mColor;
  439. gGL.color3f(color.mV[VRED], color.mV[VGREEN], color.mV[VBLUE]);
  440. gGL.vertex3f(-1.f, 0.f, 0.f);
  441. gGL.vertex3f(1.f, 0.f, 0.f);
  442. gGL.vertex3f(0.f, -1.f, 0.f);
  443. gGL.vertex3f(0.f, 1.f, 0.f);
  444. gGL.vertex3f(0.f, 0.f, -1.f);
  445. gGL.vertex3f(0.f, 0.f, 1.f);
  446. } gGL.end();
  447. gGL.popMatrix();
  448. }
  449. }
  450. //-----------------------------------------------------------------------------
  451. // update()
  452. //-----------------------------------------------------------------------------
  453. void LLHUDEffectLookAt::update()
  454. {
  455. // If the target object is dead, set the target object to NULL
  456. if (!mTargetObject.isNull() && mTargetObject->isDead())
  457. {
  458. clearLookAtTarget();
  459. }
  460. // if source avatar is null or dead, mark self as dead and return
  461. if (mSourceObject.isNull() || mSourceObject->isDead())
  462. {
  463. markDead();
  464. return;
  465. }
  466. // make sure the proper set of avatar attention are currently being used.
  467. LLVOAvatar* source_avatar = (LLVOAvatar*)(LLViewerObject*)mSourceObject;
  468. // for now the first cut will just switch on sex. future development could adjust
  469. // timeouts according to avatar age and/or other features.
  470. mAttentions = (source_avatar->getSex() == SEX_MALE) ? &gBoyAttentions : &gGirlAttentions;
  471. //printf("updated to %s\n", (source_avatar->getSex() == SEX_MALE) ? "male" : "female");
  472. F32 time = mTimer.getElapsedTimeF32();
  473. // clear out the effect if time is up
  474. if (mKillTime != 0.f && time > mKillTime)
  475. {
  476. if (mTargetType != LOOKAT_TARGET_NONE)
  477. {
  478. clearLookAtTarget();
  479. // look at timed out (only happens on own avatar), so tell everyone
  480. setNeedsSendToSim(TRUE);
  481. }
  482. }
  483. if (mTargetType != LOOKAT_TARGET_NONE)
  484. {
  485. if (calcTargetPosition())
  486. {
  487. LLMotion* head_motion = ((LLVOAvatar*)(LLViewerObject*)mSourceObject)->findMotion(ANIM_AGENT_HEAD_ROT);
  488. if (!head_motion || head_motion->isStopped())
  489. {
  490. ((LLVOAvatar*)(LLViewerObject*)mSourceObject)->startMotion(ANIM_AGENT_HEAD_ROT);
  491. }
  492. }
  493. }
  494. if (sDebugLookAt)
  495. {
  496. ((LLVOAvatar*)(LLViewerObject*)mSourceObject)->addDebugText((*mAttentions)[mTargetType].mName);
  497. }
  498. }
  499. /**
  500. * Initializes the mTargetPos member from the current mSourceObjec and mTargetObject
  501. * (and possibly mTargetOffsetGlobal).
  502. * When mTargetObject is another avatar, it sets mTargetPos to be their eyes.
  503. *
  504. * Has the side-effect of also calling setAnimationData("LookAtPoint") with the new
  505. * mTargetPos on the source object which is assumed to be an avatar.
  506. *
  507. * Returns whether we successfully calculated a finite target position.
  508. */
  509. bool LLHUDEffectLookAt::calcTargetPosition()
  510. {
  511. LLViewerObject *target_obj = (LLViewerObject *)mTargetObject;
  512. LLVector3 local_offset;
  513. if (target_obj)
  514. {
  515. local_offset.setVec(mTargetOffsetGlobal);
  516. }
  517. else
  518. {
  519. local_offset = gAgent.getPosAgentFromGlobal(mTargetOffsetGlobal);
  520. }
  521. LLVOAvatar* source_avatar = (LLVOAvatar*)(LLViewerObject*)mSourceObject;
  522. if (!source_avatar->isBuilt())
  523. return false;
  524. if (target_obj && target_obj->mDrawable.notNull())
  525. {
  526. LLQuaternion target_rot;
  527. if (target_obj->isAvatar())
  528. {
  529. LLVOAvatar *target_av = (LLVOAvatar *)target_obj;
  530. BOOL looking_at_self = source_avatar->isSelf() && target_av->isSelf();
  531. // if selecting self, stare forward
  532. if (looking_at_self && mTargetOffsetGlobal.magVecSquared() < MIN_TARGET_OFFSET_SQUARED)
  533. {
  534. //sets the lookat point in front of the avatar
  535. mTargetOffsetGlobal.setVec(5.0, 0.0, 0.0);
  536. local_offset.setVec(mTargetOffsetGlobal);
  537. }
  538. // look the other avatar in the eye. note: what happens if target is self? -MG
  539. mTargetPos = target_av->mHeadp->getWorldPosition();
  540. if (mTargetType == LOOKAT_TARGET_MOUSELOOK || mTargetType == LOOKAT_TARGET_FREELOOK)
  541. {
  542. // mouselook and freelook target offsets are absolute
  543. target_rot = LLQuaternion::DEFAULT;
  544. }
  545. else if (looking_at_self && gAgentCamera.cameraCustomizeAvatar())
  546. {
  547. // *NOTE: We have to do this because animation
  548. // overrides do not set lookat behavior.
  549. // *TODO: animation overrides for lookat behavior.
  550. target_rot = target_av->mPelvisp->getWorldRotation();
  551. }
  552. else
  553. {
  554. target_rot = target_av->mRoot.getWorldRotation();
  555. }
  556. }
  557. else // target obj is not an avatar
  558. {
  559. if (target_obj->mDrawable->getGeneration() == -1)
  560. {
  561. mTargetPos = target_obj->getPositionAgent();
  562. target_rot = target_obj->getWorldRotation();
  563. }
  564. else
  565. {
  566. mTargetPos = target_obj->getRenderPosition();
  567. target_rot = target_obj->getRenderRotation();
  568. }
  569. }
  570. mTargetPos += (local_offset * target_rot);
  571. }
  572. else // no target obj or it's not drawable
  573. {
  574. mTargetPos = local_offset;
  575. }
  576. mTargetPos -= source_avatar->mHeadp->getWorldPosition();
  577. if (!mTargetPos.isFinite())
  578. return false;
  579. source_avatar->setAnimationData("LookAtPoint", (void *)&mTargetPos);
  580. return true;
  581. }