Files
SingularityViewer/indra/newview/llvoavatarself.cpp
Shyotl cd86b3a69b Refactoring.
-New LLWearableType class, uses LLDictionary for typeindex<->typename<->assettype<->typelabel conversions.
-LLAvatarDefines cleaned up. Uses LLDictionary for Mesh, TE, Baked lookups/conversions.
-LLAgentWearables TEWearable stuff removed. Use LLAvatarDefines.
-LLWearable WearableType conversions yanked. Use LLWearableType.
-LLVOAvatar TEWEarable stuff removed. Use LLAvatarDefines.
-EWearableType now LLWearableType::EType
-LLWearable::getID() renamed to LLWearable::getAssetID()
VOAvatar cleanup.
-Removed redundant TEWearable functions.
-Some code migrated to F32 LLVOAvatar::calcMorphAmount(). No functional change.
-LLVOAvatar::removeMissingBakedTextures virtual. Implementation moved to VOAvatarSelf
2011-10-03 15:00:43 -05:00

674 lines
19 KiB
C++

/**
* @file llvoavatar.cpp
* @brief Implementation of LLVOAvatar class which is a derivation fo LLViewerObject
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#include "llviewerprecompiledheaders.h"
#include "llvoavatarself.h"
#include "llvoavatar.h"
#include "pipeline.h"
#include "llagent.h" // Get state values from here
#include "llagentcamera.h"
#include "llagentwearables.h"
#include "llhudeffecttrail.h"
#include "llhudmanager.h"
#include "llnotificationsutil.h"
#include "llselectmgr.h"
#include "lltoolgrab.h" // for needsRenderBeam
#include "lltoolmgr.h" // for needsRenderBeam
#include "lltoolmorph.h"
#include "llviewercamera.h"
#include "llviewercontrol.h"
#include "llviewermedia.h"
#include "llviewermenu.h"
#include "llviewerobjectlist.h"
#include "llviewerstats.h"
#include "llviewerregion.h"
#include "llmeshrepository.h"
#include "llvovolume.h"
LLVOAvatarSelf *gAgentAvatarp = NULL;
BOOL isAgentAvatarValid()
{
return (gAgentAvatarp &&
(gAgentAvatarp->getRegion() != NULL) &&
(!gAgentAvatarp->isDead()));
}
/*********************************************************************************
** **
** Begin LLVOAvatarSelf Constructor routines
**
**/
LLVOAvatarSelf::LLVOAvatarSelf(const LLUUID& id,
const LLPCode pcode,
LLViewerRegion* regionp) :
LLVOAvatar(id, pcode, regionp),
mScreenp(NULL),
mLastRegionHandle(0),
mRegionCrossingCount(0)
{
gAgentWearables.setAvatarObject(this);
gAgentCamera.setAvatarObject(this);
mMotionController.mIsSelf = TRUE;
lldebugs << "Marking avatar as self " << id << llendl;
}
void LLVOAvatarSelf::initInstance()
{
BOOL status = TRUE;
// creates hud joint(mScreen) among other things
status &= loadAvatarSelf();
// adds attachment points to mScreen among other things
LLVOAvatar::initInstance();
llinfos << "Self avatar object created. Starting timer." << llendl;
/*mDebugSelfLoadTimer.reset();
// clear all times to -1 for debugging
for (U32 i =0; i < LLVOAvatarDefines::TEX_NUM_INDICES; ++i)
{
for (U32 j = 0; j <= MAX_DISCARD_LEVEL; ++j)
{
mDebugTextureLoadTimes[i][j] = -1.0f;
}
}
for (U32 i =0; i < LLVOAvatarDefines::BAKED_NUM_INDICES; ++i)
{
mDebugBakedTextureTimes[i][0] = -1.0f;
mDebugBakedTextureTimes[i][1] = -1.0f;
}*/
status &= buildMenus();
if (!status)
{
llerrs << "Unable to load user's avatar" << llendl;
return;
}
}
// virtual
void LLVOAvatarSelf::markDead()
{
mBeam = NULL;
LLVOAvatar::markDead();
}
/*virtual*/ BOOL LLVOAvatarSelf::loadAvatar()
{
BOOL success = LLVOAvatar::loadAvatar();
return success;
}
BOOL LLVOAvatarSelf::loadAvatarSelf()
{
BOOL success = TRUE;
// avatar_skeleton.xml
if (!buildSkeletonSelf(sAvatarSkeletonInfo))
{
llwarns << "avatar file: buildSkeleton() failed" << llendl;
return FALSE;
}
// TODO: make loadLayersets() called only by self.
//success &= loadLayersets();
return success;
}
BOOL LLVOAvatarSelf::buildSkeletonSelf(const LLVOAvatarSkeletonInfo *info)
{
LLMemType mt(LLMemType::MTYPE_AVATAR);
// add special-purpose "screen" joint
mScreenp = new LLViewerJoint("mScreen", NULL);
// for now, put screen at origin, as it is only used during special
// HUD rendering mode
F32 aspect = LLViewerCamera::getInstance()->getAspect();
LLVector3 scale(1.f, aspect, 1.f);
mScreenp->setScale(scale);
mScreenp->setWorldPosition(LLVector3::zero);
// need to update screen agressively when sidebar opens/closes, for example
mScreenp->mUpdateXform = TRUE;
return TRUE;
}
BOOL LLVOAvatarSelf::buildMenus()
{
//-------------------------------------------------------------------------
// build the attach and detach menus
//-------------------------------------------------------------------------
if(gNoRender)
return TRUE;
// *TODO: Translate
gAttachBodyPartPieMenus[0] = NULL;
gAttachBodyPartPieMenus[1] = new LLPieMenu(std::string("Right Arm >"));
gAttachBodyPartPieMenus[2] = new LLPieMenu(std::string("Head >"));
gAttachBodyPartPieMenus[3] = new LLPieMenu(std::string("Left Arm >"));
gAttachBodyPartPieMenus[4] = NULL;
gAttachBodyPartPieMenus[5] = new LLPieMenu(std::string("Left Leg >"));
gAttachBodyPartPieMenus[6] = new LLPieMenu(std::string("Torso >"));
gAttachBodyPartPieMenus[7] = new LLPieMenu(std::string("Right Leg >"));
gDetachBodyPartPieMenus[0] = NULL;
gDetachBodyPartPieMenus[1] = new LLPieMenu(std::string("Right Arm >"));
gDetachBodyPartPieMenus[2] = new LLPieMenu(std::string("Head >"));
gDetachBodyPartPieMenus[3] = new LLPieMenu(std::string("Left Arm >"));
gDetachBodyPartPieMenus[4] = NULL;
gDetachBodyPartPieMenus[5] = new LLPieMenu(std::string("Left Leg >"));
gDetachBodyPartPieMenus[6] = new LLPieMenu(std::string("Torso >"));
gDetachBodyPartPieMenus[7] = new LLPieMenu(std::string("Right Leg >"));
for (S32 i = 0; i < 8; i++)
{
if (gAttachBodyPartPieMenus[i])
{
gAttachPieMenu->appendPieMenu( gAttachBodyPartPieMenus[i] );
}
else
{
BOOL attachment_found = FALSE;
for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
iter != mAttachmentPoints.end();
++iter)
{
LLViewerJointAttachment* attachment = iter->second;
if (attachment->getGroup() == i)
{
LLMenuItemCallGL* item;
// [RLVa:KB] - Checked: 2009-07-06 (RLVa-1.0.0c)
// We need the userdata param to disable options in this pie menu later on (Left Hand / Right Hand option)
item = new LLMenuItemCallGL(attachment->getName(),
NULL,
object_selected_and_point_valid, attachment);
// [/RLVa:KB]
// item = new LLMenuItemCallGL(attachment->getName(),
// NULL,
// object_selected_and_point_valid);
item->addListener(gMenuHolder->getListenerByName("Object.AttachToAvatar"), "on_click", iter->first);
gAttachPieMenu->append(item);
attachment_found = TRUE;
break;
}
}
if (!attachment_found)
{
gAttachPieMenu->appendSeparator();
}
}
if (gDetachBodyPartPieMenus[i])
{
gDetachPieMenu->appendPieMenu( gDetachBodyPartPieMenus[i] );
}
else
{
BOOL attachment_found = FALSE;
for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
iter != mAttachmentPoints.end();
++iter)
{
LLViewerJointAttachment* attachment = iter->second;
if (attachment->getGroup() == i)
{
gDetachPieMenu->append(new LLMenuItemCallGL(attachment->getName(),
&handle_detach_from_avatar, object_attached, attachment));
attachment_found = TRUE;
break;
}
}
if (!attachment_found)
{
gDetachPieMenu->appendSeparator();
}
}
}
// add screen attachments
for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
iter != mAttachmentPoints.end();
++iter)
{
LLViewerJointAttachment* attachment = iter->second;
if (attachment->getGroup() == 8)
{
LLMenuItemCallGL* item;
// [RLVa:KB] - Checked: 2009-07-06 (RLVa-1.0.0c)
// We need the userdata param to disable options in this pie menu later on
item = new LLMenuItemCallGL(attachment->getName(),
NULL,
object_selected_and_point_valid, attachment);
// [/RLVa:KB]
// item = new LLMenuItemCallGL(attachment->getName(),
// NULL,
// object_selected_and_point_valid);
item->addListener(gMenuHolder->getListenerByName("Object.AttachToAvatar"), "on_click", iter->first);
gAttachScreenPieMenu->append(item);
gDetachScreenPieMenu->append(new LLMenuItemCallGL(attachment->getName(),
&handle_detach_from_avatar, object_attached, attachment));
}
}
for (S32 pass = 0; pass < 2; pass++)
{
for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
iter != mAttachmentPoints.end();
++iter)
{
LLViewerJointAttachment* attachment = iter->second;
if (attachment->getIsHUDAttachment() != (pass == 1))
{
continue;
}
// RELEASE-RLVa: random comment because we want know if LL ever changes this to not include "attachment" as userdata
LLMenuItemCallGL* item = new LLMenuItemCallGL(attachment->getName(),
NULL, &object_selected_and_point_valid,
&attach_label, attachment);
item->addListener(gMenuHolder->getListenerByName("Object.AttachToAvatar"), "on_click", iter->first);
gAttachSubMenu->append(item);
gDetachSubMenu->append(new LLMenuItemCallGL(attachment->getName(),
&handle_detach_from_avatar, object_attached, &detach_label, attachment));
}
if (pass == 0)
{
// put separator between non-hud and hud attachments
gAttachSubMenu->appendSeparator();
gDetachSubMenu->appendSeparator();
}
}
for (S32 group = 0; group < 8; group++)
{
// skip over groups that don't have sub menus
if (!gAttachBodyPartPieMenus[group] || !gDetachBodyPartPieMenus[group])
{
continue;
}
std::multimap<S32, S32> attachment_pie_menu_map;
// gather up all attachment points assigned to this group, and throw into map sorted by pie slice number
for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
iter != mAttachmentPoints.end();
++iter)
{
LLViewerJointAttachment* attachment = iter->second;
if(attachment->getGroup() == group)
{
// use multimap to provide a partial order off of the pie slice key
S32 pie_index = attachment->getPieSlice();
attachment_pie_menu_map.insert(std::make_pair(pie_index, iter->first));
}
}
// add in requested order to pie menu, inserting separators as necessary
S32 cur_pie_slice = 0;
for (std::multimap<S32, S32>::iterator attach_it = attachment_pie_menu_map.begin();
attach_it != attachment_pie_menu_map.end(); ++attach_it)
{
S32 requested_pie_slice = attach_it->first;
S32 attach_index = attach_it->second;
while (cur_pie_slice < requested_pie_slice)
{
gAttachBodyPartPieMenus[group]->appendSeparator();
gDetachBodyPartPieMenus[group]->appendSeparator();
cur_pie_slice++;
}
LLViewerJointAttachment* attachment = get_if_there(mAttachmentPoints, attach_index, (LLViewerJointAttachment*)NULL);
if (attachment)
{
// [RLVa:KB] - Checked: 2009-07-06 (RLVa-1.0.0c)
// We need the userdata param to disable options in this pie menu later on
LLMenuItemCallGL* item = new LLMenuItemCallGL(attachment->getName(),
NULL, object_selected_and_point_valid, attachment);
// [/RLVa:KB]
// LLMenuItemCallGL* item = new LLMenuItemCallGL(attachment->getName(),
// NULL, object_selected_and_point_valid);
gAttachBodyPartPieMenus[group]->append(item);
item->addListener(gMenuHolder->getListenerByName("Object.AttachToAvatar"), "on_click", attach_index);
gDetachBodyPartPieMenus[group]->append(new LLMenuItemCallGL(attachment->getName(),
&handle_detach_from_avatar,
object_attached, attachment));
cur_pie_slice++;
}
}
}
return TRUE;
}
void LLVOAvatarSelf::cleanup()
{
markDead();
delete mScreenp;
mScreenp = NULL;
mRegionp = NULL;
}
LLVOAvatarSelf::~LLVOAvatarSelf()
{
cleanup();
}
BOOL LLVOAvatarSelf::updateCharacter(LLAgent &agent)
{
LLMemType mt(LLMemType::MTYPE_AVATAR);
// update screen joint size
if (mScreenp)
{
F32 aspect = LLViewerCamera::getInstance()->getAspect();
LLVector3 scale(1.f, aspect, 1.f);
mScreenp->setScale(scale);
mScreenp->updateWorldMatrixChildren();
resetHUDAttachments();
}
return LLVOAvatar::updateCharacter(agent);
}
// virtual
BOOL LLVOAvatarSelf::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
{
if (!isAgentAvatarValid())
{
return TRUE;
}
if(!gNoRender)
{
//Emerald performs some force-bakes stuff here. Added it in because we noticed slow responses with client tag ident. -HgB
for(U8 i=0;i<getNumTEs();++i)
{
LLViewerTexture* te = getTEImage(i);
te->forceActive();
}
}
LLVOAvatar::idleUpdate(agent,world,time);
if(!gNoRender)
idleUpdateTractorBeam();
return TRUE;
}
// virtual
LLJoint *LLVOAvatarSelf::getJoint(const std::string &name)
{
if (mScreenp)
{
LLJoint* jointp = mScreenp->findJoint(name);
if (jointp) return jointp;
}
return LLVOAvatar::getJoint(name);
}
//virtual
void LLVOAvatarSelf::resetJointPositions( void )
{
return LLVOAvatar::resetJointPositions();
}
// virtual
void LLVOAvatarSelf::requestStopMotion(LLMotion* motion)
{
// Only agent avatars should handle the stop motion notifications.
// Notify agent that motion has stopped
gAgent.requestStopMotion(motion);
}
// virtual
void LLVOAvatarSelf::stopMotionFromSource(const LLUUID& source_id)
{
for(AnimSourceIterator motion_it = mAnimationSources.find(source_id); motion_it != mAnimationSources.end();)
{
gAgent.sendAnimationRequest( motion_it->second, ANIM_REQUEST_STOP );
mAnimationSources.erase(motion_it++);
}
LLViewerObject* object = gObjectList.findObject(source_id);
if (object)
{
object->mFlags &= ~FLAGS_ANIM_SOURCE;
}
}
//virtual
void LLVOAvatarSelf::removeMissingBakedTextures()
{
BOOL removed = FALSE;
for (U32 i = 0; i < mBakedTextureDatas.size(); i++)
{
const S32 te = mBakedTextureDatas[i].mTextureIndex;
const LLViewerTexture* tex = getTEImage(te);
// Replace with default if we can't find the asset, assuming the
// default is actually valid (which it should be unless something
// is seriously wrong).
if (!tex || tex->isMissingAsset())
{
LLViewerTexture *imagep = LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT_AVATAR);
if (imagep)
{
setTEImage(te, imagep);
removed = TRUE;
}
}
}
if (removed)
{
for(U32 i = 0; i < mBakedTextureDatas.size(); i++)
{
invalidateComposite(mBakedTextureDatas[i].mTexLayerSet, FALSE);
}
updateMeshTextures();
requestLayerSetUploads();
}
}
//virtual
void LLVOAvatarSelf::updateRegion(LLViewerRegion *regionp)
{
// Save the global position
LLVector3d global_pos_from_old_region = getPositionGlobal();
// Change the region
setRegion(regionp);
if (regionp)
{ // Set correct region-relative position from global coordinates
setPositionGlobal(global_pos_from_old_region);
// Diagnostic info
//LLVector3d pos_from_new_region = getPositionGlobal();
//llinfos << "pos_from_old_region is " << global_pos_from_old_region
// << " while pos_from_new_region is " << pos_from_new_region
// << llendl;
}
if (!regionp || (regionp->getHandle() != mLastRegionHandle))
{
if (mLastRegionHandle != 0)
{
++mRegionCrossingCount;
F64 delta = (F64)mRegionCrossingTimer.getElapsedTimeF32();
F64 avg = (mRegionCrossingCount == 1) ? 0 : LLViewerStats::getInstance()->getStat(LLViewerStats::ST_CROSSING_AVG);
F64 delta_avg = (delta + avg*(mRegionCrossingCount-1)) / mRegionCrossingCount;
LLViewerStats::getInstance()->setStat(LLViewerStats::ST_CROSSING_AVG, delta_avg);
F64 max = (mRegionCrossingCount == 1) ? 0 : LLViewerStats::getInstance()->getStat(LLViewerStats::ST_CROSSING_MAX);
max = llmax(delta, max);
LLViewerStats::getInstance()->setStat(LLViewerStats::ST_CROSSING_MAX, max);
// Diagnostics
llinfos << "Region crossing took " << (F32)(delta * 1000.0) << " ms " << llendl;
}
if (regionp)
{
mLastRegionHandle = regionp->getHandle();
}
}
mRegionCrossingTimer.reset();
LLViewerObject::updateRegion(regionp);
}
//--------------------------------------------------------------------
// draw tractor beam when editing objects
//--------------------------------------------------------------------
//virtual
void LLVOAvatarSelf::idleUpdateTractorBeam()
{
if(gSavedSettings.getBOOL("DisablePointAtAndBeam"))
{
return;
}
// </edit>
const LLPickInfo& pick = gViewerWindow->getLastPick();
// No beam for media textures
// TODO: this will change for Media on a Prim
if(pick.getObject() && pick.mObjectFace >= 0)
{
const LLTextureEntry* tep = pick.getObject()->getTE(pick.mObjectFace);
if (tep && LLViewerMedia::textureHasMedia(tep->getID()))
{
return;
}
}
// This is only done for yourself (maybe it should be in the agent?)
if (!needsRenderBeam() || !mIsBuilt)
{
mBeam = NULL;
}
else if (!mBeam || mBeam->isDead())
{
// VEFFECT: Tractor Beam
mBeam = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BEAM);
mBeam->setColor(LLColor4U(gAgent.getEffectColor()));
mBeam->setSourceObject(this);
mBeamTimer.reset();
}
if (!mBeam.isNull())
{
LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection();
if (gAgentCamera.mPointAt.notNull())
{
// get point from pointat effect
mBeam->setPositionGlobal(gAgentCamera.mPointAt->getPointAtPosGlobal());
mBeam->triggerLocal();
}
else if (selection->getFirstRootObject() &&
selection->getSelectType() != SELECT_TYPE_HUD)
{
LLViewerObject* objectp = selection->getFirstRootObject();
mBeam->setTargetObject(objectp);
}
else
{
mBeam->setTargetObject(NULL);
LLTool *tool = LLToolMgr::getInstance()->getCurrentTool();
if (tool->isEditing())
{
if (tool->getEditingObject())
{
mBeam->setTargetObject(tool->getEditingObject());
}
else
{
mBeam->setPositionGlobal(tool->getEditingPointGlobal());
}
}
else
{
mBeam->setPositionGlobal(pick.mPosGlobal);
}
}
if (mBeamTimer.getElapsedTimeF32() > 0.25f)
{
mBeam->setColor(LLColor4U(gAgent.getEffectColor()));
mBeam->setNeedsSendToSim(TRUE);
mBeamTimer.reset();
}
}
}
//-----------------------------------------------------------------------------
// restoreMeshData()
//-----------------------------------------------------------------------------
// virtual
void LLVOAvatarSelf::restoreMeshData()
{
LLMemType mt(LLMemType::MTYPE_AVATAR);
//llinfos << "Restoring" << llendl;
mMeshValid = TRUE;
updateJointLODs();
updateAttachmentVisibility(gAgentCamera.getCameraMode());
// force mesh update as LOD might not have changed to trigger this
gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_GEOMETRY, TRUE);
}
//------------------------------------------------------------------------
// needsRenderBeam()
//------------------------------------------------------------------------
BOOL LLVOAvatarSelf::needsRenderBeam()
{
if (gNoRender)
{
return FALSE;
}
LLTool *tool = LLToolMgr::getInstance()->getCurrentTool();
BOOL is_touching_or_grabbing = (tool == LLToolGrab::getInstance() && LLToolGrab::getInstance()->isEditing());
if (LLToolGrab::getInstance()->getEditingObject() &&
LLToolGrab::getInstance()->getEditingObject()->isAttachment())
{
// don't render selection beam on hud objects
is_touching_or_grabbing = FALSE;
}
return is_touching_or_grabbing || (mState & AGENT_STATE_EDITING && LLSelectMgr::getInstance()->shouldShowSelection());
}