llhudeffectlookat.cpp
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:21k
源码类别:

游戏引擎

开发平台:

C++ Builder

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