llhudeffectlookat.cpp

Go to the documentation of this file.
00001 
00032 #include "llviewerprecompiledheaders.h"
00033 
00034 #include "llhudeffectlookat.h"
00035 
00036 #include "message.h"
00037 #include "llagent.h"
00038 #include "llvoavatar.h"
00039 #include "lldrawable.h"
00040 #include "llviewerobjectlist.h"
00041 #include "llsphere.h"
00042 #include "llselectmgr.h"
00043 #include "llglheaders.h"
00044 
00045 
00046 #include "llxmltree.h"
00047 
00048 
00049 BOOL LLHUDEffectLookAt::sDebugLookAt = FALSE;
00050 
00051 // packet layout
00052 const S32 SOURCE_AVATAR = 0;
00053 const S32 TARGET_OBJECT = 16;
00054 const S32 TARGET_POS = 32;
00055 const S32 LOOKAT_TYPE = 56;
00056 const S32 PKT_SIZE = 57;
00057 
00058 // throttle
00059 const F32 MAX_SENDS_PER_SEC = 4.f;
00060 
00061 const F32 MIN_DELTAPOS_FOR_UPDATE = 0.05f;
00062 const F32 MIN_TARGET_OFFSET_SQUARED = 0.0001f;
00063 
00064 
00065 // can't use actual F32_MAX, because we add this to the current frametime
00066 const F32 MAX_TIMEOUT = F32_MAX / 2.f;
00067 
00071 class LLAttention
00072 {
00073 public:
00074         LLAttention(){}
00075         LLAttention(F32 timeout, F32 priority, char *name, LLColor3 color) :
00076           mTimeout(timeout), mPriority(priority), mName(name), mColor(color)
00077         {
00078         }
00079         F32 mTimeout, mPriority;
00080         LLString mName;
00081         LLColor3 mColor;
00082 };
00083 
00087 class LLAttentionSet
00088 {
00089 public:
00090         LLAttentionSet(const LLAttention attentions[])
00091         {
00092                 for(int i=0; i<LOOKAT_NUM_TARGETS; i++)
00093                 {
00094                         mAttentions[i] = attentions[i];
00095                 }
00096         }
00097         LLAttention mAttentions[LOOKAT_NUM_TARGETS];
00098         LLAttention& operator[](int idx) { return mAttentions[idx]; }
00099 };
00100 
00101 // Default attribute set data.
00102 // Used to initialize the global attribute set objects, one of which will be
00103 // refered to by the hud object at any given time.
00104 // Note that the values below are only the default values and that any or all of them
00105 // can be overwritten with customizing data from the XML file. The actual values below
00106 // are those that will give exactly the same look-at behavior as before the ability
00107 // to customize was added. - MG
00108 static const 
00109         LLAttention 
00110                 BOY_ATTS[] = { // default set of masculine attentions
00111                         LLAttention(MAX_TIMEOUT, 0, "None",                      LLColor3(0.3f, 0.3f, 0.3f)), // LOOKAT_TARGET_NONE
00112                         LLAttention(3.f,         1, "Idle",                  LLColor3(0.5f, 0.5f, 0.5f)), // LOOKAT_TARGET_IDLE
00113                         LLAttention(4.f,         3, "AutoListen",        LLColor3(0.5f, 0.5f, 0.5f)), // LOOKAT_TARGET_AUTO_LISTEN
00114                         LLAttention(2.f,         2, "FreeLook",          LLColor3(0.5f, 0.5f, 0.9f)), // LOOKAT_TARGET_FREELOOK
00115                         LLAttention(4.f,         3, "Respond",       LLColor3(0.0f, 0.0f, 0.0f)), // LOOKAT_TARGET_RESPOND
00116                         LLAttention(1.f,         4, "Hover",             LLColor3(0.5f, 0.9f, 0.5f)), // LOOKAT_TARGET_HOVER
00117                         LLAttention(MAX_TIMEOUT, 0, "Conversation",  LLColor3(0.1f, 0.1f, 0.5f)), // LOOKAT_TARGET_CONVERSATION
00118                         LLAttention(MAX_TIMEOUT, 6, "Select",            LLColor3(0.9f, 0.5f, 0.5f)), // LOOKAT_TARGET_SELECT
00119                         LLAttention(MAX_TIMEOUT, 6, "Focus",             LLColor3(0.9f, 0.5f, 0.9f)), // LOOKAT_TARGET_FOCUS
00120                         LLAttention(MAX_TIMEOUT, 7, "Mouselook",         LLColor3(0.9f, 0.9f, 0.5f)), // LOOKAT_TARGET_MOUSELOOK
00121                         LLAttention(0.f,         8, "Clear",             LLColor3(1.0f, 1.0f, 1.0f)), // LOOKAT_TARGET_CLEAR
00122                 },                                                                                                                                                              
00123                 GIRL_ATTS[] = { // default set of feminine attentions                                                                                                   
00124                         LLAttention(MAX_TIMEOUT, 0, "None",                      LLColor3(0.3f, 0.3f, 0.3f)), // LOOKAT_TARGET_NONE
00125                         LLAttention(3.f,         1, "Idle",                  LLColor3(0.5f, 0.5f, 0.5f)), // LOOKAT_TARGET_IDLE
00126                         LLAttention(4.f,         3, "AutoListen",        LLColor3(0.5f, 0.5f, 0.5f)), // LOOKAT_TARGET_AUTO_LISTEN
00127                         LLAttention(2.f,         2, "FreeLook",          LLColor3(0.5f, 0.5f, 0.9f)), // LOOKAT_TARGET_FREELOOK
00128                         LLAttention(4.f,         3, "Respond",       LLColor3(0.0f, 0.0f, 0.0f)), // LOOKAT_TARGET_RESPOND
00129                         LLAttention(1.f,         4, "Hover",             LLColor3(0.5f, 0.9f, 0.5f)), // LOOKAT_TARGET_HOVER
00130                         LLAttention(MAX_TIMEOUT, 0, "Conversation",  LLColor3(0.1f, 0.1f, 0.5f)), // LOOKAT_TARGET_CONVERSATION
00131                         LLAttention(MAX_TIMEOUT, 6, "Select",            LLColor3(0.9f, 0.5f, 0.5f)), // LOOKAT_TARGET_SELECT
00132                         LLAttention(MAX_TIMEOUT, 6, "Focus",             LLColor3(0.9f, 0.5f, 0.9f)), // LOOKAT_TARGET_FOCUS
00133                         LLAttention(MAX_TIMEOUT, 7, "Mouselook",         LLColor3(0.9f, 0.9f, 0.5f)), // LOOKAT_TARGET_MOUSELOOK
00134                         LLAttention(0.f,         8, "Clear",             LLColor3(1.0f, 1.0f, 1.0f)), // LOOKAT_TARGET_CLEAR
00135                 };
00136 
00137 static LLAttentionSet
00138         gBoyAttentions(BOY_ATTS),
00139         gGirlAttentions(GIRL_ATTS);
00140 
00141 
00142 static BOOL loadGender(LLXmlTreeNode* gender)
00143 {
00144         if( !gender)
00145         {
00146                 return FALSE;
00147         }
00148         LLString str;
00149         gender->getAttributeString("name", str);
00150         LLAttentionSet& attentions = (str.compare("Masculine") == 0) ? gBoyAttentions : gGirlAttentions;
00151         for (LLXmlTreeNode* attention_node = gender->getChildByName( "param" );
00152                  attention_node;
00153                  attention_node = gender->getNextNamedChild())
00154         {
00155                 attention_node->getAttributeString("attention", str);
00156                 LLAttention* attention;
00157                 if     (str == "idle")         attention = &attentions[LOOKAT_TARGET_IDLE];
00158                 else if(str == "auto_listen")  attention = &attentions[LOOKAT_TARGET_AUTO_LISTEN];
00159                 else if(str == "freelook")     attention = &attentions[LOOKAT_TARGET_FREELOOK];
00160                 else if(str == "respond")      attention = &attentions[LOOKAT_TARGET_RESPOND];
00161                 else if(str == "hover")        attention = &attentions[LOOKAT_TARGET_HOVER];
00162                 else if(str == "conversation") attention = &attentions[LOOKAT_TARGET_CONVERSATION];
00163                 else if(str == "select")       attention = &attentions[LOOKAT_TARGET_SELECT];
00164                 else if(str == "focus")        attention = &attentions[LOOKAT_TARGET_FOCUS];
00165                 else if(str == "mouselook")    attention = &attentions[LOOKAT_TARGET_MOUSELOOK];
00166                 else return FALSE;
00167 
00168                 F32 priority, timeout;
00169                 attention_node->getAttributeF32("priority", priority);
00170                 attention_node->getAttributeF32("timeout", timeout);
00171                 if(timeout < 0) timeout = MAX_TIMEOUT;
00172                 attention->mPriority = priority;
00173                 attention->mTimeout = timeout;
00174         }       
00175         return TRUE;
00176 }
00177 
00178 static BOOL loadAttentions()
00179 {
00180         static BOOL first_time = TRUE;
00181         if( ! first_time) 
00182         {
00183                 return TRUE; // maybe not ideal but otherwise it can continue to fail forever.
00184         }
00185         first_time = FALSE;
00186         
00187         char filename[MAX_PATH]; /*Flawfinder: ignore*/
00188         strncpy(filename,gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,"attentions.xml").c_str(), sizeof(filename) -1);              /*Flawfinder: ignore*/  
00189         filename[sizeof(filename) -1] = '\0';
00190         LLXmlTree xml_tree;
00191         BOOL success = xml_tree.parseFile( filename, FALSE );
00192         if( !success )
00193         {
00194                 return FALSE;
00195         }
00196         LLXmlTreeNode* root = xml_tree.getRoot();
00197         if( !root )
00198         {
00199                 return FALSE;
00200         }
00201 
00202         //-------------------------------------------------------------------------
00203         // <linden_attentions version="1.0"> (root)
00204         //-------------------------------------------------------------------------
00205         if( !root->hasName( "linden_attentions" ) )
00206         {
00207                 llwarns << "Invalid linden_attentions file header: " << filename << llendl;
00208                 return FALSE;
00209         }
00210 
00211         LLString version;
00212         static LLStdStringHandle version_string = LLXmlTree::addAttributeString("version");
00213         if( !root->getFastAttributeString( version_string, version ) || (version != "1.0") )
00214         {
00215                 llwarns << "Invalid linden_attentions file version: " << version << llendl;
00216                 return FALSE;
00217         }
00218 
00219         //-------------------------------------------------------------------------
00220         // <gender>
00221         //-------------------------------------------------------------------------
00222         for (LLXmlTreeNode* child = root->getChildByName( "gender" );
00223                  child;
00224                  child = root->getNextNamedChild())
00225         {
00226                 if( !loadGender( child ) )
00227                 {
00228                         return FALSE;
00229                 }
00230         }
00231 
00232         return TRUE;
00233 }
00234 
00235 
00236 
00237 
00238 //-----------------------------------------------------------------------------
00239 // LLHUDEffectLookAt()
00240 //-----------------------------------------------------------------------------
00241 LLHUDEffectLookAt::LLHUDEffectLookAt(const U8 type) : 
00242         LLHUDEffect(type), 
00243         mKillTime(0.f),
00244         mLastSendTime(0.f)
00245 {
00246         clearLookAtTarget();
00247         // parse the default sets
00248         loadAttentions();
00249         // initialize current attention set. switches when avatar sex changes.
00250         mAttentions = &gGirlAttentions;
00251 }
00252 
00253 //-----------------------------------------------------------------------------
00254 // ~LLHUDEffectLookAt()
00255 //-----------------------------------------------------------------------------
00256 LLHUDEffectLookAt::~LLHUDEffectLookAt()
00257 {
00258 }
00259 
00260 //-----------------------------------------------------------------------------
00261 // packData()
00262 //-----------------------------------------------------------------------------
00263 void LLHUDEffectLookAt::packData(LLMessageSystem *mesgsys)
00264 {
00265         // Pack the default data
00266         LLHUDEffect::packData(mesgsys);
00267 
00268         // Pack the type-specific data.  Uses a fun packed binary format.  Whee!
00269         U8 packed_data[PKT_SIZE];
00270         memset(packed_data, 0, PKT_SIZE);
00271 
00272         if (mSourceObject)
00273         {
00274                 htonmemcpy(&(packed_data[SOURCE_AVATAR]), mSourceObject->mID.mData, MVT_LLUUID, 16);
00275         }
00276         else
00277         {
00278                 htonmemcpy(&(packed_data[SOURCE_AVATAR]), LLUUID::null.mData, MVT_LLUUID, 16);
00279         }
00280 
00281         // pack both target object and position
00282         // position interpreted as offset if target object is non-null
00283         if (mTargetObject)
00284         {
00285                 htonmemcpy(&(packed_data[TARGET_OBJECT]), mTargetObject->mID.mData, MVT_LLUUID, 16);
00286         }
00287         else
00288         {
00289                 htonmemcpy(&(packed_data[TARGET_OBJECT]), LLUUID::null.mData, MVT_LLUUID, 16);
00290         }
00291 
00292         htonmemcpy(&(packed_data[TARGET_POS]), mTargetOffsetGlobal.mdV, MVT_LLVector3d, 24);
00293 
00294         U8 lookAtTypePacked = (U8)mTargetType;
00295         
00296         htonmemcpy(&(packed_data[LOOKAT_TYPE]), &lookAtTypePacked, MVT_U8, 1);
00297 
00298         mesgsys->addBinaryDataFast(_PREHASH_TypeData, packed_data, PKT_SIZE);
00299 
00300         mLastSendTime = mTimer.getElapsedTimeF32();
00301 }
00302 
00303 //-----------------------------------------------------------------------------
00304 // unpackData()
00305 //-----------------------------------------------------------------------------
00306 void LLHUDEffectLookAt::unpackData(LLMessageSystem *mesgsys, S32 blocknum)
00307 {
00308         LLVector3d new_target;
00309         U8 packed_data[PKT_SIZE];
00310 
00311         LLUUID dataId;
00312         mesgsys->getUUIDFast(_PREHASH_Effect, _PREHASH_ID, dataId, blocknum);
00313 
00314         if (!gAgent.mLookAt.isNull() && dataId == gAgent.mLookAt->getID())
00315         {
00316                 return;
00317         }
00318 
00319         LLHUDEffect::unpackData(mesgsys, blocknum);
00320         LLUUID source_id;
00321         LLUUID target_id;
00322         S32 size = mesgsys->getSizeFast(_PREHASH_Effect, blocknum, _PREHASH_TypeData);
00323         if (size != PKT_SIZE)
00324         {
00325                 llwarns << "LookAt effect with bad size " << size << llendl;
00326                 return;
00327         }
00328         mesgsys->getBinaryDataFast(_PREHASH_Effect, _PREHASH_TypeData, packed_data, PKT_SIZE, blocknum);
00329         
00330         htonmemcpy(source_id.mData, &(packed_data[SOURCE_AVATAR]), MVT_LLUUID, 16);
00331 
00332         LLViewerObject *objp = gObjectList.findObject(source_id);
00333         if (objp && objp->isAvatar())
00334         {
00335                 setSourceObject(objp);
00336         }
00337         else
00338         {
00339                 //llwarns << "Could not find source avatar for lookat effect" << llendl;
00340                 return;
00341         }
00342 
00343         htonmemcpy(target_id.mData, &(packed_data[TARGET_OBJECT]), MVT_LLUUID, 16);
00344 
00345         objp = gObjectList.findObject(target_id);
00346 
00347         htonmemcpy(new_target.mdV, &(packed_data[TARGET_POS]), MVT_LLVector3d, 24);
00348 
00349         if (objp)
00350         {
00351                 setTargetObjectAndOffset(objp, new_target);
00352         }
00353         else if (target_id.isNull())
00354         {
00355                 setTargetPosGlobal(new_target);
00356         }
00357         else
00358         {
00359                 //llwarns << "Could not find target object for lookat effect" << llendl;
00360         }
00361 
00362         U8 lookAtTypeUnpacked = 0;
00363         htonmemcpy(&lookAtTypeUnpacked, &(packed_data[LOOKAT_TYPE]), MVT_U8, 1);
00364         mTargetType = (ELookAtType)lookAtTypeUnpacked;
00365 
00366         if (mTargetType == LOOKAT_TARGET_NONE)
00367         {
00368                 clearLookAtTarget();
00369         }
00370 }
00371 
00372 //-----------------------------------------------------------------------------
00373 // setTargetObjectAndOffset()
00374 //-----------------------------------------------------------------------------
00375 void LLHUDEffectLookAt::setTargetObjectAndOffset(LLViewerObject *objp, LLVector3d offset)
00376 {
00377         mTargetObject = objp;
00378         mTargetOffsetGlobal = offset;
00379 }
00380 
00381 //-----------------------------------------------------------------------------
00382 // setTargetPosGlobal()
00383 //-----------------------------------------------------------------------------
00384 void LLHUDEffectLookAt::setTargetPosGlobal(const LLVector3d &target_pos_global)
00385 {
00386         mTargetObject = NULL;
00387         mTargetOffsetGlobal = target_pos_global;
00388 }
00389 
00390 //-----------------------------------------------------------------------------
00391 // setLookAt()
00392 // called by agent logic to set look at behavior locally, and propagate to sim
00393 //-----------------------------------------------------------------------------
00394 BOOL LLHUDEffectLookAt::setLookAt(ELookAtType target_type, LLViewerObject *object, LLVector3 position)
00395 {
00396         if (!mSourceObject)
00397         {
00398                 return FALSE;
00399         }
00400         
00401         llassert(target_type < LOOKAT_NUM_TARGETS);
00402 
00403         // must be same or higher priority than existing effect
00404         if ((*mAttentions)[target_type].mPriority < (*mAttentions)[mTargetType].mPriority)
00405         {
00406                 return FALSE;
00407         }
00408 
00409         F32 current_time  = mTimer.getElapsedTimeF32();
00410 
00411         // type of lookat behavior or target object has changed
00412         BOOL lookAtChanged = (target_type != mTargetType) || (object != mTargetObject);
00413 
00414         // lookat position has moved a certain amount and we haven't just sent an update
00415         lookAtChanged = lookAtChanged || (dist_vec(position, mLastSentOffsetGlobal) > MIN_DELTAPOS_FOR_UPDATE) && 
00416                 ((current_time - mLastSendTime) > (1.f / MAX_SENDS_PER_SEC));
00417 
00418         if (lookAtChanged)
00419         {
00420                 mLastSentOffsetGlobal = position;
00421                 F32 timeout = (*mAttentions)[target_type].mTimeout;
00422                 setDuration(timeout);
00423                 setNeedsSendToSim(TRUE);
00424         }
00425  
00426         if (target_type == LOOKAT_TARGET_CLEAR)
00427         {
00428                 clearLookAtTarget();
00429         }
00430         else
00431         {
00432                 mTargetType = target_type;
00433                 mTargetObject = object;
00434                 if (object)
00435                 {
00436                         mTargetOffsetGlobal.setVec(position);
00437                 }
00438                 else
00439                 {
00440                         mTargetOffsetGlobal = gAgent.getPosGlobalFromAgent(position);
00441                 }
00442                 mKillTime = mTimer.getElapsedTimeF32() + mDuration;
00443 
00444                 update();
00445         }
00446         return TRUE;
00447 }
00448 
00449 //-----------------------------------------------------------------------------
00450 // clearLookAtTarget()
00451 //-----------------------------------------------------------------------------
00452 void LLHUDEffectLookAt::clearLookAtTarget()
00453 {
00454         mTargetObject = NULL;
00455         mTargetOffsetGlobal.clearVec();
00456         mTargetType = LOOKAT_TARGET_NONE;
00457         if (mSourceObject.notNull())
00458         {
00459                 ((LLVOAvatar*)(LLViewerObject*)mSourceObject)->stopMotion(ANIM_AGENT_HEAD_ROT);
00460         }
00461 }
00462 
00463 //-----------------------------------------------------------------------------
00464 // markDead()
00465 //-----------------------------------------------------------------------------
00466 void LLHUDEffectLookAt::markDead()
00467 {
00468         if (mSourceObject.notNull())
00469         {
00470                 ((LLVOAvatar*)(LLViewerObject*)mSourceObject)->removeAnimationData("LookAtPoint");
00471         }
00472 
00473         mSourceObject = NULL;
00474         clearLookAtTarget();
00475         LLHUDEffect::markDead();
00476 }
00477 
00478 void LLHUDEffectLookAt::setSourceObject(LLViewerObject* objectp)
00479 {
00480         // restrict source objects to avatars
00481         if (objectp && objectp->isAvatar())
00482         {
00483                 LLHUDEffect::setSourceObject(objectp);
00484         }
00485 }
00486 
00487 //-----------------------------------------------------------------------------
00488 // render()
00489 //-----------------------------------------------------------------------------
00490 void LLHUDEffectLookAt::render()
00491 {
00492         if (sDebugLookAt && mSourceObject.notNull())
00493         {
00494                 LLGLSNoTexture gls_no_texture;
00495 
00496                 LLVector3 target = mTargetPos + ((LLVOAvatar*)(LLViewerObject*)mSourceObject)->mHeadp->getWorldPosition();
00497                 glMatrixMode(GL_MODELVIEW);
00498                 glPushMatrix();
00499                 glTranslatef(target.mV[VX], target.mV[VY], target.mV[VZ]);
00500                 glScalef(0.3f, 0.3f, 0.3f);
00501                 glBegin(GL_LINES);
00502                 {
00503                         LLColor3 color = (*mAttentions)[mTargetType].mColor;
00504                         glColor3f(color.mV[VRED], color.mV[VGREEN], color.mV[VBLUE]);
00505                         glVertex3f(-1.f, 0.f, 0.f);
00506                         glVertex3f(1.f, 0.f, 0.f);
00507 
00508                         glVertex3f(0.f, -1.f, 0.f);
00509                         glVertex3f(0.f, 1.f, 0.f);
00510 
00511                         glVertex3f(0.f, 0.f, -1.f);
00512                         glVertex3f(0.f, 0.f, 1.f);
00513                 } glEnd();
00514                 glPopMatrix();
00515         }
00516 }
00517 
00518 //-----------------------------------------------------------------------------
00519 // update()
00520 //-----------------------------------------------------------------------------
00521 void LLHUDEffectLookAt::update()
00522 {
00523         // If the target object is dead, set the target object to NULL
00524         if (!mTargetObject.isNull() && mTargetObject->isDead())
00525         {
00526                 clearLookAtTarget();
00527         }
00528 
00529         // if source avatar is null or dead, mark self as dead and return
00530         if (mSourceObject.isNull() || mSourceObject->isDead())
00531         {
00532                 markDead();
00533                 return;
00534         }
00535 
00536         // make sure the proper set of avatar attention are currently being used.
00537         LLVOAvatar* source_avatar = (LLVOAvatar*)(LLViewerObject*)mSourceObject;
00538         // for now the first cut will just switch on sex. future development could adjust 
00539         // timeouts according to avatar age and/or other features. 
00540         mAttentions = (source_avatar->getSex() == SEX_MALE) ? &gBoyAttentions : &gGirlAttentions;
00541         //printf("updated to %s\n", (source_avatar->getSex() == SEX_MALE) ? "male" : "female");
00542 
00543         F32 time = mTimer.getElapsedTimeF32();
00544 
00545         // clear out the effect if time is up
00546         if (mKillTime != 0.f && time > mKillTime)
00547         {
00548                 if (mTargetType != LOOKAT_TARGET_NONE)
00549                 {
00550                         clearLookAtTarget();
00551                         // look at timed out (only happens on own avatar), so tell everyone
00552                         setNeedsSendToSim(TRUE);
00553                 }
00554         }
00555 
00556         if (mTargetType != LOOKAT_TARGET_NONE)
00557         {
00558                 calcTargetPosition();
00559 
00560                 LLMotion* head_motion = ((LLVOAvatar*)(LLViewerObject*)mSourceObject)->findMotion(ANIM_AGENT_HEAD_ROT);
00561                 if (!head_motion || head_motion->isStopped())
00562                 {
00563                         ((LLVOAvatar*)(LLViewerObject*)mSourceObject)->startMotion(ANIM_AGENT_HEAD_ROT);
00564                 }
00565         }
00566 
00567         if (sDebugLookAt)
00568         {
00569                 ((LLVOAvatar*)(LLViewerObject*)mSourceObject)->addDebugText((*mAttentions)[mTargetType].mName);
00570         }
00571 }
00572 
00581 void LLHUDEffectLookAt::calcTargetPosition()
00582 {
00583         if (gNoRender)
00584         {
00585                 return;
00586         }
00587 
00588         LLViewerObject *target_obj = (LLViewerObject *)mTargetObject;
00589         LLVector3 local_offset;
00590         
00591         if (target_obj)
00592         {
00593                 local_offset.setVec(mTargetOffsetGlobal);
00594         }
00595         else
00596         {
00597                 local_offset = gAgent.getPosAgentFromGlobal(mTargetOffsetGlobal);
00598         }
00599 
00600         LLVOAvatar* source_avatar = (LLVOAvatar*)(LLViewerObject*)mSourceObject;
00601 
00602         if (target_obj && target_obj->mDrawable.notNull())
00603         {
00604                 LLQuaternion target_rot;
00605                 if (target_obj->isAvatar())
00606                 {
00607                         LLVOAvatar *target_av = (LLVOAvatar *)target_obj;
00608 
00609                         BOOL looking_at_self = source_avatar->isSelf() && target_av->isSelf();
00610 
00611                         // if selecting self, stare forward
00612                         if (looking_at_self && mTargetOffsetGlobal.magVecSquared() < MIN_TARGET_OFFSET_SQUARED)
00613                         {
00614                                 //sets the lookat point in front of the avatar
00615                                 mTargetOffsetGlobal.setVec(5.0, 0.0, 0.0);
00616                                 local_offset.setVec(mTargetOffsetGlobal);
00617                         }
00618 
00619                         // look the other avatar in the eye. note: what happens if target is self? -MG
00620                         mTargetPos = target_av->mHeadp->getWorldPosition();
00621                         if (mTargetType == LOOKAT_TARGET_MOUSELOOK || mTargetType == LOOKAT_TARGET_FREELOOK)
00622                         {
00623                                 // mouselook and freelook target offsets are absolute
00624                                 target_rot = LLQuaternion::DEFAULT;
00625                         }
00626                         else if (looking_at_self && gAgent.cameraCustomizeAvatar())
00627                         {
00628                                 // *NOTE: We have to do this because animation
00629                                 // overrides do not set lookat behavior.
00630                                 // *TODO: animation overrides for lookat behavior.
00631                                 target_rot = target_av->mPelvisp->getWorldRotation();
00632                         }
00633                         else
00634                         {
00635                                 target_rot = target_av->mRoot.getWorldRotation();
00636                         }
00637                 }
00638                 else // target obj is not an avatar
00639                 {
00640                         if (target_obj->mDrawable->getGeneration() == -1)
00641                         {
00642                                 mTargetPos = target_obj->getPositionAgent();
00643                                 target_rot = target_obj->getWorldRotation();
00644                         }
00645                         else
00646                         {
00647                                 mTargetPos = target_obj->getRenderPosition();
00648                                 target_rot = target_obj->getRenderRotation();
00649                         }
00650                 }
00651 
00652                 mTargetPos += (local_offset * target_rot);
00653         }
00654         else // no target obj or it's not drawable
00655         {
00656                 mTargetPos = local_offset;
00657         }
00658 
00659         mTargetPos -= source_avatar->mHeadp->getWorldPosition();
00660         source_avatar->setAnimationData("LookAtPoint", (void *)&mTargetPos);
00661 }

Generated on Thu Jul 1 06:08:42 2010 for Second Life Viewer by  doxygen 1.4.7