llhudeffectlookat.cpp

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

Generated on Fri May 16 08:33:38 2008 for SecondLife by  doxygen 1.5.5