diff options
author | Ansariel <ansariel.hiller@phoenixviewer.com> | 2024-05-22 21:25:21 +0200 |
---|---|---|
committer | Andrey Lihatskiy <alihatskiy@productengine.com> | 2024-05-22 22:40:26 +0300 |
commit | e2e37cced861b98de8c1a7c9c0d3a50d2d90e433 (patch) | |
tree | 1bb897489ce524986f6196201c10ac0d8861aa5f /indra/newview/llvoavatarself.cpp | |
parent | 069ea06848f766466f1a281144c82a0f2bd79f3a (diff) |
Fix line endlings
Diffstat (limited to 'indra/newview/llvoavatarself.cpp')
-rw-r--r-- | indra/newview/llvoavatarself.cpp | 5802 |
1 files changed, 2901 insertions, 2901 deletions
diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp index 753f105736..2e347920f5 100644 --- a/indra/newview/llvoavatarself.cpp +++ b/indra/newview/llvoavatarself.cpp @@ -1,2901 +1,2901 @@ -/**
- * @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$
- */
-
-#if LL_MSVC
-// disable warning about boost::lexical_cast returning uninitialized data
-// when it fails to parse the string
-#pragma warning (disable:4701)
-#endif
-
-#include "llviewerprecompiledheaders.h"
-
-#include "llvoavatarself.h"
-#include "llvoavatar.h"
-
-#include "pipeline.h"
-
-#include "llagent.h" // Get state values from here
-#include "llattachmentsmgr.h"
-#include "llagentcamera.h"
-#include "llagentwearables.h"
-#include "llhudeffecttrail.h"
-#include "llhudmanager.h"
-#include "llinventoryfunctions.h"
-#include "lllocaltextureobject.h"
-#include "llnotificationsutil.h"
-#include "llselectmgr.h"
-#include "lltoolgrab.h" // for needsRenderBeam
-#include "lltoolmgr.h" // for needsRenderBeam
-#include "lltoolmorph.h"
-#include "lltrans.h"
-#include "llviewercamera.h"
-#include "llviewercontrol.h"
-#include "llviewermenu.h"
-#include "llviewerobjectlist.h"
-#include "llviewerstats.h"
-#include "llviewerregion.h"
-#include "llviewertexlayer.h"
-#include "llviewerwearable.h"
-#include "llappearancemgr.h"
-#include "llmeshrepository.h"
-#include "llvovolume.h"
-#include "llsdutil.h"
-#include "llstartup.h"
-#include "llsdserialize.h"
-#include "llcallstack.h"
-#include "llcorehttputil.h"
-#include "lluiusage.h"
-
-#if LL_MSVC
-// disable boost::lexical_cast warning
-#pragma warning (disable:4702)
-#endif
-
-#include <boost/lexical_cast.hpp>
-
-LLPointer<LLVOAvatarSelf> gAgentAvatarp = NULL;
-
-bool isAgentAvatarValid()
-{
- return (gAgentAvatarp.notNull() && gAgentAvatarp->isValid());
-}
-
-void selfStartPhase(const std::string& phase_name)
-{
- if (isAgentAvatarValid())
- {
- gAgentAvatarp->startPhase(phase_name);
- }
-}
-
-void selfStopPhase(const std::string& phase_name, bool err_check)
-{
- if (isAgentAvatarValid())
- {
- gAgentAvatarp->stopPhase(phase_name, err_check);
- }
-}
-
-void selfClearPhases()
-{
- if (isAgentAvatarValid())
- {
- gAgentAvatarp->clearPhases();
- }
-}
-
-using namespace LLAvatarAppearanceDefines;
-
-
-LLSD summarize_by_buckets(std::vector<LLSD> in_records, std::vector<std::string> by_fields, std::string val_field);
-
-/*********************************************************************************
- ** **
- ** Begin private LLVOAvatarSelf Support classes
- **
- **/
-
-struct LocalTextureData
-{
- LocalTextureData() :
- mIsBakedReady(false),
- mDiscard(MAX_DISCARD_LEVEL+1),
- mImage(NULL),
- mWearableID(IMG_DEFAULT_AVATAR),
- mTexEntry(NULL)
- {}
- LLPointer<LLViewerFetchedTexture> mImage;
- bool mIsBakedReady;
- S32 mDiscard;
- LLUUID mWearableID; // UUID of the wearable that this texture belongs to, not of the image itself
- LLTextureEntry *mTexEntry;
-};
-
-//-----------------------------------------------------------------------------
-// Callback data
-//-----------------------------------------------------------------------------
-
-
-/**
- **
- ** End LLVOAvatarSelf Support classes
- ** **
- *********************************************************************************/
-
-
-//-----------------------------------------------------------------------------
-// Static Data
-//-----------------------------------------------------------------------------
-S32Bytes LLVOAvatarSelf::sScratchTexBytes(0);
-std::map< LLGLenum, LLGLuint*> LLVOAvatarSelf::sScratchTexNames;
-
-
-/*********************************************************************************
- ** **
- ** Begin LLVOAvatarSelf Constructor routines
- **
- **/
-
-LLVOAvatarSelf::LLVOAvatarSelf(const LLUUID& id,
- const LLPCode pcode,
- LLViewerRegion* regionp) :
- LLVOAvatar(id, pcode, regionp),
- mScreenp(NULL),
- mLastRegionHandle(0),
- mRegionCrossingCount(0),
- // Value outside legal range, so will always be a mismatch the
- // first time through.
- mLastHoverOffsetSent(LLVector3(0.0f, 0.0f, -999.0f)),
- mInitialMetric(true),
- mMetricSequence(0)
-{
- mMotionController.mIsSelf = true;
-
- LL_DEBUGS() << "Marking avatar as self " << id << LL_ENDL;
-}
-
-// Called periodically for diagnostics, return true when done.
-bool output_self_av_texture_diagnostics()
-{
- if (!isAgentAvatarValid())
- return true; // done checking
-
- gAgentAvatarp->outputRezDiagnostics();
-
- return false;
-}
-
-bool update_avatar_rez_metrics()
-{
- if (!isAgentAvatarValid())
- return true;
-
- gAgentAvatarp->updateAvatarRezMetrics(false);
-
- return false;
-}
-
-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();
-
- LL_INFOS() << "Self avatar object created. Starting timer." << LL_ENDL;
- mDebugSelfLoadTimer.reset();
- // clear all times to -1 for debugging
- for (U32 i =0; i < LLAvatarAppearanceDefines::TEX_NUM_INDICES; ++i)
- {
- for (U32 j = 0; j <= MAX_DISCARD_LEVEL; ++j)
- {
- mDebugTextureLoadTimes[i][j] = -1.0f;
- }
- }
-
- for (U32 i =0; i < LLAvatarAppearanceDefines::BAKED_NUM_INDICES; ++i)
- {
- mDebugBakedTextureTimes[i][0] = -1.0f;
- mDebugBakedTextureTimes[i][1] = -1.0f;
- }
-
- status &= buildMenus();
- if (!status)
- {
- LL_ERRS() << "Unable to load user's avatar" << LL_ENDL;
- return;
- }
-
- setHoverIfRegionEnabled();
-
- //doPeriodically(output_self_av_texture_diagnostics, 30.0);
- doPeriodically(update_avatar_rez_metrics, 5.0);
- doPeriodically(boost::bind(&LLVOAvatarSelf::checkStuckAppearance, this), 30.0);
-
- mInitFlags |= 1<<2;
-}
-
-void LLVOAvatarSelf::setHoverIfRegionEnabled()
-{
- if (getRegion() && getRegion()->simulatorFeaturesReceived())
- {
- if (getRegion()->avatarHoverHeightEnabled())
- {
- F32 hover_z = gSavedPerAccountSettings.getF32("AvatarHoverOffsetZ");
- setHoverOffset(LLVector3(0.0, 0.0, llclamp(hover_z,MIN_HOVER_Z,MAX_HOVER_Z)));
- LL_INFOS("Avatar") << avString() << " set hover height from debug setting " << hover_z << LL_ENDL;
- }
- else
- {
- setHoverOffset(LLVector3(0.0, 0.0, 0.0));
- LL_INFOS("Avatar") << avString() << " zeroing hover height, region does not support" << LL_ENDL;
- }
- }
- else
- {
- LL_INFOS("Avatar") << avString() << " region or simulator features not known, no change on hover" << LL_ENDL;
- if (getRegion())
- {
- getRegion()->setSimulatorFeaturesReceivedCallback(boost::bind(&LLVOAvatarSelf::onSimulatorFeaturesReceived,this,_1));
- }
-
- }
-}
-
-bool LLVOAvatarSelf::checkStuckAppearance()
-{
- const F32 CONDITIONAL_UNSTICK_INTERVAL = 300.0;
- const F32 UNCONDITIONAL_UNSTICK_INTERVAL = 600.0;
-
- if (gAgentWearables.isCOFChangeInProgress())
- {
- LL_DEBUGS("Avatar") << "checking for stuck appearance" << LL_ENDL;
- F32 change_time = gAgentWearables.getCOFChangeTime();
- LL_DEBUGS("Avatar") << "change in progress for " << change_time << " seconds" << LL_ENDL;
- S32 active_hp = LLAppearanceMgr::instance().countActiveHoldingPatterns();
- LL_DEBUGS("Avatar") << "active holding patterns " << active_hp << " seconds" << LL_ENDL;
- S32 active_copies = LLAppearanceMgr::instance().getActiveCopyOperations();
- LL_DEBUGS("Avatar") << "active copy operations " << active_copies << LL_ENDL;
-
- if ((change_time > CONDITIONAL_UNSTICK_INTERVAL && active_copies == 0) ||
- (change_time > UNCONDITIONAL_UNSTICK_INTERVAL))
- {
- gAgentWearables.notifyLoadingFinished();
- }
- }
-
- // Return false to continue running check periodically.
- return LLApp::isExiting();
-}
-
-// virtual
-void LLVOAvatarSelf::markDead()
-{
- mBeam = NULL;
- LLVOAvatar::markDead();
-}
-
-/*virtual*/ bool LLVOAvatarSelf::loadAvatar()
-{
- bool success = LLVOAvatar::loadAvatar();
-
- // set all parameters stored directly in the avatar to have
- // the isSelfParam to be true - this is used to prevent
- // them from being animated or trigger accidental rebakes
- // when we copy params from the wearable to the base avatar.
- for (LLViewerVisualParam* param = (LLViewerVisualParam*) getFirstVisualParam();
- param;
- param = (LLViewerVisualParam*) getNextVisualParam())
- {
- if (param->getWearableType() != LLWearableType::WT_INVALID)
- {
- param->setIsDummy(true);
- }
- }
-
- return success;
-}
-
-
-bool LLVOAvatarSelf::loadAvatarSelf()
-{
- bool success = true;
- // avatar_skeleton.xml
- if (!buildSkeletonSelf(sAvatarSkeletonInfo))
- {
- LL_WARNS() << "avatar file: buildSkeleton() failed" << LL_ENDL;
- return false;
- }
-
- return success;
-}
-
-bool LLVOAvatarSelf::buildSkeletonSelf(const LLAvatarSkeletonInfo *info)
-{
- // 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);
- // SL-315
- 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
- //-------------------------------------------------------------------------
- gAttachBodyPartPieMenus[0] = NULL;
-
- LLContextMenu::Params params;
- params.label(LLTrans::getString("BodyPartsRightArm"));
- params.name(params.label);
- params.visible(false);
- gAttachBodyPartPieMenus[1] = LLUICtrlFactory::create<LLContextMenu> (params);
-
- params.label(LLTrans::getString("BodyPartsHead"));
- params.name(params.label);
- gAttachBodyPartPieMenus[2] = LLUICtrlFactory::create<LLContextMenu> (params);
-
- params.label(LLTrans::getString("BodyPartsLeftArm"));
- params.name(params.label);
- gAttachBodyPartPieMenus[3] = LLUICtrlFactory::create<LLContextMenu> (params);
-
- gAttachBodyPartPieMenus[4] = NULL;
-
- params.label(LLTrans::getString("BodyPartsLeftLeg"));
- params.name(params.label);
- gAttachBodyPartPieMenus[5] = LLUICtrlFactory::create<LLContextMenu> (params);
-
- params.label(LLTrans::getString("BodyPartsTorso"));
- params.name(params.label);
- gAttachBodyPartPieMenus[6] = LLUICtrlFactory::create<LLContextMenu> (params);
-
- params.label(LLTrans::getString("BodyPartsRightLeg"));
- params.name(params.label);
- gAttachBodyPartPieMenus[7] = LLUICtrlFactory::create<LLContextMenu> (params);
-
- params.label(LLTrans::getString("BodyPartsEnhancedSkeleton"));
- params.name(params.label);
- gAttachBodyPartPieMenus[8] = LLUICtrlFactory::create<LLContextMenu>(params);
-
- gDetachBodyPartPieMenus[0] = NULL;
-
- params.label(LLTrans::getString("BodyPartsRightArm"));
- params.name(params.label);
- gDetachBodyPartPieMenus[1] = LLUICtrlFactory::create<LLContextMenu> (params);
-
- params.label(LLTrans::getString("BodyPartsHead"));
- params.name(params.label);
- gDetachBodyPartPieMenus[2] = LLUICtrlFactory::create<LLContextMenu> (params);
-
- params.label(LLTrans::getString("BodyPartsLeftArm"));
- params.name(params.label);
- gDetachBodyPartPieMenus[3] = LLUICtrlFactory::create<LLContextMenu> (params);
-
- gDetachBodyPartPieMenus[4] = NULL;
-
- params.label(LLTrans::getString("BodyPartsLeftLeg"));
- params.name(params.label);
- gDetachBodyPartPieMenus[5] = LLUICtrlFactory::create<LLContextMenu> (params);
-
- params.label(LLTrans::getString("BodyPartsTorso"));
- params.name(params.label);
- gDetachBodyPartPieMenus[6] = LLUICtrlFactory::create<LLContextMenu> (params);
-
- params.label(LLTrans::getString("BodyPartsRightLeg"));
- params.name(params.label);
- gDetachBodyPartPieMenus[7] = LLUICtrlFactory::create<LLContextMenu> (params);
-
- params.label(LLTrans::getString("BodyPartsEnhancedSkeleton"));
- params.name(params.label);
- gDetachBodyPartPieMenus[8] = LLUICtrlFactory::create<LLContextMenu>(params);
-
- for (S32 i = 0; i < 9; i++)
- {
- if (gAttachBodyPartPieMenus[i])
- {
- gAttachPieMenu->appendContextSubMenu( gAttachBodyPartPieMenus[i] );
- }
- else
- {
- for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
- iter != mAttachmentPoints.end();
- ++iter)
- {
- LLViewerJointAttachment* attachment = iter->second;
- if (attachment && attachment->getGroup() == i)
- {
- LLMenuItemCallGL::Params item_params;
-
- std::string sub_piemenu_name = attachment->getName();
- if (LLTrans::getString(sub_piemenu_name) != "")
- {
- item_params.label = LLTrans::getString(sub_piemenu_name);
- }
- else
- {
- item_params.label = sub_piemenu_name;
- }
- item_params.name =(item_params.label );
- item_params.on_click.function_name = "Object.AttachToAvatar";
- item_params.on_click.parameter = iter->first;
- item_params.on_enable.function_name = "Object.EnableWear";
- item_params.on_enable.parameter = iter->first;
- LLMenuItemCallGL* item = LLUICtrlFactory::create<LLMenuItemCallGL>(item_params);
-
- gAttachPieMenu->addChild(item);
-
- break;
-
- }
- }
- }
-
- if (gDetachBodyPartPieMenus[i])
- {
- gDetachPieMenu->appendContextSubMenu( gDetachBodyPartPieMenus[i] );
- gDetachAttSelfMenu->appendContextSubMenu(gDetachBodyPartPieMenus[i]);
- gDetachAvatarMenu->appendContextSubMenu(gDetachBodyPartPieMenus[i]);
- }
- else
- {
- for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
- iter != mAttachmentPoints.end();
- ++iter)
- {
- LLViewerJointAttachment* attachment = iter->second;
- if (attachment && attachment->getGroup() == i)
- {
- LLMenuItemCallGL::Params item_params;
- std::string sub_piemenu_name = attachment->getName();
- if (LLTrans::getString(sub_piemenu_name) != "")
- {
- item_params.label = LLTrans::getString(sub_piemenu_name);
- }
- else
- {
- item_params.label = sub_piemenu_name;
- }
- item_params.name =(item_params.label );
- item_params.on_click.function_name = "Attachment.DetachFromPoint";
- item_params.on_click.parameter = iter->first;
- item_params.on_enable.function_name = "Attachment.PointFilled";
- item_params.on_enable.parameter = iter->first;
- LLMenuItemCallGL* item = LLUICtrlFactory::create<LLMenuItemCallGL>(item_params);
-
- gDetachPieMenu->addChild(item);
- gDetachAttSelfMenu->addChild(LLUICtrlFactory::create<LLMenuItemCallGL>(item_params));
- gDetachAvatarMenu->addChild(LLUICtrlFactory::create<LLMenuItemCallGL>(item_params));
- break;
- }
- }
- }
- }
-
-
- // add screen attachments
- for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
- iter != mAttachmentPoints.end();
- ++iter)
- {
- LLViewerJointAttachment* attachment = iter->second;
- if (attachment->getGroup() == 9)
- {
- LLMenuItemCallGL::Params item_params;
- std::string sub_piemenu_name = attachment->getName();
- if (LLTrans::getString(sub_piemenu_name) != "")
- {
- item_params.label = LLTrans::getString(sub_piemenu_name);
- }
- else
- {
- item_params.label = sub_piemenu_name;
- }
- item_params.name =(item_params.label );
- item_params.on_click.function_name = "Object.AttachToAvatar";
- item_params.on_click.parameter = iter->first;
- item_params.on_enable.function_name = "Object.EnableWear";
- item_params.on_enable.parameter = iter->first;
- LLMenuItemCallGL* item = LLUICtrlFactory::create<LLMenuItemCallGL>(item_params);
- gAttachScreenPieMenu->addChild(item);
-
- item_params.on_click.function_name = "Attachment.DetachFromPoint";
- item_params.on_click.parameter = iter->first;
- item_params.on_enable.function_name = "Attachment.PointFilled";
- item_params.on_enable.parameter = iter->first;
- item = LLUICtrlFactory::create<LLMenuItemCallGL>(item_params);
- gDetachScreenPieMenu->addChild(item);
- gDetachHUDAttSelfMenu->addChild(LLUICtrlFactory::create<LLMenuItemCallGL>(item_params));
- gDetachHUDAvatarMenu->addChild(LLUICtrlFactory::create<LLMenuItemCallGL>(item_params));
- }
- }
-
- for (S32 pass = 0; pass < 2; pass++)
- {
- // *TODO: Skinning - gAttachSubMenu is an awful, awful hack
- if (!gAttachSubMenu)
- {
- break;
- }
- for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
- iter != mAttachmentPoints.end();
- ++iter)
- {
- LLViewerJointAttachment* attachment = iter->second;
- if (attachment->getIsHUDAttachment() != (pass == 1))
- {
- continue;
- }
- LLMenuItemCallGL::Params item_params;
- std::string sub_piemenu_name = attachment->getName();
- if (LLTrans::getString(sub_piemenu_name) != "")
- {
- item_params.label = LLTrans::getString(sub_piemenu_name);
- }
- else
- {
- item_params.label = sub_piemenu_name;
- }
- item_params.name =(item_params.label );
- item_params.on_click.function_name = "Object.AttachToAvatar";
- item_params.on_click.parameter = iter->first;
- item_params.on_enable.function_name = "Object.EnableWear";
- item_params.on_enable.parameter = iter->first;
- //* TODO: Skinning:
- //LLSD params;
- //params["index"] = iter->first;
- //params["label"] = attachment->getName();
- //item->addEventHandler("on_enable", LLMenuItemCallGL::MenuCallback().function_name("Attachment.Label").parameter(params));
-
- LLMenuItemCallGL* item = LLUICtrlFactory::create<LLMenuItemCallGL>(item_params);
- gAttachSubMenu->addChild(item);
-
- item_params.on_click.function_name = "Attachment.DetachFromPoint";
- item_params.on_click.parameter = iter->first;
- item_params.on_enable.function_name = "Attachment.PointFilled";
- item_params.on_enable.parameter = iter->first;
- //* TODO: Skinning: item->addEventHandler("on_enable", LLMenuItemCallGL::MenuCallback().function_name("Attachment.Label").parameter(params));
-
- item = LLUICtrlFactory::create<LLMenuItemCallGL>(item_params);
- gDetachSubMenu->addChild(item);
- }
- if (pass == 0)
- {
- // put separator between non-hud and hud attachments
- gAttachSubMenu->addSeparator();
- gDetachSubMenu->addSeparator();
- }
- }
-
- for (S32 group = 0; group < 9; 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 && 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
- for (std::multimap<S32, S32>::iterator attach_it = attachment_pie_menu_map.begin();
- attach_it != attachment_pie_menu_map.end(); ++attach_it)
- {
- S32 attach_index = attach_it->second;
-
- LLViewerJointAttachment* attachment = get_if_there(mAttachmentPoints, attach_index, (LLViewerJointAttachment*)NULL);
- if (attachment)
- {
- LLMenuItemCallGL::Params item_params;
- item_params.name = attachment->getName();
- item_params.label = LLTrans::getString(attachment->getName());
- item_params.on_click.function_name = "Object.AttachToAvatar";
- item_params.on_click.parameter = attach_index;
- item_params.on_enable.function_name = "Object.EnableWear";
- item_params.on_enable.parameter = attach_index;
-
- LLMenuItemCallGL* item = LLUICtrlFactory::create<LLMenuItemCallGL>(item_params);
- gAttachBodyPartPieMenus[group]->addChild(item);
-
- item_params.on_click.function_name = "Attachment.DetachFromPoint";
- item_params.on_click.parameter = attach_index;
- item_params.on_enable.function_name = "Attachment.PointFilled";
- item_params.on_enable.parameter = attach_index;
- item = LLUICtrlFactory::create<LLMenuItemCallGL>(item_params);
- gDetachBodyPartPieMenus[group]->addChild(item);
- }
- }
- }
- return true;
-}
-
-void LLVOAvatarSelf::cleanup()
-{
- markDead();
- delete mScreenp;
- mScreenp = NULL;
- mRegionp = NULL;
-}
-
-LLVOAvatarSelf::~LLVOAvatarSelf()
-{
- cleanup();
-}
-
-/**
- **
- ** End LLVOAvatarSelf Constructor routines
- ** **
- *********************************************************************************/
-
-// virtual
-bool LLVOAvatarSelf::updateCharacter(LLAgent &agent)
-{
- // 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::isValid() const
-{
- return ((getRegion() != NULL) && !isDead());
-}
-
-// virtual
-void LLVOAvatarSelf::idleUpdate(LLAgent &agent, const F64 &time)
-{
- if (isValid())
- {
- LLVOAvatar::idleUpdate(agent, time);
- idleUpdateTractorBeam();
- }
-}
-
-// virtual
-LLJoint *LLVOAvatarSelf::getJoint(const std::string &name)
-{
- LLJoint *jointp = NULL;
- jointp = LLVOAvatar::getJoint(name);
- if (!jointp && mScreenp)
- {
- jointp = mScreenp->findJoint(name);
- if (jointp)
- {
- mJointMap[name] = jointp;
- }
- }
- if (jointp && jointp != mScreenp && jointp != mRoot)
- {
- llassert(LLVOAvatar::getJoint((S32)jointp->getJointNum())==jointp);
- }
- return jointp;
-}
-
-// virtual
-bool LLVOAvatarSelf::setVisualParamWeight(const LLVisualParam *which_param, F32 weight)
-{
- if (!which_param)
- {
- return false;
- }
- LLViewerVisualParam *param = (LLViewerVisualParam*) LLCharacter::getVisualParam(which_param->getID());
- return setParamWeight(param,weight);
-}
-
-// virtual
-bool LLVOAvatarSelf::setVisualParamWeight(const char* param_name, F32 weight)
-{
- if (!param_name)
- {
- return false;
- }
- LLViewerVisualParam *param = (LLViewerVisualParam*) LLCharacter::getVisualParam(param_name);
- return setParamWeight(param,weight);
-}
-
-// virtual
-bool LLVOAvatarSelf::setVisualParamWeight(S32 index, F32 weight)
-{
- LLViewerVisualParam *param = (LLViewerVisualParam*) LLCharacter::getVisualParam(index);
- return setParamWeight(param,weight);
-}
-
-bool LLVOAvatarSelf::setParamWeight(const LLViewerVisualParam *param, F32 weight)
-{
- if (!param)
- {
- return false;
- }
-
- if (param->getCrossWearable())
- {
- LLWearableType::EType type = (LLWearableType::EType)param->getWearableType();
- U32 size = gAgentWearables.getWearableCount(type);
- for (U32 count = 0; count < size; ++count)
- {
- LLViewerWearable *wearable = gAgentWearables.getViewerWearable(type,count);
- if (wearable)
- {
- wearable->setVisualParamWeight(param->getID(), weight);
- }
- }
- }
-
- return LLCharacter::setVisualParamWeight(param,weight);
-}
-
-/*virtual*/
-void LLVOAvatarSelf::updateVisualParams()
-{
- LLVOAvatar::updateVisualParams();
-}
-
-void LLVOAvatarSelf::writeWearablesToAvatar()
-{
- for (U32 type = 0; type < LLWearableType::WT_COUNT; type++)
- {
- LLWearable *wearable = gAgentWearables.getTopWearable((LLWearableType::EType)type);
- if (wearable)
- {
- wearable->writeToAvatar(this);
- }
- }
-
-}
-
-/*virtual*/
-void LLVOAvatarSelf::idleUpdateAppearanceAnimation()
-{
- // Animate all top-level wearable visual parameters
- gAgentWearables.animateAllWearableParams(calcMorphAmount());
-
- // Apply wearable visual params to avatar
- writeWearablesToAvatar();
-
- //allow avatar to process updates
- LLVOAvatar::idleUpdateAppearanceAnimation();
-
-}
-
-// 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
-bool LLVOAvatarSelf::hasMotionFromSource(const LLUUID& source_id)
-{
- AnimSourceIterator motion_it = mAnimationSources.find(source_id);
- return motion_it != mAnimationSources.end();
-}
-
-// 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);
- // Must find() after each erase() to deal with potential iterator invalidation
- // This also ensures that we don't go past the end of this source's animations
- // into those of another source.
- motion_it = mAnimationSources.find(source_id);
- }
-
-
- LLViewerObject* object = gObjectList.findObject(source_id);
- if (object)
- {
- object->setFlagsWithoutUpdate(FLAGS_ANIM_SOURCE, false);
- }
-}
-
-void LLVOAvatarSelf::setLocalTextureTE(U8 te, LLViewerTexture* image, U32 index)
-{
- if (te >= TEX_NUM_INDICES)
- {
- llassert(0);
- return;
- }
-
- if (getTEImage(te)->getID() == image->getID())
- {
- return;
- }
-
- if (isIndexBakedTexture((ETextureIndex)te))
- {
- llassert(0);
- return;
- }
-
- setTEImage(te, image);
-}
-
-//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 && imagep != tex)
- {
- setTEImage(te, imagep);
- removed = true;
- }
- }
- }
-
- if (removed)
- {
- for (U32 i = 0; i < mBakedTextureDatas.size(); i++)
- {
- LLViewerTexLayerSet *layerset = getTexLayerSet(i);
- layerset->setUpdatesEnabled(true);
- invalidateComposite(layerset);
- }
- updateMeshTextures();
- }
-}
-
-void LLVOAvatarSelf::onSimulatorFeaturesReceived(const LLUUID& region_id)
-{
- LL_INFOS("Avatar") << "simulator features received, setting hover based on region props" << LL_ENDL;
- setHoverIfRegionEnabled();
-}
-
-//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();
- //LL_INFOS() << "pos_from_old_region is " << global_pos_from_old_region
- // << " while pos_from_new_region is " << pos_from_new_region
- // << LL_ENDL;
-
- // Update hover height, or schedule callback, based on whether
- // it's supported in this region.
- if (regionp->simulatorFeaturesReceived())
- {
- setHoverIfRegionEnabled();
- }
- else
- {
- regionp->setSimulatorFeaturesReceivedCallback(boost::bind(&LLVOAvatarSelf::onSimulatorFeaturesReceived,this,_1));
- }
- }
-
- if (!regionp || (regionp->getHandle() != mLastRegionHandle))
- {
- if (mLastRegionHandle != 0)
- {
- ++mRegionCrossingCount;
- F64Seconds delta(mRegionCrossingTimer.getElapsedTimeF32());
- record(LLStatViewer::REGION_CROSSING_TIME, delta);
-
- // Diagnostics
- LL_INFOS() << "Region crossing took " << (F32)(delta * 1000.0).value() << " ms " << LL_ENDL;
- }
- if (regionp)
- {
- mLastRegionHandle = regionp->getHandle();
- }
- }
- mRegionCrossingTimer.reset();
- LLViewerObject::updateRegion(regionp);
-}
-
-//--------------------------------------------------------------------
-// draw tractor (selection) beam when editing objects
-//--------------------------------------------------------------------
-//virtual
-void LLVOAvatarSelf::idleUpdateTractorBeam()
-{
- // This is only done for yourself (maybe it should be in the agent?)
- if (!needsRenderBeam() || !isBuilt())
- {
- 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
- {
- const LLPickInfo& pick = gViewerWindow->getLastPick();
- mBeam->setPositionGlobal(pick.mPosGlobal);
- }
-
- }
- if (mBeamTimer.getElapsedTimeF32() > 0.25f)
- {
- mBeam->setColor(LLColor4U(gAgent.getEffectColor()));
- mBeam->setNeedsSendToSim(true);
- mBeamTimer.reset();
- }
- }
-}
-
-//-----------------------------------------------------------------------------
-// restoreMeshData()
-//-----------------------------------------------------------------------------
-// virtual
-void LLVOAvatarSelf::restoreMeshData()
-{
- //LL_INFOS() << "Restoring" << LL_ENDL;
- mMeshValid = true;
- updateJointLODs();
- updateAttachmentVisibility(gAgentCamera.getCameraMode());
-
- // force mesh update as LOD might not have changed to trigger this
- gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_GEOMETRY);
-}
-
-
-
-//-----------------------------------------------------------------------------
-// updateAttachmentVisibility()
-//-----------------------------------------------------------------------------
-void LLVOAvatarSelf::updateAttachmentVisibility(U32 camera_mode)
-{
- for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
- iter != mAttachmentPoints.end();
- ++iter)
- {
- LLViewerJointAttachment* attachment = iter->second;
- if (attachment->getIsHUDAttachment())
- {
- attachment->setAttachmentVisibility(true);
- }
- else
- {
- switch (camera_mode)
- {
- case CAMERA_MODE_MOUSELOOK:
- if (LLVOAvatar::sVisibleInFirstPerson && attachment->getVisibleInFirstPerson())
- {
- attachment->setAttachmentVisibility(true);
- }
- else
- {
- attachment->setAttachmentVisibility(false);
- }
- break;
- default:
- attachment->setAttachmentVisibility(true);
- break;
- }
- }
- }
-}
-
-//-----------------------------------------------------------------------------
-// updatedWearable( LLWearableType::EType type )
-// forces an update to any baked textures relevant to type.
-// will force an upload of the resulting bake if the second parameter is true
-//-----------------------------------------------------------------------------
-void LLVOAvatarSelf::wearableUpdated(LLWearableType::EType type)
-{
- for (LLAvatarAppearanceDictionary::BakedTextures::const_iterator baked_iter = sAvatarDictionary->getBakedTextures().begin();
- baked_iter != sAvatarDictionary->getBakedTextures().end();
- ++baked_iter)
- {
- const LLAvatarAppearanceDictionary::BakedEntry *baked_dict = baked_iter->second;
- const LLAvatarAppearanceDefines::EBakedTextureIndex index = baked_iter->first;
-
- if (baked_dict)
- {
- for (LLAvatarAppearanceDefines::wearables_vec_t::const_iterator type_iter = baked_dict->mWearables.begin();
- type_iter != baked_dict->mWearables.end();
- ++type_iter)
- {
- const LLWearableType::EType comp_type = *type_iter;
- if (comp_type == type)
- {
- LLViewerTexLayerSet *layerset = getLayerSet(index);
- if (layerset)
- {
- layerset->setUpdatesEnabled(true);
- invalidateComposite(layerset);
- }
- break;
- }
- }
- }
- }
-}
-
-//-----------------------------------------------------------------------------
-// isWearingAttachment()
-//-----------------------------------------------------------------------------
-bool LLVOAvatarSelf::isWearingAttachment(const LLUUID& inv_item_id) const
-{
- const LLUUID& base_inv_item_id = gInventory.getLinkedItemID(inv_item_id);
- for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin();
- iter != mAttachmentPoints.end();
- ++iter)
- {
- const LLViewerJointAttachment* attachment = iter->second;
- if (attachment->getAttachedObject(base_inv_item_id))
- {
- return true;
- }
- }
- return false;
-}
-
-//-----------------------------------------------------------------------------
-// getWornAttachment()
-//-----------------------------------------------------------------------------
-LLViewerObject* LLVOAvatarSelf::getWornAttachment(const LLUUID& inv_item_id)
-{
- const LLUUID& base_inv_item_id = gInventory.getLinkedItemID(inv_item_id);
- for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin();
- iter != mAttachmentPoints.end();
- ++iter)
- {
- LLViewerJointAttachment* attachment = iter->second;
- if (LLViewerObject *attached_object = attachment->getAttachedObject(base_inv_item_id))
- {
- return attached_object;
- }
- }
- return NULL;
-}
-
-bool LLVOAvatarSelf::getAttachedPointName(const LLUUID& inv_item_id, std::string& name) const
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
- if (!gInventory.getItem(inv_item_id))
- {
- name = "ATTACHMENT_MISSING_ITEM";
- return false;
- }
- const LLUUID& base_inv_item_id = gInventory.getLinkedItemID(inv_item_id);
- if (!gInventory.getItem(base_inv_item_id))
- {
- name = "ATTACHMENT_MISSING_BASE_ITEM";
- return false;
- }
- for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin();
- iter != mAttachmentPoints.end();
- ++iter)
- {
- const LLViewerJointAttachment* attachment = iter->second;
- if (attachment->getAttachedObject(base_inv_item_id))
- {
- name = attachment->getName();
- return true;
- }
- }
-
- name = "ATTACHMENT_NOT_ATTACHED";
- return false;
-}
-
-//virtual
-const LLViewerJointAttachment *LLVOAvatarSelf::attachObject(LLViewerObject *viewer_object)
-{
- const LLViewerJointAttachment *attachment = LLVOAvatar::attachObject(viewer_object);
- if (!attachment)
- {
- return 0;
- }
-
- updateAttachmentVisibility(gAgentCamera.getCameraMode());
-
- // Then make sure the inventory is in sync with the avatar.
-
- // Should just be the last object added
- if (attachment->isObjectAttached(viewer_object))
- {
- const LLUUID& attachment_id = viewer_object->getAttachmentItemID();
- LLAppearanceMgr::instance().registerAttachment(attachment_id);
- updateLODRiggedAttachments();
- }
-
- return attachment;
-}
-
-//virtual
-bool LLVOAvatarSelf::detachObject(LLViewerObject *viewer_object)
-{
- const LLUUID attachment_id = viewer_object->getAttachmentItemID();
- if ( LLVOAvatar::detachObject(viewer_object) )
- {
- // the simulator should automatically handle permission revocation
-
- stopMotionFromSource(attachment_id);
- LLFollowCamMgr::getInstance()->setCameraActive(viewer_object->getID(), false);
-
- LLViewerObject::const_child_list_t& child_list = viewer_object->getChildren();
- for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin();
- iter != child_list.end();
- ++iter)
- {
- LLViewerObject* child_objectp = *iter;
- // the simulator should automatically handle
- // permissions revocation
-
- stopMotionFromSource(child_objectp->getID());
- LLFollowCamMgr::getInstance()->setCameraActive(child_objectp->getID(), false);
- }
-
- // Make sure the inventory is in sync with the avatar.
-
- // Update COF contents, don't trigger appearance update.
- if (!isValid())
- {
- LL_INFOS() << "removeItemLinks skipped, avatar is under destruction" << LL_ENDL;
- }
- else
- {
- LLAppearanceMgr::instance().unregisterAttachment(attachment_id);
- }
-
- return true;
- }
- return false;
-}
-
-bool LLVOAvatarSelf::hasAttachmentsInTrash()
-{
- const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH);
-
- for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin(); iter != mAttachmentPoints.end(); ++iter)
- {
- LLViewerJointAttachment *attachment = iter->second;
- for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
- attachment_iter != attachment->mAttachedObjects.end();
- ++attachment_iter)
- {
- LLViewerObject *attached_object = attachment_iter->get();
- if (attached_object && gInventory.isObjectDescendentOf(attached_object->getAttachmentItemID(), trash_id))
- {
- return true;
- }
- }
- }
- return false;
-}
-
-// static
-bool LLVOAvatarSelf::detachAttachmentIntoInventory(const LLUUID &item_id)
-{
- LLInventoryItem* item = gInventory.getItem(item_id);
- if (item)
- {
- gMessageSystem->newMessageFast(_PREHASH_DetachAttachmentIntoInv);
- gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
- gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
- gMessageSystem->addUUIDFast(_PREHASH_ItemID, item_id);
- gMessageSystem->sendReliable(gAgent.getRegionHost());
-
- // This object might have been selected, so let the selection manager know it's gone now
- LLViewerObject *found_obj = gObjectList.findObject(item_id);
- if (found_obj)
- {
- LLSelectMgr::getInstance()->remove(found_obj);
- }
-
- // Error checking in case this object was attached to an invalid point
- // In that case, just remove the item from COF preemptively since detach
- // will fail.
- if (isAgentAvatarValid())
- {
- const LLViewerObject *attached_obj = gAgentAvatarp->getWornAttachment(item_id);
- if (!attached_obj)
- {
- LLAppearanceMgr::instance().removeCOFItemLinks(item_id);
- }
- }
- return true;
- }
- return false;
-}
-
-U32 LLVOAvatarSelf::getNumWearables(LLAvatarAppearanceDefines::ETextureIndex i) const
-{
- LLWearableType::EType type = sAvatarDictionary->getTEWearableType(i);
- return gAgentWearables.getWearableCount(type);
-}
-
-// virtual
-void LLVOAvatarSelf::localTextureLoaded(bool success, LLViewerFetchedTexture *src_vi, LLImageRaw* src_raw, LLImageRaw* aux_src, S32 discard_level, bool final, void* userdata)
-{
-
- const LLUUID& src_id = src_vi->getID();
- LLAvatarTexData *data = (LLAvatarTexData *)userdata;
- ETextureIndex index = data->mIndex;
- if (!isIndexLocalTexture(index)) return;
-
- LLLocalTextureObject *local_tex_obj = getLocalTextureObject(index, 0);
-
- // fix for EXT-268. Preventing using of NULL pointer
- if(NULL == local_tex_obj)
- {
- LL_WARNS("TAG") << "There is no Local Texture Object with index: " << index
- << ", final: " << final
- << LL_ENDL;
- return;
- }
- if (success)
- {
- if (!local_tex_obj->getBakedReady() &&
- local_tex_obj->getImage() != NULL &&
- (local_tex_obj->getID() == src_id) &&
- discard_level < local_tex_obj->getDiscard())
- {
- local_tex_obj->setDiscard(discard_level);
- requestLayerSetUpdate(index);
- if (isEditingAppearance())
- {
- LLVisualParamHint::requestHintUpdates();
- }
- updateMeshTextures();
- }
- }
- else if (final)
- {
- // Failed: asset is missing
- if (!local_tex_obj->getBakedReady() &&
- local_tex_obj->getImage() != NULL &&
- local_tex_obj->getImage()->getID() == src_id)
- {
- local_tex_obj->setDiscard(0);
- requestLayerSetUpdate(index);
- updateMeshTextures();
- }
- }
-}
-
-// virtual
-bool LLVOAvatarSelf::getLocalTextureGL(ETextureIndex type, LLViewerTexture** tex_pp, U32 index) const
-{
- *tex_pp = NULL;
-
- if (!isIndexLocalTexture(type)) return false;
- if (getLocalTextureID(type, index) == IMG_DEFAULT_AVATAR) return true;
-
- const LLLocalTextureObject *local_tex_obj = getLocalTextureObject(type, index);
- if (!local_tex_obj)
- {
- return false;
- }
- *tex_pp = dynamic_cast<LLViewerTexture*> (local_tex_obj->getImage());
- return true;
-}
-
-LLViewerFetchedTexture* LLVOAvatarSelf::getLocalTextureGL(LLAvatarAppearanceDefines::ETextureIndex type, U32 index) const
-{
- if (!isIndexLocalTexture(type))
- {
- return NULL;
- }
-
- const LLLocalTextureObject *local_tex_obj = getLocalTextureObject(type, index);
- if (!local_tex_obj)
- {
- return NULL;
- }
- if (local_tex_obj->getID() == IMG_DEFAULT_AVATAR)
- {
- return LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT_AVATAR);
- }
- return dynamic_cast<LLViewerFetchedTexture*> (local_tex_obj->getImage());
-}
-
-const LLUUID& LLVOAvatarSelf::getLocalTextureID(ETextureIndex type, U32 index) const
-{
- if (!isIndexLocalTexture(type)) return IMG_DEFAULT_AVATAR;
-
- const LLLocalTextureObject *local_tex_obj = getLocalTextureObject(type, index);
- if (local_tex_obj && local_tex_obj->getImage() != NULL)
- {
- return local_tex_obj->getImage()->getID();
- }
- return IMG_DEFAULT_AVATAR;
-}
-
-
-//-----------------------------------------------------------------------------
-// isLocalTextureDataAvailable()
-// Returns true if at least the lowest quality discard level exists for every texture
-// in the layerset.
-//-----------------------------------------------------------------------------
-bool LLVOAvatarSelf::isLocalTextureDataAvailable(const LLViewerTexLayerSet* layerset) const
-{
- /* if (layerset == mBakedTextureDatas[BAKED_HEAD].mTexLayerSet)
- return getLocalDiscardLevel(TEX_HEAD_BODYPAINT) >= 0; */
- for (LLAvatarAppearanceDictionary::BakedTextures::const_iterator baked_iter = sAvatarDictionary->getBakedTextures().begin();
- baked_iter != sAvatarDictionary->getBakedTextures().end();
- ++baked_iter)
- {
- const EBakedTextureIndex baked_index = baked_iter->first;
- if (layerset == mBakedTextureDatas[baked_index].mTexLayerSet)
- {
- bool ret = true;
- const LLAvatarAppearanceDictionary::BakedEntry *baked_dict = baked_iter->second;
- for (texture_vec_t::const_iterator local_tex_iter = baked_dict->mLocalTextures.begin();
- local_tex_iter != baked_dict->mLocalTextures.end();
- ++local_tex_iter)
- {
- const ETextureIndex tex_index = *local_tex_iter;
- const LLWearableType::EType wearable_type = sAvatarDictionary->getTEWearableType(tex_index);
- const U32 wearable_count = gAgentWearables.getWearableCount(wearable_type);
- for (U32 wearable_index = 0; wearable_index < wearable_count; wearable_index++)
- {
- bool tex_avail = (getLocalDiscardLevel(tex_index, wearable_index) >= 0);
- ret &= tex_avail;
- }
- }
- return ret;
- }
- }
- llassert(0);
- return false;
-}
-
-//-----------------------------------------------------------------------------
-// virtual
-// isLocalTextureDataFinal()
-// Returns true if the highest quality discard level exists for every texture
-// in the layerset.
-//-----------------------------------------------------------------------------
-bool LLVOAvatarSelf::isLocalTextureDataFinal(const LLViewerTexLayerSet* layerset) const
-{
- const U32 desired_tex_discard_level = gSavedSettings.getU32("TextureDiscardLevel");
- // const U32 desired_tex_discard_level = 0; // hack to not bake textures on lower discard levels.
-
- for (U32 i = 0; i < mBakedTextureDatas.size(); i++)
- {
- if (layerset == mBakedTextureDatas[i].mTexLayerSet)
- {
- const LLAvatarAppearanceDictionary::BakedEntry *baked_dict = sAvatarDictionary->getBakedTexture((EBakedTextureIndex)i);
- for (texture_vec_t::const_iterator local_tex_iter = baked_dict->mLocalTextures.begin();
- local_tex_iter != baked_dict->mLocalTextures.end();
- ++local_tex_iter)
- {
- const ETextureIndex tex_index = *local_tex_iter;
- const LLWearableType::EType wearable_type = sAvatarDictionary->getTEWearableType(tex_index);
- const U32 wearable_count = gAgentWearables.getWearableCount(wearable_type);
- for (U32 wearable_index = 0; wearable_index < wearable_count; wearable_index++)
- {
- S32 local_discard_level = getLocalDiscardLevel(*local_tex_iter, wearable_index);
- if ((local_discard_level > (S32)(desired_tex_discard_level)) ||
- (local_discard_level < 0 ))
- {
- return false;
- }
- }
- }
- return true;
- }
- }
- llassert(0);
- return false;
-}
-
-
-bool LLVOAvatarSelf::isAllLocalTextureDataFinal() const
-{
- const U32 desired_tex_discard_level = gSavedSettings.getU32("TextureDiscardLevel");
- // const U32 desired_tex_discard_level = 0; // hack to not bake textures on lower discard levels
-
- for (U32 i = 0; i < mBakedTextureDatas.size(); i++)
- {
- const LLAvatarAppearanceDictionary::BakedEntry *baked_dict = sAvatarDictionary->getBakedTexture((EBakedTextureIndex)i);
- for (texture_vec_t::const_iterator local_tex_iter = baked_dict->mLocalTextures.begin();
- local_tex_iter != baked_dict->mLocalTextures.end();
- ++local_tex_iter)
- {
- const ETextureIndex tex_index = *local_tex_iter;
- const LLWearableType::EType wearable_type = sAvatarDictionary->getTEWearableType(tex_index);
- const U32 wearable_count = gAgentWearables.getWearableCount(wearable_type);
- for (U32 wearable_index = 0; wearable_index < wearable_count; wearable_index++)
- {
- S32 local_discard_level = getLocalDiscardLevel(*local_tex_iter, wearable_index);
- if ((local_discard_level > (S32)(desired_tex_discard_level)) ||
- (local_discard_level < 0 ))
- {
- return false;
- }
- }
- }
- }
- return true;
-}
-
-bool LLVOAvatarSelf::isTextureDefined(LLAvatarAppearanceDefines::ETextureIndex type, U32 index) const
-{
- LLUUID id;
- bool isDefined = true;
- if (isIndexLocalTexture(type))
- {
- const LLWearableType::EType wearable_type = sAvatarDictionary->getTEWearableType(type);
- const U32 wearable_count = gAgentWearables.getWearableCount(wearable_type);
- if (index >= wearable_count)
- {
- // invalid index passed in. check all textures of a given type
- for (U32 wearable_index = 0; wearable_index < wearable_count; wearable_index++)
- {
- id = getLocalTextureID(type, wearable_index);
- isDefined &= (id != IMG_DEFAULT_AVATAR && id != IMG_DEFAULT);
- }
- }
- else
- {
- id = getLocalTextureID(type, index);
- isDefined &= (id != IMG_DEFAULT_AVATAR && id != IMG_DEFAULT);
- }
- }
- else
- {
- id = getTEImage(type)->getID();
- isDefined &= (id != IMG_DEFAULT_AVATAR && id != IMG_DEFAULT);
- }
-
- return isDefined;
-}
-
-//virtual
-bool LLVOAvatarSelf::isTextureVisible(LLAvatarAppearanceDefines::ETextureIndex type, U32 index) const
-{
- if (isIndexBakedTexture(type))
- {
- return LLVOAvatar::isTextureVisible(type, (U32)0);
- }
-
- LLUUID tex_id = getLocalTextureID(type,index);
- return (tex_id != IMG_INVISIBLE)
- || (LLDrawPoolAlpha::sShowDebugAlpha);
-}
-
-//virtual
-bool LLVOAvatarSelf::isTextureVisible(LLAvatarAppearanceDefines::ETextureIndex type, LLViewerWearable *wearable) const
-{
- if (isIndexBakedTexture(type))
- {
- return LLVOAvatar::isTextureVisible(type);
- }
-
- U32 index;
- if (gAgentWearables.getWearableIndex(wearable,index))
- {
- return isTextureVisible(type,index);
- }
- else
- {
- LL_WARNS() << "Wearable not found" << LL_ENDL;
- return false;
- }
-}
-
-bool LLVOAvatarSelf::areTexturesCurrent() const
-{
- return gAgentWearables.areWearablesLoaded();
-}
-
-void LLVOAvatarSelf::invalidateComposite( LLTexLayerSet* layerset)
-{
- LLViewerTexLayerSet *layer_set = dynamic_cast<LLViewerTexLayerSet*>(layerset);
- if( !layer_set || !layer_set->getUpdatesEnabled() )
- {
- return;
- }
- // LL_INFOS() << "LLVOAvatar::invalidComposite() " << layerset->getBodyRegionName() << LL_ENDL;
-
- layer_set->requestUpdate();
- layer_set->invalidateMorphMasks();
-}
-
-void LLVOAvatarSelf::invalidateAll()
-{
- for (U32 i = 0; i < mBakedTextureDatas.size(); i++)
- {
- LLViewerTexLayerSet *layerset = getTexLayerSet(i);
- invalidateComposite(layerset);
- }
- //mDebugSelfLoadTimer.reset();
-}
-
-//-----------------------------------------------------------------------------
-// setCompositeUpdatesEnabled()
-//-----------------------------------------------------------------------------
-void LLVOAvatarSelf::setCompositeUpdatesEnabled( bool b )
-{
- for (U32 i = 0; i < mBakedTextureDatas.size(); i++)
- {
- setCompositeUpdatesEnabled(i, b);
- }
-}
-
-void LLVOAvatarSelf::setCompositeUpdatesEnabled(U32 index, bool b)
-{
- LLViewerTexLayerSet *layerset = getTexLayerSet(index);
- if (layerset )
- {
- layerset->setUpdatesEnabled( b );
- }
-}
-
-bool LLVOAvatarSelf::isCompositeUpdateEnabled(U32 index)
-{
- LLViewerTexLayerSet *layerset = getTexLayerSet(index);
- if (layerset)
- {
- return layerset->getUpdatesEnabled();
- }
- return false;
-}
-
-void LLVOAvatarSelf::setupComposites()
-{
- for (U32 i = 0; i < mBakedTextureDatas.size(); i++)
- {
- ETextureIndex tex_index = mBakedTextureDatas[i].mTextureIndex;
- bool layer_baked = isTextureDefined(tex_index, gAgentWearables.getWearableCount(tex_index));
- LLViewerTexLayerSet *layerset = getTexLayerSet(i);
- if (layerset)
- {
- layerset->setUpdatesEnabled(!layer_baked);
- }
- }
-}
-
-void LLVOAvatarSelf::updateComposites()
-{
- for (U32 i = 0; i < mBakedTextureDatas.size(); i++)
- {
- LLViewerTexLayerSet *layerset = getTexLayerSet(i);
- if (layerset
- && ((i != BAKED_SKIRT) || isWearingWearableType(LLWearableType::WT_SKIRT)))
- {
- layerset->updateComposite();
- }
- }
-}
-
-// virtual
-S32 LLVOAvatarSelf::getLocalDiscardLevel(ETextureIndex type, U32 wearable_index) const
-{
- if (!isIndexLocalTexture(type)) return false;
-
- const LLLocalTextureObject *local_tex_obj = getLocalTextureObject(type, wearable_index);
- if (local_tex_obj)
- {
- const LLViewerFetchedTexture* image = dynamic_cast<LLViewerFetchedTexture*>( local_tex_obj->getImage() );
- if (type >= 0
- && local_tex_obj->getID() != IMG_DEFAULT_AVATAR
- && !image->isMissingAsset())
- {
- return image->getDiscardLevel();
- }
- else
- {
- // We don't care about this (no image associated with the layer) treat as fully loaded.
- return 0;
- }
- }
- return 0;
-}
-
-// virtual
-// Counts the memory footprint of local textures.
-void LLVOAvatarSelf::getLocalTextureByteCount(S32* gl_bytes) const
-{
- *gl_bytes = 0;
- for (S32 type = 0; type < TEX_NUM_INDICES; type++)
- {
- if (!isIndexLocalTexture((ETextureIndex)type)) continue;
- U32 max_tex = getNumWearables((ETextureIndex) type);
- for (U32 num = 0; num < max_tex; num++)
- {
- const LLLocalTextureObject *local_tex_obj = getLocalTextureObject((ETextureIndex) type, num);
- if (local_tex_obj)
- {
- const LLViewerFetchedTexture* image_gl = dynamic_cast<LLViewerFetchedTexture*>( local_tex_obj->getImage() );
- if (image_gl)
- {
- S32 bytes = (S32)image_gl->getWidth() * image_gl->getHeight() * image_gl->getComponents();
-
- if (image_gl->hasGLTexture())
- {
- *gl_bytes += bytes;
- }
- }
- }
- }
- }
-}
-
-// virtual
-void LLVOAvatarSelf::setLocalTexture(ETextureIndex type, LLViewerTexture* src_tex, bool baked_version_ready, U32 index)
-{
- if (!isIndexLocalTexture(type)) return;
-
- LLViewerFetchedTexture* tex = LLViewerTextureManager::staticCastToFetchedTexture(src_tex, true) ;
- if(!tex)
- {
- return ;
- }
-
- S32 desired_discard = isSelf() ? 0 : 2;
- LLLocalTextureObject *local_tex_obj = getLocalTextureObject(type,index);
- if (!local_tex_obj)
- {
- if (type >= TEX_NUM_INDICES)
- {
- LL_ERRS() << "Tried to set local texture with invalid type: (" << (U32) type << ", " << index << ")" << LL_ENDL;
- return;
- }
- LLWearableType::EType wearable_type = sAvatarDictionary->getTEWearableType(type);
- if (!gAgentWearables.getViewerWearable(wearable_type,index))
- {
- // no wearable is loaded, cannot set the texture.
- return;
- }
- gAgentWearables.addLocalTextureObject(wearable_type,type,index);
- local_tex_obj = getLocalTextureObject(type,index);
- if (!local_tex_obj)
- {
- LL_ERRS() << "Unable to create LocalTextureObject for wearable type & index: (" << (U32) wearable_type << ", " << index << ")" << LL_ENDL;
- return;
- }
-
- LLViewerTexLayerSet *layer_set = getLayerSet(type);
- if (layer_set)
- {
- layer_set->cloneTemplates(local_tex_obj, type, gAgentWearables.getViewerWearable(wearable_type,index));
- }
-
- }
- if (!baked_version_ready)
- {
- if (tex != local_tex_obj->getImage() || local_tex_obj->getBakedReady())
- {
- local_tex_obj->setDiscard(MAX_DISCARD_LEVEL+1);
- }
- if (tex->getID() != IMG_DEFAULT_AVATAR)
- {
- if (local_tex_obj->getDiscard() > desired_discard)
- {
- S32 tex_discard = tex->getDiscardLevel();
- if (tex_discard >= 0 && tex_discard <= desired_discard)
- {
- local_tex_obj->setDiscard(tex_discard);
- if (isSelf())
- {
- requestLayerSetUpdate(type);
- if (isEditingAppearance())
- {
- LLVisualParamHint::requestHintUpdates();
- }
- }
- }
- else
- {
- tex->setLoadedCallback(onLocalTextureLoaded, desired_discard, true, false, new LLAvatarTexData(getID(), type), NULL);
- }
- }
- tex->setMinDiscardLevel(desired_discard);
- }
- }
- local_tex_obj->setImage(tex);
- local_tex_obj->setID(tex->getID());
- setBakedReady(type,baked_version_ready,index);
-}
-
-//virtual
-void LLVOAvatarSelf::setBakedReady(LLAvatarAppearanceDefines::ETextureIndex type, bool baked_version_exists, U32 index)
-{
- if (!isIndexLocalTexture(type)) return;
- LLLocalTextureObject *local_tex_obj = getLocalTextureObject(type,index);
- if (local_tex_obj)
- {
- local_tex_obj->setBakedReady( baked_version_exists );
- }
-}
-
-
-// virtual
-void LLVOAvatarSelf::dumpLocalTextures() const
-{
- LL_INFOS() << "Local Textures:" << LL_ENDL;
-
- /* ETextureIndex baked_equiv[] = {
- TEX_UPPER_BAKED,
- if (isTextureDefined(baked_equiv[i])) */
- for (LLAvatarAppearanceDictionary::Textures::const_iterator iter = sAvatarDictionary->getTextures().begin();
- iter != sAvatarDictionary->getTextures().end();
- ++iter)
- {
- const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = iter->second;
- if (!texture_dict->mIsLocalTexture || !texture_dict->mIsUsedByBakedTexture)
- continue;
-
- const EBakedTextureIndex baked_index = texture_dict->mBakedTextureIndex;
- const ETextureIndex baked_equiv = sAvatarDictionary->getBakedTexture(baked_index)->mTextureIndex;
-
- const std::string &name = texture_dict->mName;
- const LLLocalTextureObject *local_tex_obj = getLocalTextureObject(iter->first, 0);
- // index is baked texture - index is not relevant. putting in 0 as placeholder
- if (isTextureDefined(baked_equiv, 0))
- {
-#if LL_RELEASE_FOR_DOWNLOAD
- // End users don't get to trivially see avatar texture IDs, makes textures
- // easier to steal. JC
- LL_INFOS() << "LocTex " << name << ": Baked " << LL_ENDL;
-#else
- LL_INFOS() << "LocTex " << name << ": Baked " << getTEImage(baked_equiv)->getID() << LL_ENDL;
-#endif
- }
- else if (local_tex_obj && local_tex_obj->getImage() != NULL)
- {
- if (local_tex_obj->getImage()->getID() == IMG_DEFAULT_AVATAR)
- {
- LL_INFOS() << "LocTex " << name << ": None" << LL_ENDL;
- }
- else
- {
- LLViewerFetchedTexture* image = dynamic_cast<LLViewerFetchedTexture*>( local_tex_obj->getImage() );
-
- LL_INFOS() << "LocTex " << name << ": "
- << "Discard " << image->getDiscardLevel() << ", "
- << "(" << image->getWidth() << ", " << image->getHeight() << ") "
-#if !LL_RELEASE_FOR_DOWNLOAD
- // End users don't get to trivially see avatar texture IDs,
- // makes textures easier to steal
- << image->getID() << " "
-#endif
- << "Priority: " << image->getMaxVirtualSize()
- << LL_ENDL;
- }
- }
- else
- {
- LL_INFOS() << "LocTex " << name << ": No LLViewerTexture" << LL_ENDL;
- }
- }
-}
-
-//-----------------------------------------------------------------------------
-// static
-// onLocalTextureLoaded()
-//-----------------------------------------------------------------------------
-
-void LLVOAvatarSelf::onLocalTextureLoaded(bool success, LLViewerFetchedTexture *src_vi, LLImageRaw* src_raw, LLImageRaw* aux_src, S32 discard_level, bool final, void* userdata)
-{
- LLAvatarTexData *data = (LLAvatarTexData *)userdata;
- LLVOAvatarSelf *self = (LLVOAvatarSelf *)gObjectList.findObject(data->mAvatarID);
- if (self)
- {
- // We should only be handling local textures for ourself
- self->localTextureLoaded(success, src_vi, src_raw, aux_src, discard_level, final, userdata);
- }
- // ensure data is cleaned up
- if (final || !success)
- {
- delete data;
- }
-}
-
-/*virtual*/ void LLVOAvatarSelf::setImage(const U8 te, LLViewerTexture *imagep, const U32 index)
-{
- if (isIndexLocalTexture((ETextureIndex)te))
- {
- setLocalTexture((ETextureIndex)te, imagep, false ,index);
- }
- else
- {
- setTEImage(te,imagep);
- }
-}
-
-/*virtual*/ LLViewerTexture* LLVOAvatarSelf::getImage(const U8 te, const U32 index) const
-{
- if (isIndexLocalTexture((ETextureIndex)te))
- {
- return getLocalTextureGL((ETextureIndex)te,index);
- }
- else
- {
- return getTEImage(te);
- }
-}
-
-
-// static
-void LLVOAvatarSelf::dumpTotalLocalTextureByteCount()
-{
- S32 gl_bytes = 0;
- gAgentAvatarp->getLocalTextureByteCount(&gl_bytes);
- LL_INFOS() << "Total Avatar LocTex GL:" << (gl_bytes/1024) << "KB" << LL_ENDL;
-}
-
-bool LLVOAvatarSelf::getIsCloud() const
-{
- // Let people know why they're clouded without spamming them into oblivion.
- bool do_warn = false;
- static LLTimer time_since_notice;
- F32 update_freq = 30.0;
- if (time_since_notice.getElapsedTimeF32() > update_freq)
- {
- time_since_notice.reset();
- do_warn = true;
- }
-
- // do we have our body parts?
- S32 shape_count = gAgentWearables.getWearableCount(LLWearableType::WT_SHAPE);
- S32 hair_count = gAgentWearables.getWearableCount(LLWearableType::WT_HAIR);
- S32 eye_count = gAgentWearables.getWearableCount(LLWearableType::WT_EYES);
- S32 skin_count = gAgentWearables.getWearableCount(LLWearableType::WT_SKIN);
- if (!shape_count || !hair_count || !eye_count || !skin_count)
- {
- if (do_warn)
- {
- LL_INFOS() << "Self is clouded due to missing one or more required body parts: "
- << (shape_count ? "" : "SHAPE ")
- << (hair_count ? "" : "HAIR ")
- << (eye_count ? "" : "EYES ")
- << (skin_count ? "" : "SKIN ")
- << LL_ENDL;
- }
- return true;
- }
-
- if (!isTextureDefined(TEX_HAIR, 0))
- {
- if (do_warn)
- {
- LL_INFOS() << "Self is clouded because of no hair texture" << LL_ENDL;
- }
- return true;
- }
-
- if (!mPreviousFullyLoaded)
- {
- if (!isLocalTextureDataAvailable(getLayerSet(BAKED_LOWER)) &&
- (!isTextureDefined(TEX_LOWER_BAKED, 0)))
- {
- if (do_warn)
- {
- LL_INFOS() << "Self is clouded because lower textures not baked" << LL_ENDL;
- }
- return true;
- }
-
- if (!isLocalTextureDataAvailable(getLayerSet(BAKED_UPPER)) &&
- (!isTextureDefined(TEX_UPPER_BAKED, 0)))
- {
- if (do_warn)
- {
- LL_INFOS() << "Self is clouded because upper textures not baked" << LL_ENDL;
- }
- return true;
- }
-
- for (U32 i = 0; i < mBakedTextureDatas.size(); i++)
- {
- if (i == BAKED_SKIRT && !isWearingWearableType(LLWearableType::WT_SKIRT))
- continue;
-
- const BakedTextureData& texture_data = mBakedTextureDatas[i];
- if (!isTextureDefined(texture_data.mTextureIndex, 0))
- continue;
-
- // Check for the case that texture is defined but not sufficiently loaded to display anything.
- const LLViewerTexture* baked_img = getImage( texture_data.mTextureIndex, 0 );
- if (!baked_img || !baked_img->hasGLTexture())
- {
- if (do_warn)
- {
- LL_INFOS() << "Self is clouded because texture at index " << i
- << " (texture index is " << texture_data.mTextureIndex << ") is not loaded" << LL_ENDL;
- }
- return true;
- }
- }
-
- LL_DEBUGS() << "Avatar de-clouded" << LL_ENDL;
- }
- return false;
-}
-
-/*static*/
-void LLVOAvatarSelf::debugOnTimingLocalTexLoaded(bool success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, bool final, void* userdata)
-{
- if (gAgentAvatarp.notNull())
- {
- gAgentAvatarp->debugTimingLocalTexLoaded(success, src_vi, src, aux_src, discard_level, final, userdata);
- }
-}
-
-void LLVOAvatarSelf::debugTimingLocalTexLoaded(bool success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, bool final, void* userdata)
-{
- LLAvatarTexData *data = (LLAvatarTexData *)userdata;
- if (!data)
- {
- return;
- }
-
- ETextureIndex index = data->mIndex;
-
- if (index < 0 || index >= TEX_NUM_INDICES)
- {
- return;
- }
-
- if (discard_level >=0 && discard_level <= MAX_DISCARD_LEVEL) // ignore discard level -1, as it means we have no data.
- {
- mDebugTextureLoadTimes[(U32)index][(U32)discard_level] = mDebugSelfLoadTimer.getElapsedTimeF32();
- }
- if (final)
- {
- delete data;
- }
-}
-
-void LLVOAvatarSelf::debugBakedTextureUpload(EBakedTextureIndex index, bool finished)
-{
- U32 done = 0;
- if (finished)
- {
- done = 1;
- }
- mDebugBakedTextureTimes[index][done] = mDebugSelfLoadTimer.getElapsedTimeF32();
-}
-
-const std::string LLVOAvatarSelf::verboseDebugDumpLocalTextureDataInfo(const LLViewerTexLayerSet* layerset) const
-{
- std::ostringstream outbuf;
- LLWearableType *wr_inst = LLWearableType::getInstance();
- for (LLAvatarAppearanceDictionary::BakedTextures::const_iterator baked_iter =
- sAvatarDictionary->getBakedTextures().begin();
- baked_iter != sAvatarDictionary->getBakedTextures().end();
- ++baked_iter)
- {
- const EBakedTextureIndex baked_index = baked_iter->first;
- if (layerset == mBakedTextureDatas[baked_index].mTexLayerSet)
- {
- outbuf << "baked_index: " << baked_index << "\n";
- const LLAvatarAppearanceDictionary::BakedEntry *baked_dict = baked_iter->second;
- for (texture_vec_t::const_iterator local_tex_iter = baked_dict->mLocalTextures.begin();
- local_tex_iter != baked_dict->mLocalTextures.end();
- ++local_tex_iter)
- {
- const ETextureIndex tex_index = *local_tex_iter;
- const std::string tex_name = sAvatarDictionary->getTexture(tex_index)->mName;
- outbuf << " tex_index " << (S32) tex_index << " name " << tex_name << "\n";
- const LLWearableType::EType wearable_type = sAvatarDictionary->getTEWearableType(tex_index);
- const U32 wearable_count = gAgentWearables.getWearableCount(wearable_type);
- if (wearable_count > 0)
- {
- for (U32 wearable_index = 0; wearable_index < wearable_count; wearable_index++)
- {
- outbuf << " " << wr_inst->getTypeName(wearable_type) << " " << wearable_index << ":";
- const LLLocalTextureObject *local_tex_obj = getLocalTextureObject(tex_index, wearable_index);
- if (local_tex_obj)
- {
- LLViewerFetchedTexture* image = dynamic_cast<LLViewerFetchedTexture*>( local_tex_obj->getImage() );
- if (tex_index >= 0
- && local_tex_obj->getID() != IMG_DEFAULT_AVATAR
- && !image->isMissingAsset())
- {
- outbuf << " id: " << image->getID()
- << " refs: " << image->getNumRefs()
- << " glocdisc: " << getLocalDiscardLevel(tex_index, wearable_index)
- << " discard: " << image->getDiscardLevel()
- << " desired: " << image->getDesiredDiscardLevel()
- << " vsize: " << image->getMaxVirtualSize()
- << " ts: " << image->getTextureState()
- << " bl: " << image->getBoostLevel()
- << " fl: " << image->isFullyLoaded() // this is not an accessor for mFullyLoaded - see comment there.
- << " cl: " << (image->isFullyLoaded() && image->getDiscardLevel()==0) // "completely loaded"
- << " mvs: " << image->getMaxVirtualSize()
- << " mvsc: " << image->getMaxVirtualSizeResetCounter()
- << " mem: " << image->getTextureMemory();
- }
- }
- outbuf << "\n";
- }
- }
- }
- break;
- }
- }
- return outbuf.str();
-}
-
-void LLVOAvatarSelf::dumpAllTextures() const
-{
- std::string vd_text = "Local textures per baked index and wearable:\n";
- for (LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary::BakedTextures::const_iterator baked_iter = sAvatarDictionary->getBakedTextures().begin();
- baked_iter != sAvatarDictionary->getBakedTextures().end();
- ++baked_iter)
- {
- const LLAvatarAppearanceDefines::EBakedTextureIndex baked_index = baked_iter->first;
- const LLViewerTexLayerSet *layerset = debugGetLayerSet(baked_index);
- if (!layerset) continue;
- const LLViewerTexLayerSetBuffer *layerset_buffer = layerset->getViewerComposite();
- if (!layerset_buffer) continue;
- vd_text += verboseDebugDumpLocalTextureDataInfo(layerset);
- }
- LL_DEBUGS("Avatar") << vd_text << LL_ENDL;
-}
-
-const std::string LLVOAvatarSelf::debugDumpLocalTextureDataInfo(const LLViewerTexLayerSet* layerset) const
-{
- std::string text="";
- LLWearableType *wr_inst = LLWearableType::getInstance();
-
- text = llformat("[Final:%d Avail:%d] ",isLocalTextureDataFinal(layerset), isLocalTextureDataAvailable(layerset));
-
- /* if (layerset == mBakedTextureDatas[BAKED_HEAD].mTexLayerSet)
- return getLocalDiscardLevel(TEX_HEAD_BODYPAINT) >= 0; */
- for (LLAvatarAppearanceDictionary::BakedTextures::const_iterator baked_iter = sAvatarDictionary->getBakedTextures().begin();
- baked_iter != sAvatarDictionary->getBakedTextures().end();
- ++baked_iter)
- {
- const EBakedTextureIndex baked_index = baked_iter->first;
- if (layerset == mBakedTextureDatas[baked_index].mTexLayerSet)
- {
- const LLAvatarAppearanceDictionary::BakedEntry *baked_dict = baked_iter->second;
- text += llformat("%d-%s ( ",baked_index, baked_dict->mName.c_str());
- for (texture_vec_t::const_iterator local_tex_iter = baked_dict->mLocalTextures.begin();
- local_tex_iter != baked_dict->mLocalTextures.end();
- ++local_tex_iter)
- {
- const ETextureIndex tex_index = *local_tex_iter;
- const LLWearableType::EType wearable_type = sAvatarDictionary->getTEWearableType(tex_index);
- const U32 wearable_count = gAgentWearables.getWearableCount(wearable_type);
- if (wearable_count > 0)
- {
- text += wr_inst->getTypeName(wearable_type) + ":";
- for (U32 wearable_index = 0; wearable_index < wearable_count; wearable_index++)
- {
- const U32 discard_level = getLocalDiscardLevel(tex_index, wearable_index);
- std::string discard_str = llformat("%d ",discard_level);
- text += llformat("%d ",discard_level);
- }
- }
- }
- text += ")";
- break;
- }
- }
- return text;
-}
-
-const std::string LLVOAvatarSelf::debugDumpAllLocalTextureDataInfo() const
-{
- std::string text;
- const U32 override_tex_discard_level = gSavedSettings.getU32("TextureDiscardLevel");
-
- for (U32 i = 0; i < mBakedTextureDatas.size(); i++)
- {
- const LLAvatarAppearanceDictionary::BakedEntry *baked_dict = sAvatarDictionary->getBakedTexture((EBakedTextureIndex)i);
- bool is_texture_final = true;
- for (texture_vec_t::const_iterator local_tex_iter = baked_dict->mLocalTextures.begin();
- local_tex_iter != baked_dict->mLocalTextures.end();
- ++local_tex_iter)
- {
- const ETextureIndex tex_index = *local_tex_iter;
- const LLWearableType::EType wearable_type = sAvatarDictionary->getTEWearableType(tex_index);
- const U32 wearable_count = gAgentWearables.getWearableCount(wearable_type);
- for (U32 wearable_index = 0; wearable_index < wearable_count; wearable_index++)
- {
- is_texture_final &= (getLocalDiscardLevel(*local_tex_iter, wearable_index) <= (S32)(override_tex_discard_level));
- }
- }
- text += llformat("%s:%d ",baked_dict->mName.c_str(),is_texture_final);
- }
- return text;
-}
-
-void LLVOAvatarSelf::appearanceChangeMetricsCoro(std::string url)
-{
- LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
- LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
- httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("appearanceChangeMetrics", httpPolicy));
- LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
- LLCore::HttpOptions::ptr_t httpOpts = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions);
-
- S32 currentSequence = mMetricSequence;
- if (S32_MAX == ++mMetricSequence)
- mMetricSequence = 0;
-
- LLSD msg;
- msg["message"] = "ViewerAppearanceChangeMetrics";
- msg["session_id"] = gAgentSessionID;
- msg["agent_id"] = gAgentID;
- msg["sequence"] = currentSequence;
- msg["initial"] = mInitialMetric;
- msg["break"] = false;
- msg["duration"] = mTimeSinceLastRezMessage.getElapsedTimeF32();
-
- // Status of our own rezzing.
- msg["rez_status"] = LLVOAvatar::rezStatusToString(getRezzedStatus());
- msg["first_decloud_time"] = getFirstDecloudTime();
-
- // Status of all nearby avs including ourself.
- msg["nearby"] = LLSD::emptyArray();
- std::vector<S32> rez_counts;
- F32 avg_time;
- S32 total_cloud_avatars;
- LLVOAvatar::getNearbyRezzedStats(rez_counts, avg_time, total_cloud_avatars);
- for (S32 rez_stat = 0; rez_stat < rez_counts.size(); ++rez_stat)
- {
- std::string rez_status_name = LLVOAvatar::rezStatusToString(rez_stat);
- msg["nearby"][rez_status_name] = rez_counts[rez_stat];
- }
- msg["nearby"]["avg_decloud_time"] = avg_time;
- msg["nearby"]["cloud_total"] = total_cloud_avatars;
-
- // std::vector<std::string> bucket_fields("timer_name","is_self","grid_x","grid_y","is_using_server_bake");
- std::vector<std::string> by_fields;
- by_fields.push_back("timer_name");
- by_fields.push_back("completed");
- by_fields.push_back("grid_x");
- by_fields.push_back("grid_y");
- by_fields.push_back("is_using_server_bakes");
- by_fields.push_back("is_self");
- by_fields.push_back("central_bake_version");
- LLSD summary = summarize_by_buckets(mPendingTimerRecords, by_fields, std::string("elapsed"));
- msg["timers"] = summary;
-
- mPendingTimerRecords.clear();
-
- LL_DEBUGS("Avatar") << avString() << "message: " << ll_pretty_print_sd(msg) << LL_ENDL;
-
- gPendingMetricsUploads++;
-
- LLSD result = httpAdapter->postAndSuspend(httpRequest, url, msg);
-
- LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
- LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
-
- gPendingMetricsUploads--;
-
- if (!status)
- {
- LL_WARNS("Avatar") << "Unable to upload statistics" << LL_ENDL;
- return;
- }
- else
- {
- LL_INFOS("Avatar") << "Statistics upload OK" << LL_ENDL;
- mInitialMetric = false;
- }
-}
-
-bool LLVOAvatarSelf::updateAvatarRezMetrics(bool force_send)
-{
- const F32 AV_METRICS_INTERVAL_QA = 30.0;
- F32 send_period = 300.0;
-
- static LLCachedControl<bool> qa_mode_metrics(gSavedSettings,"QAModeMetrics");
- if (qa_mode_metrics)
- {
- send_period = AV_METRICS_INTERVAL_QA;
- }
-
- if (force_send || mTimeSinceLastRezMessage.getElapsedTimeF32() > send_period)
- {
- // Stats for completed phases have been getting logged as they
- // complete. This will give us stats for any timers that
- // haven't finished as of the metric's being sent.
-
- if (force_send)
- {
- LLVOAvatar::logPendingPhasesAllAvatars();
- }
- sendViewerAppearanceChangeMetrics();
- }
-
- return false;
-}
-
-void LLVOAvatarSelf::addMetricsTimerRecord(const LLSD& record)
-{
- mPendingTimerRecords.push_back(record);
-}
-
-bool operator<(const LLSD& a, const LLSD& b)
-{
- std::ostringstream aout, bout;
- aout << LLSDNotationStreamer(a);
- bout << LLSDNotationStreamer(b);
- std::string astring = aout.str();
- std::string bstring = bout.str();
-
- return astring < bstring;
-
-}
-
-// Given a vector of LLSD records, return an LLSD array of bucketed stats for val_field.
-LLSD summarize_by_buckets(std::vector<LLSD> in_records,
- std::vector<std::string> by_fields,
- std::string val_field)
-{
- LLSD result = LLSD::emptyArray();
- std::map<LLSD,LLViewerStats::StatsAccumulator> accum;
- for (std::vector<LLSD>::iterator in_record_iter = in_records.begin();
- in_record_iter != in_records.end(); ++in_record_iter)
- {
- LLSD& record = *in_record_iter;
- LLSD key;
- for (std::vector<std::string>::iterator field_iter = by_fields.begin();
- field_iter != by_fields.end(); ++field_iter)
- {
- const std::string& field = *field_iter;
- key[field] = record[field];
- }
- LLViewerStats::StatsAccumulator& stats = accum[key];
- F32 value = record[val_field].asReal();
- stats.push(value);
- }
- for (std::map<LLSD,LLViewerStats::StatsAccumulator>::iterator accum_it = accum.begin();
- accum_it != accum.end(); ++accum_it)
- {
- LLSD out_record = accum_it->first;
- out_record["stats"] = accum_it->second.asLLSD();
- result.append(out_record);
- }
- return result;
-}
-
-void LLVOAvatarSelf::sendViewerAppearanceChangeMetrics()
-{
- std::string caps_url;
- if (getRegion())
- {
- // runway - change here to activate.
- caps_url = getRegion()->getCapability("ViewerMetrics");
- }
- if (!caps_url.empty())
- {
-
- LLCoros::instance().launch("LLVOAvatarSelf::appearanceChangeMetricsCoro",
- boost::bind(&LLVOAvatarSelf::appearanceChangeMetricsCoro, this, caps_url));
- mTimeSinceLastRezMessage.reset();
- }
-}
-
-const LLUUID& LLVOAvatarSelf::grabBakedTexture(EBakedTextureIndex baked_index) const
-{
- if (canGrabBakedTexture(baked_index))
- {
- ETextureIndex tex_index = sAvatarDictionary->bakedToLocalTextureIndex(baked_index);
- if (tex_index == TEX_NUM_INDICES)
- {
- return LLUUID::null;
- }
- return getTEImage( tex_index )->getID();
- }
- return LLUUID::null;
-}
-
-bool LLVOAvatarSelf::canGrabBakedTexture(EBakedTextureIndex baked_index) const
-{
- ETextureIndex tex_index = sAvatarDictionary->bakedToLocalTextureIndex(baked_index);
- if (tex_index == TEX_NUM_INDICES)
- {
- return false;
- }
- // Check if the texture hasn't been baked yet.
- if (!isTextureDefined(tex_index, 0))
- {
- LL_DEBUGS() << "getTEImage( " << (U32) tex_index << " )->getID() == IMG_DEFAULT_AVATAR" << LL_ENDL;
- return false;
- }
-
- if (gAgent.isGodlikeWithoutAdminMenuFakery())
- return true;
-
- // Check permissions of textures that show up in the
- // baked texture. We don't want people copying people's
- // work via baked textures.
-
- const LLAvatarAppearanceDictionary::BakedEntry *baked_dict = sAvatarDictionary->getBakedTexture(baked_index);
- for (texture_vec_t::const_iterator iter = baked_dict->mLocalTextures.begin();
- iter != baked_dict->mLocalTextures.end();
- ++iter)
- {
- const ETextureIndex t_index = (*iter);
- LLWearableType::EType wearable_type = sAvatarDictionary->getTEWearableType(t_index);
- U32 count = gAgentWearables.getWearableCount(wearable_type);
- LL_DEBUGS() << "Checking index " << (U32) t_index << " count: " << count << LL_ENDL;
-
- for (U32 wearable_index = 0; wearable_index < count; ++wearable_index)
- {
- LLViewerWearable *wearable = gAgentWearables.getViewerWearable(wearable_type, wearable_index);
- if (wearable)
- {
- const LLLocalTextureObject *texture = wearable->getLocalTextureObject((S32)t_index);
- const LLUUID& texture_id = texture->getID();
- if (texture_id != IMG_DEFAULT_AVATAR)
- {
- // Search inventory for this texture.
- LLViewerInventoryCategory::cat_array_t cats;
- LLViewerInventoryItem::item_array_t items;
- LLAssetIDMatches asset_id_matches(texture_id);
- gInventory.collectDescendentsIf(LLUUID::null,
- cats,
- items,
- LLInventoryModel::INCLUDE_TRASH,
- asset_id_matches);
-
- bool can_grab = false;
- LL_DEBUGS() << "item count for asset " << texture_id << ": " << items.size() << LL_ENDL;
- if (items.size())
- {
- // search for full permissions version
- for (S32 i = 0; i < items.size(); i++)
- {
- LLViewerInventoryItem* itemp = items[i];
- if (itemp->getIsFullPerm())
- {
- can_grab = true;
- break;
- }
- }
- }
- if (!can_grab) return false;
- }
- }
- }
- }
-
- return true;
-}
-
-void LLVOAvatarSelf::addLocalTextureStats( ETextureIndex type, LLViewerFetchedTexture* imagep,
- F32 texel_area_ratio, bool render_avatar, bool covered_by_baked)
-{
- if (!isIndexLocalTexture(type)) return;
-
- // Sunshine - ignoring covered_by_baked will force local textures
- // to always load. Fix for SH-4001 and many related issues. Do
- // not restore this without some more targetted fix for the local
- // textures failing to load issue.
- //if (!covered_by_baked)
- {
- if (imagep->getID() != IMG_DEFAULT_AVATAR)
- {
- imagep->setNoDelete();
- if (imagep->getDiscardLevel() != 0)
- {
- F32 desired_pixels;
- desired_pixels = llmin(mPixelArea, (F32)getTexImageArea());
-
- imagep->setBoostLevel(getAvatarBoostLevel());
- imagep->resetTextureStats();
- imagep->setMaxVirtualSizeResetInterval(MAX_TEXTURE_VIRTUAL_SIZE_RESET_INTERVAL);
- imagep->addTextureStats( desired_pixels / texel_area_ratio );
- imagep->forceUpdateBindStats() ;
- if (imagep->getDiscardLevel() < 0)
- {
- mHasGrey = true; // for statistics gathering
- }
- }
- }
- else
- {
- // texture asset is missing
- mHasGrey = true; // for statistics gathering
- }
- }
-}
-
-LLLocalTextureObject* LLVOAvatarSelf::getLocalTextureObject(LLAvatarAppearanceDefines::ETextureIndex i, U32 wearable_index) const
-{
- LLWearableType::EType type = sAvatarDictionary->getTEWearableType(i);
- LLViewerWearable* wearable = gAgentWearables.getViewerWearable(type, wearable_index);
- if (wearable)
- {
- return wearable->getLocalTextureObject(i);
- }
-
- return NULL;
-}
-
-//-----------------------------------------------------------------------------
-// getBakedTE()
-// Used by the LayerSet. (Layer sets don't in general know what textures depend on them.)
-//-----------------------------------------------------------------------------
-ETextureIndex LLVOAvatarSelf::getBakedTE( const LLViewerTexLayerSet* layerset ) const
-{
- for (U32 i = 0; i < mBakedTextureDatas.size(); i++)
- {
- if (layerset == mBakedTextureDatas[i].mTexLayerSet )
- {
- return mBakedTextureDatas[i].mTextureIndex;
- }
- }
- llassert(0);
- return TEX_HEAD_BAKED;
-}
-
-// FIXME: This is not called consistently. Something may be broken.
-void LLVOAvatarSelf::outputRezDiagnostics() const
-{
- if(!gSavedSettings.getBOOL("DebugAvatarLocalTexLoadedTime"))
- {
- return ;
- }
-
- const F32 final_time = mDebugSelfLoadTimer.getElapsedTimeF32();
- LL_DEBUGS("Avatar") << "REZTIME: Myself rez stats:" << LL_ENDL;
- LL_DEBUGS("Avatar") << "\t Time from avatar creation to load wearables: " << (S32)mDebugTimeWearablesLoaded << LL_ENDL;
- LL_DEBUGS("Avatar") << "\t Time from avatar creation to de-cloud: " << (S32)mDebugTimeAvatarVisible << LL_ENDL;
- LL_DEBUGS("Avatar") << "\t Time from avatar creation to de-cloud for others: " << (S32)final_time << LL_ENDL;
- LL_DEBUGS("Avatar") << "\t Load time for each texture: " << LL_ENDL;
- for (U32 i = 0; i < LLAvatarAppearanceDefines::TEX_NUM_INDICES; ++i)
- {
- std::stringstream out;
- out << "\t\t (" << i << ") ";
- U32 j=0;
- for (j=0; j <= MAX_DISCARD_LEVEL; j++)
- {
- out << "\t";
- S32 load_time = (S32)mDebugTextureLoadTimes[i][j];
- if (load_time == -1)
- {
- out << "*";
- if (j == 0)
- break;
- }
- else
- {
- out << load_time;
- }
- }
-
- // Don't print out non-existent textures.
- if (j != 0)
- {
- LL_DEBUGS("Avatar") << out.str() << LL_ENDL;
- }
- }
- LL_DEBUGS("Avatar") << "\t Time points for each upload (start / finish)" << LL_ENDL;
- for (U32 i = 0; i < LLAvatarAppearanceDefines::BAKED_NUM_INDICES; ++i)
- {
- LL_DEBUGS("Avatar") << "\t\t (" << i << ") \t" << (S32)mDebugBakedTextureTimes[i][0] << " / " << (S32)mDebugBakedTextureTimes[i][1] << LL_ENDL;
- }
-
- for (LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary::BakedTextures::const_iterator baked_iter = sAvatarDictionary->getBakedTextures().begin();
- baked_iter != sAvatarDictionary->getBakedTextures().end();
- ++baked_iter)
- {
- const LLAvatarAppearanceDefines::EBakedTextureIndex baked_index = baked_iter->first;
- const LLViewerTexLayerSet *layerset = debugGetLayerSet(baked_index);
- if (!layerset) continue;
- const LLViewerTexLayerSetBuffer *layerset_buffer = layerset->getViewerComposite();
- if (!layerset_buffer) continue;
- LL_DEBUGS("Avatar") << layerset_buffer->dumpTextureInfo() << LL_ENDL;
- }
-
- dumpAllTextures();
-}
-
-void LLVOAvatarSelf::outputRezTiming(const std::string& msg) const
-{
- LL_DEBUGS("Avatar")
- << avString()
- << llformat("%s. Time from avatar creation: %.2f", msg.c_str(), mDebugSelfLoadTimer.getElapsedTimeF32())
- << LL_ENDL;
-}
-
-void LLVOAvatarSelf::reportAvatarRezTime() const
-{
- // TODO: report mDebugSelfLoadTimer.getElapsedTimeF32() somehow.
-}
-
-// SUNSHINE CLEANUP - not clear we need any of this, may be sufficient to request server appearance in llviewermenu.cpp:handle_rebake_textures()
-void LLVOAvatarSelf::forceBakeAllTextures(bool slam_for_debug)
-{
- LL_INFOS() << "TAT: forced full rebake. " << LL_ENDL;
-
- for (U32 i = 0; i < mBakedTextureDatas.size(); i++)
- {
- ETextureIndex baked_index = mBakedTextureDatas[i].mTextureIndex;
- LLViewerTexLayerSet* layer_set = getLayerSet(baked_index);
- if (layer_set)
- {
- if (slam_for_debug)
- {
- layer_set->setUpdatesEnabled(true);
- }
-
- invalidateComposite(layer_set);
- add(LLStatViewer::TEX_REBAKES, 1);
- }
- else
- {
- LL_WARNS() << "TAT: NO LAYER SET FOR " << (S32)baked_index << LL_ENDL;
- }
- }
-
- // Don't know if this is needed
- updateMeshTextures();
-}
-
-//-----------------------------------------------------------------------------
-// requestLayerSetUpdate()
-//-----------------------------------------------------------------------------
-void LLVOAvatarSelf::requestLayerSetUpdate(ETextureIndex index )
-{
- /* switch(index)
- case LOCTEX_UPPER_BODYPAINT:
- case LOCTEX_UPPER_SHIRT:
- if( mUpperBodyLayerSet )
- mUpperBodyLayerSet->requestUpdate(); */
- const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = sAvatarDictionary->getTexture(index);
- if (!texture_dict)
- return;
- if (!texture_dict->mIsLocalTexture || !texture_dict->mIsUsedByBakedTexture)
- return;
- const EBakedTextureIndex baked_index = texture_dict->mBakedTextureIndex;
- if (mBakedTextureDatas[baked_index].mTexLayerSet)
- {
- mBakedTextureDatas[baked_index].mTexLayerSet->requestUpdate();
- }
-}
-
-LLViewerTexLayerSet* LLVOAvatarSelf::getLayerSet(ETextureIndex index) const
-{
- /* switch(index)
- case TEX_HEAD_BAKED:
- case TEX_HEAD_BODYPAINT:
- return mHeadLayerSet; */
- const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = sAvatarDictionary->getTexture(index);
- if (texture_dict && texture_dict->mIsUsedByBakedTexture)
- {
- const EBakedTextureIndex baked_index = texture_dict->mBakedTextureIndex;
- return getLayerSet(baked_index);
- }
- return NULL;
-}
-
-LLViewerTexLayerSet* LLVOAvatarSelf::getLayerSet(EBakedTextureIndex baked_index) const
-{
- /* switch(index)
- case TEX_HEAD_BAKED:
- case TEX_HEAD_BODYPAINT:
- return mHeadLayerSet; */
- if (baked_index >= 0 && baked_index < BAKED_NUM_INDICES)
- {
- return getTexLayerSet(baked_index);
- }
- return NULL;
-}
-
-
-
-
-// static
-void LLVOAvatarSelf::onCustomizeStart(bool disable_camera_switch)
-{
- if (isAgentAvatarValid())
- {
- LLUIUsage::instance().logCommand("Avatar.CustomizeStart");
- if (!gAgentAvatarp->mEndCustomizeCallback.get())
- {
- gAgentAvatarp->mEndCustomizeCallback = new LLUpdateAppearanceOnDestroy;
- }
-
- gAgentAvatarp->mIsEditingAppearance = true;
- gAgentAvatarp->mUseLocalAppearance = true;
-
- if (gSavedSettings.getBOOL("AppearanceCameraMovement") && !disable_camera_switch)
- {
- gAgentCamera.changeCameraToCustomizeAvatar();
- }
-
- gAgentAvatarp->invalidateAll(); // mark all bakes as dirty, request updates
- gAgentAvatarp->updateMeshTextures(); // make sure correct textures are applied to the avatar mesh.
- gAgentAvatarp->updateTextures(); // call updateTextureStats
- }
-}
-
-// static
-void LLVOAvatarSelf::onCustomizeEnd(bool disable_camera_switch)
-{
-
- if (isAgentAvatarValid())
- {
- gAgentAvatarp->mIsEditingAppearance = false;
- gAgentAvatarp->invalidateAll();
-
- if (gSavedSettings.getBOOL("AppearanceCameraMovement") && !disable_camera_switch)
- {
- gAgentCamera.changeCameraToDefault();
- gAgentCamera.resetView();
- }
-
- // Dereferencing the previous callback will cause
- // updateAppearanceFromCOF to be called, whenever all refs
- // have resolved.
- gAgentAvatarp->mEndCustomizeCallback = NULL;
- }
-}
-
-// virtual
-bool LLVOAvatarSelf::shouldRenderRigged() const
-{
- return gAgent.needsRenderAvatar();
-}
-
-// HACK: this will null out the avatar's local texture IDs before the TE message is sent
-// to ensure local texture IDs are not sent to other clients in the area.
-// this is a short-term solution. The long term solution will be to not set the texture
-// IDs in the avatar object, and keep them only in the wearable.
-// This will involve further refactoring that is too risky for the initial release of 2.0.
-bool LLVOAvatarSelf::sendAppearanceMessage(LLMessageSystem *mesgsys) const
-{
- LLUUID texture_id[TEX_NUM_INDICES];
- // pack away current TEs to make sure we don't send them out
- for (LLAvatarAppearanceDictionary::Textures::const_iterator iter = sAvatarDictionary->getTextures().begin();
- iter != sAvatarDictionary->getTextures().end();
- ++iter)
- {
- const ETextureIndex index = iter->first;
- const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = iter->second;
- if (!texture_dict->mIsBakedTexture)
- {
- LLTextureEntry* entry = getTE((U8) index);
- texture_id[index] = entry->getID();
- entry->setID(IMG_DEFAULT_AVATAR);
- }
- }
-
- bool success = packTEMessage(mesgsys);
-
- // unpack TEs to make sure we don't re-trigger a bake
- for (LLAvatarAppearanceDictionary::Textures::const_iterator iter = sAvatarDictionary->getTextures().begin();
- iter != sAvatarDictionary->getTextures().end();
- ++iter)
- {
- const ETextureIndex index = iter->first;
- const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = iter->second;
- if (!texture_dict->mIsBakedTexture)
- {
- LLTextureEntry* entry = getTE((U8) index);
- entry->setID(texture_id[index]);
- }
- }
-
- return success;
-}
-
-//------------------------------------------------------------------------
-// sendHoverHeight()
-//------------------------------------------------------------------------
-void LLVOAvatarSelf::sendHoverHeight() const
-{
- std::string url = gAgent.getRegionCapability("AgentPreferences");
-
- if (!url.empty())
- {
- LLSD update = LLSD::emptyMap();
- const LLVector3& hover_offset = getHoverOffset();
- update["hover_height"] = hover_offset[2];
-
- LL_DEBUGS("Avatar") << avString() << "sending hover height value " << hover_offset[2] << LL_ENDL;
-
- // *TODO: - this class doesn't really do anything, could just use a base
- // class responder if nothing else gets added.
- // (comment from removed Responder)
- LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost(url, update,
- "Hover height sent to sim", "Hover height not sent to sim");
- mLastHoverOffsetSent = hover_offset;
- }
-}
-
-void LLVOAvatarSelf::setHoverOffset(const LLVector3& hover_offset, bool send_update)
-{
- if (getHoverOffset() != hover_offset)
- {
- LL_INFOS("Avatar") << avString() << " setting hover due to change " << hover_offset[2] << LL_ENDL;
- LLVOAvatar::setHoverOffset(hover_offset, send_update);
- }
- if (send_update && (hover_offset != mLastHoverOffsetSent))
- {
- LL_INFOS("Avatar") << avString() << " sending hover due to change " << hover_offset[2] << LL_ENDL;
- sendHoverHeight();
- }
-}
-
-//------------------------------------------------------------------------
-// needsRenderBeam()
-//------------------------------------------------------------------------
-bool LLVOAvatarSelf::needsRenderBeam()
-{
- LLTool *tool = LLToolMgr::getInstance()->getCurrentTool();
-
- bool is_touching_or_grabbing = (tool == LLToolGrab::getInstance() && LLToolGrab::getInstance()->isEditing());
- LLViewerObject* objp = LLToolGrab::getInstance()->getEditingObject();
- if (objp // might need to be "!objp ||" instead of "objp &&".
- && (objp->isAttachment() || objp->isAvatar()))
- {
- // don't render grab tool's selection beam on hud objects,
- // attachments or avatars
- is_touching_or_grabbing = false;
- }
- return is_touching_or_grabbing || (getAttachmentState() & AGENT_STATE_EDITING && LLSelectMgr::getInstance()->shouldShowSelection());
-}
-
-// static
-void LLVOAvatarSelf::deleteScratchTextures()
-{
- for(std::map< LLGLenum, LLGLuint*>::iterator it = sScratchTexNames.begin(), end_it = sScratchTexNames.end();
- it != end_it;
- ++it)
- {
- LLImageGL::deleteTextures(1, (U32 *)it->second );
- stop_glerror();
- }
-
- if( sScratchTexBytes.value() )
- {
- LL_DEBUGS() << "Clearing Scratch Textures " << (S32Kilobytes)sScratchTexBytes << LL_ENDL;
-
- delete_and_clear(sScratchTexNames);
- sScratchTexBytes = S32Bytes(0);
- }
-}
-
-// static
-void LLVOAvatarSelf::dumpScratchTextureByteCount()
-{
- LL_INFOS() << "Scratch Texture GL: " << (sScratchTexBytes/1024) << "KB" << LL_ENDL;
-}
-
-void LLVOAvatarSelf::dumpWearableInfo(LLAPRFile& outfile)
-{
- apr_file_t* file = outfile.getFileHandle();
- if (!file)
- {
- return;
- }
-
-
- apr_file_printf( file, "\n<wearable_info>\n" );
-
- LLWearableData *wd = getWearableData();
- LLWearableType *wr_inst = LLWearableType::getInstance();
- for (S32 type = 0; type < LLWearableType::WT_COUNT; type++)
- {
- const std::string& type_name = wr_inst->getTypeName((LLWearableType::EType)type);
- for (U32 j=0; j< wd->getWearableCount((LLWearableType::EType)type); j++)
- {
- LLViewerWearable *wearable = gAgentWearables.getViewerWearable((LLWearableType::EType)type,j);
- apr_file_printf( file, "\n\t <wearable type=\"%s\" name=\"%s\"/>\n",
- type_name.c_str(), wearable->getName().c_str() );
- LLWearable::visual_param_vec_t v_params;
- wearable->getVisualParams(v_params);
- for (LLWearable::visual_param_vec_t::iterator it = v_params.begin();
- it != v_params.end(); ++it)
- {
- LLVisualParam *param = *it;
- dump_visual_param(file, param, param->getWeight());
- }
- }
- }
- apr_file_printf( file, "\n</wearable_info>\n" );
-}
+/** + * @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$ + */ + +#if LL_MSVC +// disable warning about boost::lexical_cast returning uninitialized data +// when it fails to parse the string +#pragma warning (disable:4701) +#endif + +#include "llviewerprecompiledheaders.h" + +#include "llvoavatarself.h" +#include "llvoavatar.h" + +#include "pipeline.h" + +#include "llagent.h" // Get state values from here +#include "llattachmentsmgr.h" +#include "llagentcamera.h" +#include "llagentwearables.h" +#include "llhudeffecttrail.h" +#include "llhudmanager.h" +#include "llinventoryfunctions.h" +#include "lllocaltextureobject.h" +#include "llnotificationsutil.h" +#include "llselectmgr.h" +#include "lltoolgrab.h" // for needsRenderBeam +#include "lltoolmgr.h" // for needsRenderBeam +#include "lltoolmorph.h" +#include "lltrans.h" +#include "llviewercamera.h" +#include "llviewercontrol.h" +#include "llviewermenu.h" +#include "llviewerobjectlist.h" +#include "llviewerstats.h" +#include "llviewerregion.h" +#include "llviewertexlayer.h" +#include "llviewerwearable.h" +#include "llappearancemgr.h" +#include "llmeshrepository.h" +#include "llvovolume.h" +#include "llsdutil.h" +#include "llstartup.h" +#include "llsdserialize.h" +#include "llcallstack.h" +#include "llcorehttputil.h" +#include "lluiusage.h" + +#if LL_MSVC +// disable boost::lexical_cast warning +#pragma warning (disable:4702) +#endif + +#include <boost/lexical_cast.hpp> + +LLPointer<LLVOAvatarSelf> gAgentAvatarp = NULL; + +bool isAgentAvatarValid() +{ + return (gAgentAvatarp.notNull() && gAgentAvatarp->isValid()); +} + +void selfStartPhase(const std::string& phase_name) +{ + if (isAgentAvatarValid()) + { + gAgentAvatarp->startPhase(phase_name); + } +} + +void selfStopPhase(const std::string& phase_name, bool err_check) +{ + if (isAgentAvatarValid()) + { + gAgentAvatarp->stopPhase(phase_name, err_check); + } +} + +void selfClearPhases() +{ + if (isAgentAvatarValid()) + { + gAgentAvatarp->clearPhases(); + } +} + +using namespace LLAvatarAppearanceDefines; + + +LLSD summarize_by_buckets(std::vector<LLSD> in_records, std::vector<std::string> by_fields, std::string val_field); + +/********************************************************************************* + ** ** + ** Begin private LLVOAvatarSelf Support classes + ** + **/ + +struct LocalTextureData +{ + LocalTextureData() : + mIsBakedReady(false), + mDiscard(MAX_DISCARD_LEVEL+1), + mImage(NULL), + mWearableID(IMG_DEFAULT_AVATAR), + mTexEntry(NULL) + {} + LLPointer<LLViewerFetchedTexture> mImage; + bool mIsBakedReady; + S32 mDiscard; + LLUUID mWearableID; // UUID of the wearable that this texture belongs to, not of the image itself + LLTextureEntry *mTexEntry; +}; + +//----------------------------------------------------------------------------- +// Callback data +//----------------------------------------------------------------------------- + + +/** + ** + ** End LLVOAvatarSelf Support classes + ** ** + *********************************************************************************/ + + +//----------------------------------------------------------------------------- +// Static Data +//----------------------------------------------------------------------------- +S32Bytes LLVOAvatarSelf::sScratchTexBytes(0); +std::map< LLGLenum, LLGLuint*> LLVOAvatarSelf::sScratchTexNames; + + +/********************************************************************************* + ** ** + ** Begin LLVOAvatarSelf Constructor routines + ** + **/ + +LLVOAvatarSelf::LLVOAvatarSelf(const LLUUID& id, + const LLPCode pcode, + LLViewerRegion* regionp) : + LLVOAvatar(id, pcode, regionp), + mScreenp(NULL), + mLastRegionHandle(0), + mRegionCrossingCount(0), + // Value outside legal range, so will always be a mismatch the + // first time through. + mLastHoverOffsetSent(LLVector3(0.0f, 0.0f, -999.0f)), + mInitialMetric(true), + mMetricSequence(0) +{ + mMotionController.mIsSelf = true; + + LL_DEBUGS() << "Marking avatar as self " << id << LL_ENDL; +} + +// Called periodically for diagnostics, return true when done. +bool output_self_av_texture_diagnostics() +{ + if (!isAgentAvatarValid()) + return true; // done checking + + gAgentAvatarp->outputRezDiagnostics(); + + return false; +} + +bool update_avatar_rez_metrics() +{ + if (!isAgentAvatarValid()) + return true; + + gAgentAvatarp->updateAvatarRezMetrics(false); + + return false; +} + +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(); + + LL_INFOS() << "Self avatar object created. Starting timer." << LL_ENDL; + mDebugSelfLoadTimer.reset(); + // clear all times to -1 for debugging + for (U32 i =0; i < LLAvatarAppearanceDefines::TEX_NUM_INDICES; ++i) + { + for (U32 j = 0; j <= MAX_DISCARD_LEVEL; ++j) + { + mDebugTextureLoadTimes[i][j] = -1.0f; + } + } + + for (U32 i =0; i < LLAvatarAppearanceDefines::BAKED_NUM_INDICES; ++i) + { + mDebugBakedTextureTimes[i][0] = -1.0f; + mDebugBakedTextureTimes[i][1] = -1.0f; + } + + status &= buildMenus(); + if (!status) + { + LL_ERRS() << "Unable to load user's avatar" << LL_ENDL; + return; + } + + setHoverIfRegionEnabled(); + + //doPeriodically(output_self_av_texture_diagnostics, 30.0); + doPeriodically(update_avatar_rez_metrics, 5.0); + doPeriodically(boost::bind(&LLVOAvatarSelf::checkStuckAppearance, this), 30.0); + + mInitFlags |= 1<<2; +} + +void LLVOAvatarSelf::setHoverIfRegionEnabled() +{ + if (getRegion() && getRegion()->simulatorFeaturesReceived()) + { + if (getRegion()->avatarHoverHeightEnabled()) + { + F32 hover_z = gSavedPerAccountSettings.getF32("AvatarHoverOffsetZ"); + setHoverOffset(LLVector3(0.0, 0.0, llclamp(hover_z,MIN_HOVER_Z,MAX_HOVER_Z))); + LL_INFOS("Avatar") << avString() << " set hover height from debug setting " << hover_z << LL_ENDL; + } + else + { + setHoverOffset(LLVector3(0.0, 0.0, 0.0)); + LL_INFOS("Avatar") << avString() << " zeroing hover height, region does not support" << LL_ENDL; + } + } + else + { + LL_INFOS("Avatar") << avString() << " region or simulator features not known, no change on hover" << LL_ENDL; + if (getRegion()) + { + getRegion()->setSimulatorFeaturesReceivedCallback(boost::bind(&LLVOAvatarSelf::onSimulatorFeaturesReceived,this,_1)); + } + + } +} + +bool LLVOAvatarSelf::checkStuckAppearance() +{ + const F32 CONDITIONAL_UNSTICK_INTERVAL = 300.0; + const F32 UNCONDITIONAL_UNSTICK_INTERVAL = 600.0; + + if (gAgentWearables.isCOFChangeInProgress()) + { + LL_DEBUGS("Avatar") << "checking for stuck appearance" << LL_ENDL; + F32 change_time = gAgentWearables.getCOFChangeTime(); + LL_DEBUGS("Avatar") << "change in progress for " << change_time << " seconds" << LL_ENDL; + S32 active_hp = LLAppearanceMgr::instance().countActiveHoldingPatterns(); + LL_DEBUGS("Avatar") << "active holding patterns " << active_hp << " seconds" << LL_ENDL; + S32 active_copies = LLAppearanceMgr::instance().getActiveCopyOperations(); + LL_DEBUGS("Avatar") << "active copy operations " << active_copies << LL_ENDL; + + if ((change_time > CONDITIONAL_UNSTICK_INTERVAL && active_copies == 0) || + (change_time > UNCONDITIONAL_UNSTICK_INTERVAL)) + { + gAgentWearables.notifyLoadingFinished(); + } + } + + // Return false to continue running check periodically. + return LLApp::isExiting(); +} + +// virtual +void LLVOAvatarSelf::markDead() +{ + mBeam = NULL; + LLVOAvatar::markDead(); +} + +/*virtual*/ bool LLVOAvatarSelf::loadAvatar() +{ + bool success = LLVOAvatar::loadAvatar(); + + // set all parameters stored directly in the avatar to have + // the isSelfParam to be true - this is used to prevent + // them from being animated or trigger accidental rebakes + // when we copy params from the wearable to the base avatar. + for (LLViewerVisualParam* param = (LLViewerVisualParam*) getFirstVisualParam(); + param; + param = (LLViewerVisualParam*) getNextVisualParam()) + { + if (param->getWearableType() != LLWearableType::WT_INVALID) + { + param->setIsDummy(true); + } + } + + return success; +} + + +bool LLVOAvatarSelf::loadAvatarSelf() +{ + bool success = true; + // avatar_skeleton.xml + if (!buildSkeletonSelf(sAvatarSkeletonInfo)) + { + LL_WARNS() << "avatar file: buildSkeleton() failed" << LL_ENDL; + return false; + } + + return success; +} + +bool LLVOAvatarSelf::buildSkeletonSelf(const LLAvatarSkeletonInfo *info) +{ + // 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); + // SL-315 + 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 + //------------------------------------------------------------------------- + gAttachBodyPartPieMenus[0] = NULL; + + LLContextMenu::Params params; + params.label(LLTrans::getString("BodyPartsRightArm")); + params.name(params.label); + params.visible(false); + gAttachBodyPartPieMenus[1] = LLUICtrlFactory::create<LLContextMenu> (params); + + params.label(LLTrans::getString("BodyPartsHead")); + params.name(params.label); + gAttachBodyPartPieMenus[2] = LLUICtrlFactory::create<LLContextMenu> (params); + + params.label(LLTrans::getString("BodyPartsLeftArm")); + params.name(params.label); + gAttachBodyPartPieMenus[3] = LLUICtrlFactory::create<LLContextMenu> (params); + + gAttachBodyPartPieMenus[4] = NULL; + + params.label(LLTrans::getString("BodyPartsLeftLeg")); + params.name(params.label); + gAttachBodyPartPieMenus[5] = LLUICtrlFactory::create<LLContextMenu> (params); + + params.label(LLTrans::getString("BodyPartsTorso")); + params.name(params.label); + gAttachBodyPartPieMenus[6] = LLUICtrlFactory::create<LLContextMenu> (params); + + params.label(LLTrans::getString("BodyPartsRightLeg")); + params.name(params.label); + gAttachBodyPartPieMenus[7] = LLUICtrlFactory::create<LLContextMenu> (params); + + params.label(LLTrans::getString("BodyPartsEnhancedSkeleton")); + params.name(params.label); + gAttachBodyPartPieMenus[8] = LLUICtrlFactory::create<LLContextMenu>(params); + + gDetachBodyPartPieMenus[0] = NULL; + + params.label(LLTrans::getString("BodyPartsRightArm")); + params.name(params.label); + gDetachBodyPartPieMenus[1] = LLUICtrlFactory::create<LLContextMenu> (params); + + params.label(LLTrans::getString("BodyPartsHead")); + params.name(params.label); + gDetachBodyPartPieMenus[2] = LLUICtrlFactory::create<LLContextMenu> (params); + + params.label(LLTrans::getString("BodyPartsLeftArm")); + params.name(params.label); + gDetachBodyPartPieMenus[3] = LLUICtrlFactory::create<LLContextMenu> (params); + + gDetachBodyPartPieMenus[4] = NULL; + + params.label(LLTrans::getString("BodyPartsLeftLeg")); + params.name(params.label); + gDetachBodyPartPieMenus[5] = LLUICtrlFactory::create<LLContextMenu> (params); + + params.label(LLTrans::getString("BodyPartsTorso")); + params.name(params.label); + gDetachBodyPartPieMenus[6] = LLUICtrlFactory::create<LLContextMenu> (params); + + params.label(LLTrans::getString("BodyPartsRightLeg")); + params.name(params.label); + gDetachBodyPartPieMenus[7] = LLUICtrlFactory::create<LLContextMenu> (params); + + params.label(LLTrans::getString("BodyPartsEnhancedSkeleton")); + params.name(params.label); + gDetachBodyPartPieMenus[8] = LLUICtrlFactory::create<LLContextMenu>(params); + + for (S32 i = 0; i < 9; i++) + { + if (gAttachBodyPartPieMenus[i]) + { + gAttachPieMenu->appendContextSubMenu( gAttachBodyPartPieMenus[i] ); + } + else + { + for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); + iter != mAttachmentPoints.end(); + ++iter) + { + LLViewerJointAttachment* attachment = iter->second; + if (attachment && attachment->getGroup() == i) + { + LLMenuItemCallGL::Params item_params; + + std::string sub_piemenu_name = attachment->getName(); + if (LLTrans::getString(sub_piemenu_name) != "") + { + item_params.label = LLTrans::getString(sub_piemenu_name); + } + else + { + item_params.label = sub_piemenu_name; + } + item_params.name =(item_params.label ); + item_params.on_click.function_name = "Object.AttachToAvatar"; + item_params.on_click.parameter = iter->first; + item_params.on_enable.function_name = "Object.EnableWear"; + item_params.on_enable.parameter = iter->first; + LLMenuItemCallGL* item = LLUICtrlFactory::create<LLMenuItemCallGL>(item_params); + + gAttachPieMenu->addChild(item); + + break; + + } + } + } + + if (gDetachBodyPartPieMenus[i]) + { + gDetachPieMenu->appendContextSubMenu( gDetachBodyPartPieMenus[i] ); + gDetachAttSelfMenu->appendContextSubMenu(gDetachBodyPartPieMenus[i]); + gDetachAvatarMenu->appendContextSubMenu(gDetachBodyPartPieMenus[i]); + } + else + { + for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); + iter != mAttachmentPoints.end(); + ++iter) + { + LLViewerJointAttachment* attachment = iter->second; + if (attachment && attachment->getGroup() == i) + { + LLMenuItemCallGL::Params item_params; + std::string sub_piemenu_name = attachment->getName(); + if (LLTrans::getString(sub_piemenu_name) != "") + { + item_params.label = LLTrans::getString(sub_piemenu_name); + } + else + { + item_params.label = sub_piemenu_name; + } + item_params.name =(item_params.label ); + item_params.on_click.function_name = "Attachment.DetachFromPoint"; + item_params.on_click.parameter = iter->first; + item_params.on_enable.function_name = "Attachment.PointFilled"; + item_params.on_enable.parameter = iter->first; + LLMenuItemCallGL* item = LLUICtrlFactory::create<LLMenuItemCallGL>(item_params); + + gDetachPieMenu->addChild(item); + gDetachAttSelfMenu->addChild(LLUICtrlFactory::create<LLMenuItemCallGL>(item_params)); + gDetachAvatarMenu->addChild(LLUICtrlFactory::create<LLMenuItemCallGL>(item_params)); + break; + } + } + } + } + + + // add screen attachments + for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); + iter != mAttachmentPoints.end(); + ++iter) + { + LLViewerJointAttachment* attachment = iter->second; + if (attachment->getGroup() == 9) + { + LLMenuItemCallGL::Params item_params; + std::string sub_piemenu_name = attachment->getName(); + if (LLTrans::getString(sub_piemenu_name) != "") + { + item_params.label = LLTrans::getString(sub_piemenu_name); + } + else + { + item_params.label = sub_piemenu_name; + } + item_params.name =(item_params.label ); + item_params.on_click.function_name = "Object.AttachToAvatar"; + item_params.on_click.parameter = iter->first; + item_params.on_enable.function_name = "Object.EnableWear"; + item_params.on_enable.parameter = iter->first; + LLMenuItemCallGL* item = LLUICtrlFactory::create<LLMenuItemCallGL>(item_params); + gAttachScreenPieMenu->addChild(item); + + item_params.on_click.function_name = "Attachment.DetachFromPoint"; + item_params.on_click.parameter = iter->first; + item_params.on_enable.function_name = "Attachment.PointFilled"; + item_params.on_enable.parameter = iter->first; + item = LLUICtrlFactory::create<LLMenuItemCallGL>(item_params); + gDetachScreenPieMenu->addChild(item); + gDetachHUDAttSelfMenu->addChild(LLUICtrlFactory::create<LLMenuItemCallGL>(item_params)); + gDetachHUDAvatarMenu->addChild(LLUICtrlFactory::create<LLMenuItemCallGL>(item_params)); + } + } + + for (S32 pass = 0; pass < 2; pass++) + { + // *TODO: Skinning - gAttachSubMenu is an awful, awful hack + if (!gAttachSubMenu) + { + break; + } + for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); + iter != mAttachmentPoints.end(); + ++iter) + { + LLViewerJointAttachment* attachment = iter->second; + if (attachment->getIsHUDAttachment() != (pass == 1)) + { + continue; + } + LLMenuItemCallGL::Params item_params; + std::string sub_piemenu_name = attachment->getName(); + if (LLTrans::getString(sub_piemenu_name) != "") + { + item_params.label = LLTrans::getString(sub_piemenu_name); + } + else + { + item_params.label = sub_piemenu_name; + } + item_params.name =(item_params.label ); + item_params.on_click.function_name = "Object.AttachToAvatar"; + item_params.on_click.parameter = iter->first; + item_params.on_enable.function_name = "Object.EnableWear"; + item_params.on_enable.parameter = iter->first; + //* TODO: Skinning: + //LLSD params; + //params["index"] = iter->first; + //params["label"] = attachment->getName(); + //item->addEventHandler("on_enable", LLMenuItemCallGL::MenuCallback().function_name("Attachment.Label").parameter(params)); + + LLMenuItemCallGL* item = LLUICtrlFactory::create<LLMenuItemCallGL>(item_params); + gAttachSubMenu->addChild(item); + + item_params.on_click.function_name = "Attachment.DetachFromPoint"; + item_params.on_click.parameter = iter->first; + item_params.on_enable.function_name = "Attachment.PointFilled"; + item_params.on_enable.parameter = iter->first; + //* TODO: Skinning: item->addEventHandler("on_enable", LLMenuItemCallGL::MenuCallback().function_name("Attachment.Label").parameter(params)); + + item = LLUICtrlFactory::create<LLMenuItemCallGL>(item_params); + gDetachSubMenu->addChild(item); + } + if (pass == 0) + { + // put separator between non-hud and hud attachments + gAttachSubMenu->addSeparator(); + gDetachSubMenu->addSeparator(); + } + } + + for (S32 group = 0; group < 9; 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 && 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 + for (std::multimap<S32, S32>::iterator attach_it = attachment_pie_menu_map.begin(); + attach_it != attachment_pie_menu_map.end(); ++attach_it) + { + S32 attach_index = attach_it->second; + + LLViewerJointAttachment* attachment = get_if_there(mAttachmentPoints, attach_index, (LLViewerJointAttachment*)NULL); + if (attachment) + { + LLMenuItemCallGL::Params item_params; + item_params.name = attachment->getName(); + item_params.label = LLTrans::getString(attachment->getName()); + item_params.on_click.function_name = "Object.AttachToAvatar"; + item_params.on_click.parameter = attach_index; + item_params.on_enable.function_name = "Object.EnableWear"; + item_params.on_enable.parameter = attach_index; + + LLMenuItemCallGL* item = LLUICtrlFactory::create<LLMenuItemCallGL>(item_params); + gAttachBodyPartPieMenus[group]->addChild(item); + + item_params.on_click.function_name = "Attachment.DetachFromPoint"; + item_params.on_click.parameter = attach_index; + item_params.on_enable.function_name = "Attachment.PointFilled"; + item_params.on_enable.parameter = attach_index; + item = LLUICtrlFactory::create<LLMenuItemCallGL>(item_params); + gDetachBodyPartPieMenus[group]->addChild(item); + } + } + } + return true; +} + +void LLVOAvatarSelf::cleanup() +{ + markDead(); + delete mScreenp; + mScreenp = NULL; + mRegionp = NULL; +} + +LLVOAvatarSelf::~LLVOAvatarSelf() +{ + cleanup(); +} + +/** + ** + ** End LLVOAvatarSelf Constructor routines + ** ** + *********************************************************************************/ + +// virtual +bool LLVOAvatarSelf::updateCharacter(LLAgent &agent) +{ + // 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::isValid() const +{ + return ((getRegion() != NULL) && !isDead()); +} + +// virtual +void LLVOAvatarSelf::idleUpdate(LLAgent &agent, const F64 &time) +{ + if (isValid()) + { + LLVOAvatar::idleUpdate(agent, time); + idleUpdateTractorBeam(); + } +} + +// virtual +LLJoint *LLVOAvatarSelf::getJoint(const std::string &name) +{ + LLJoint *jointp = NULL; + jointp = LLVOAvatar::getJoint(name); + if (!jointp && mScreenp) + { + jointp = mScreenp->findJoint(name); + if (jointp) + { + mJointMap[name] = jointp; + } + } + if (jointp && jointp != mScreenp && jointp != mRoot) + { + llassert(LLVOAvatar::getJoint((S32)jointp->getJointNum())==jointp); + } + return jointp; +} + +// virtual +bool LLVOAvatarSelf::setVisualParamWeight(const LLVisualParam *which_param, F32 weight) +{ + if (!which_param) + { + return false; + } + LLViewerVisualParam *param = (LLViewerVisualParam*) LLCharacter::getVisualParam(which_param->getID()); + return setParamWeight(param,weight); +} + +// virtual +bool LLVOAvatarSelf::setVisualParamWeight(const char* param_name, F32 weight) +{ + if (!param_name) + { + return false; + } + LLViewerVisualParam *param = (LLViewerVisualParam*) LLCharacter::getVisualParam(param_name); + return setParamWeight(param,weight); +} + +// virtual +bool LLVOAvatarSelf::setVisualParamWeight(S32 index, F32 weight) +{ + LLViewerVisualParam *param = (LLViewerVisualParam*) LLCharacter::getVisualParam(index); + return setParamWeight(param,weight); +} + +bool LLVOAvatarSelf::setParamWeight(const LLViewerVisualParam *param, F32 weight) +{ + if (!param) + { + return false; + } + + if (param->getCrossWearable()) + { + LLWearableType::EType type = (LLWearableType::EType)param->getWearableType(); + U32 size = gAgentWearables.getWearableCount(type); + for (U32 count = 0; count < size; ++count) + { + LLViewerWearable *wearable = gAgentWearables.getViewerWearable(type,count); + if (wearable) + { + wearable->setVisualParamWeight(param->getID(), weight); + } + } + } + + return LLCharacter::setVisualParamWeight(param,weight); +} + +/*virtual*/ +void LLVOAvatarSelf::updateVisualParams() +{ + LLVOAvatar::updateVisualParams(); +} + +void LLVOAvatarSelf::writeWearablesToAvatar() +{ + for (U32 type = 0; type < LLWearableType::WT_COUNT; type++) + { + LLWearable *wearable = gAgentWearables.getTopWearable((LLWearableType::EType)type); + if (wearable) + { + wearable->writeToAvatar(this); + } + } + +} + +/*virtual*/ +void LLVOAvatarSelf::idleUpdateAppearanceAnimation() +{ + // Animate all top-level wearable visual parameters + gAgentWearables.animateAllWearableParams(calcMorphAmount()); + + // Apply wearable visual params to avatar + writeWearablesToAvatar(); + + //allow avatar to process updates + LLVOAvatar::idleUpdateAppearanceAnimation(); + +} + +// 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 +bool LLVOAvatarSelf::hasMotionFromSource(const LLUUID& source_id) +{ + AnimSourceIterator motion_it = mAnimationSources.find(source_id); + return motion_it != mAnimationSources.end(); +} + +// 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); + // Must find() after each erase() to deal with potential iterator invalidation + // This also ensures that we don't go past the end of this source's animations + // into those of another source. + motion_it = mAnimationSources.find(source_id); + } + + + LLViewerObject* object = gObjectList.findObject(source_id); + if (object) + { + object->setFlagsWithoutUpdate(FLAGS_ANIM_SOURCE, false); + } +} + +void LLVOAvatarSelf::setLocalTextureTE(U8 te, LLViewerTexture* image, U32 index) +{ + if (te >= TEX_NUM_INDICES) + { + llassert(0); + return; + } + + if (getTEImage(te)->getID() == image->getID()) + { + return; + } + + if (isIndexBakedTexture((ETextureIndex)te)) + { + llassert(0); + return; + } + + setTEImage(te, image); +} + +//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 && imagep != tex) + { + setTEImage(te, imagep); + removed = true; + } + } + } + + if (removed) + { + for (U32 i = 0; i < mBakedTextureDatas.size(); i++) + { + LLViewerTexLayerSet *layerset = getTexLayerSet(i); + layerset->setUpdatesEnabled(true); + invalidateComposite(layerset); + } + updateMeshTextures(); + } +} + +void LLVOAvatarSelf::onSimulatorFeaturesReceived(const LLUUID& region_id) +{ + LL_INFOS("Avatar") << "simulator features received, setting hover based on region props" << LL_ENDL; + setHoverIfRegionEnabled(); +} + +//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(); + //LL_INFOS() << "pos_from_old_region is " << global_pos_from_old_region + // << " while pos_from_new_region is " << pos_from_new_region + // << LL_ENDL; + + // Update hover height, or schedule callback, based on whether + // it's supported in this region. + if (regionp->simulatorFeaturesReceived()) + { + setHoverIfRegionEnabled(); + } + else + { + regionp->setSimulatorFeaturesReceivedCallback(boost::bind(&LLVOAvatarSelf::onSimulatorFeaturesReceived,this,_1)); + } + } + + if (!regionp || (regionp->getHandle() != mLastRegionHandle)) + { + if (mLastRegionHandle != 0) + { + ++mRegionCrossingCount; + F64Seconds delta(mRegionCrossingTimer.getElapsedTimeF32()); + record(LLStatViewer::REGION_CROSSING_TIME, delta); + + // Diagnostics + LL_INFOS() << "Region crossing took " << (F32)(delta * 1000.0).value() << " ms " << LL_ENDL; + } + if (regionp) + { + mLastRegionHandle = regionp->getHandle(); + } + } + mRegionCrossingTimer.reset(); + LLViewerObject::updateRegion(regionp); +} + +//-------------------------------------------------------------------- +// draw tractor (selection) beam when editing objects +//-------------------------------------------------------------------- +//virtual +void LLVOAvatarSelf::idleUpdateTractorBeam() +{ + // This is only done for yourself (maybe it should be in the agent?) + if (!needsRenderBeam() || !isBuilt()) + { + 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 + { + const LLPickInfo& pick = gViewerWindow->getLastPick(); + mBeam->setPositionGlobal(pick.mPosGlobal); + } + + } + if (mBeamTimer.getElapsedTimeF32() > 0.25f) + { + mBeam->setColor(LLColor4U(gAgent.getEffectColor())); + mBeam->setNeedsSendToSim(true); + mBeamTimer.reset(); + } + } +} + +//----------------------------------------------------------------------------- +// restoreMeshData() +//----------------------------------------------------------------------------- +// virtual +void LLVOAvatarSelf::restoreMeshData() +{ + //LL_INFOS() << "Restoring" << LL_ENDL; + mMeshValid = true; + updateJointLODs(); + updateAttachmentVisibility(gAgentCamera.getCameraMode()); + + // force mesh update as LOD might not have changed to trigger this + gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_GEOMETRY); +} + + + +//----------------------------------------------------------------------------- +// updateAttachmentVisibility() +//----------------------------------------------------------------------------- +void LLVOAvatarSelf::updateAttachmentVisibility(U32 camera_mode) +{ + for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); + iter != mAttachmentPoints.end(); + ++iter) + { + LLViewerJointAttachment* attachment = iter->second; + if (attachment->getIsHUDAttachment()) + { + attachment->setAttachmentVisibility(true); + } + else + { + switch (camera_mode) + { + case CAMERA_MODE_MOUSELOOK: + if (LLVOAvatar::sVisibleInFirstPerson && attachment->getVisibleInFirstPerson()) + { + attachment->setAttachmentVisibility(true); + } + else + { + attachment->setAttachmentVisibility(false); + } + break; + default: + attachment->setAttachmentVisibility(true); + break; + } + } + } +} + +//----------------------------------------------------------------------------- +// updatedWearable( LLWearableType::EType type ) +// forces an update to any baked textures relevant to type. +// will force an upload of the resulting bake if the second parameter is true +//----------------------------------------------------------------------------- +void LLVOAvatarSelf::wearableUpdated(LLWearableType::EType type) +{ + for (LLAvatarAppearanceDictionary::BakedTextures::const_iterator baked_iter = sAvatarDictionary->getBakedTextures().begin(); + baked_iter != sAvatarDictionary->getBakedTextures().end(); + ++baked_iter) + { + const LLAvatarAppearanceDictionary::BakedEntry *baked_dict = baked_iter->second; + const LLAvatarAppearanceDefines::EBakedTextureIndex index = baked_iter->first; + + if (baked_dict) + { + for (LLAvatarAppearanceDefines::wearables_vec_t::const_iterator type_iter = baked_dict->mWearables.begin(); + type_iter != baked_dict->mWearables.end(); + ++type_iter) + { + const LLWearableType::EType comp_type = *type_iter; + if (comp_type == type) + { + LLViewerTexLayerSet *layerset = getLayerSet(index); + if (layerset) + { + layerset->setUpdatesEnabled(true); + invalidateComposite(layerset); + } + break; + } + } + } + } +} + +//----------------------------------------------------------------------------- +// isWearingAttachment() +//----------------------------------------------------------------------------- +bool LLVOAvatarSelf::isWearingAttachment(const LLUUID& inv_item_id) const +{ + const LLUUID& base_inv_item_id = gInventory.getLinkedItemID(inv_item_id); + for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin(); + iter != mAttachmentPoints.end(); + ++iter) + { + const LLViewerJointAttachment* attachment = iter->second; + if (attachment->getAttachedObject(base_inv_item_id)) + { + return true; + } + } + return false; +} + +//----------------------------------------------------------------------------- +// getWornAttachment() +//----------------------------------------------------------------------------- +LLViewerObject* LLVOAvatarSelf::getWornAttachment(const LLUUID& inv_item_id) +{ + const LLUUID& base_inv_item_id = gInventory.getLinkedItemID(inv_item_id); + for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin(); + iter != mAttachmentPoints.end(); + ++iter) + { + LLViewerJointAttachment* attachment = iter->second; + if (LLViewerObject *attached_object = attachment->getAttachedObject(base_inv_item_id)) + { + return attached_object; + } + } + return NULL; +} + +bool LLVOAvatarSelf::getAttachedPointName(const LLUUID& inv_item_id, std::string& name) const +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; + if (!gInventory.getItem(inv_item_id)) + { + name = "ATTACHMENT_MISSING_ITEM"; + return false; + } + const LLUUID& base_inv_item_id = gInventory.getLinkedItemID(inv_item_id); + if (!gInventory.getItem(base_inv_item_id)) + { + name = "ATTACHMENT_MISSING_BASE_ITEM"; + return false; + } + for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin(); + iter != mAttachmentPoints.end(); + ++iter) + { + const LLViewerJointAttachment* attachment = iter->second; + if (attachment->getAttachedObject(base_inv_item_id)) + { + name = attachment->getName(); + return true; + } + } + + name = "ATTACHMENT_NOT_ATTACHED"; + return false; +} + +//virtual +const LLViewerJointAttachment *LLVOAvatarSelf::attachObject(LLViewerObject *viewer_object) +{ + const LLViewerJointAttachment *attachment = LLVOAvatar::attachObject(viewer_object); + if (!attachment) + { + return 0; + } + + updateAttachmentVisibility(gAgentCamera.getCameraMode()); + + // Then make sure the inventory is in sync with the avatar. + + // Should just be the last object added + if (attachment->isObjectAttached(viewer_object)) + { + const LLUUID& attachment_id = viewer_object->getAttachmentItemID(); + LLAppearanceMgr::instance().registerAttachment(attachment_id); + updateLODRiggedAttachments(); + } + + return attachment; +} + +//virtual +bool LLVOAvatarSelf::detachObject(LLViewerObject *viewer_object) +{ + const LLUUID attachment_id = viewer_object->getAttachmentItemID(); + if ( LLVOAvatar::detachObject(viewer_object) ) + { + // the simulator should automatically handle permission revocation + + stopMotionFromSource(attachment_id); + LLFollowCamMgr::getInstance()->setCameraActive(viewer_object->getID(), false); + + LLViewerObject::const_child_list_t& child_list = viewer_object->getChildren(); + for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin(); + iter != child_list.end(); + ++iter) + { + LLViewerObject* child_objectp = *iter; + // the simulator should automatically handle + // permissions revocation + + stopMotionFromSource(child_objectp->getID()); + LLFollowCamMgr::getInstance()->setCameraActive(child_objectp->getID(), false); + } + + // Make sure the inventory is in sync with the avatar. + + // Update COF contents, don't trigger appearance update. + if (!isValid()) + { + LL_INFOS() << "removeItemLinks skipped, avatar is under destruction" << LL_ENDL; + } + else + { + LLAppearanceMgr::instance().unregisterAttachment(attachment_id); + } + + return true; + } + return false; +} + +bool LLVOAvatarSelf::hasAttachmentsInTrash() +{ + const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); + + for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin(); iter != mAttachmentPoints.end(); ++iter) + { + LLViewerJointAttachment *attachment = iter->second; + for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); + attachment_iter != attachment->mAttachedObjects.end(); + ++attachment_iter) + { + LLViewerObject *attached_object = attachment_iter->get(); + if (attached_object && gInventory.isObjectDescendentOf(attached_object->getAttachmentItemID(), trash_id)) + { + return true; + } + } + } + return false; +} + +// static +bool LLVOAvatarSelf::detachAttachmentIntoInventory(const LLUUID &item_id) +{ + LLInventoryItem* item = gInventory.getItem(item_id); + if (item) + { + gMessageSystem->newMessageFast(_PREHASH_DetachAttachmentIntoInv); + gMessageSystem->nextBlockFast(_PREHASH_ObjectData); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + gMessageSystem->addUUIDFast(_PREHASH_ItemID, item_id); + gMessageSystem->sendReliable(gAgent.getRegionHost()); + + // This object might have been selected, so let the selection manager know it's gone now + LLViewerObject *found_obj = gObjectList.findObject(item_id); + if (found_obj) + { + LLSelectMgr::getInstance()->remove(found_obj); + } + + // Error checking in case this object was attached to an invalid point + // In that case, just remove the item from COF preemptively since detach + // will fail. + if (isAgentAvatarValid()) + { + const LLViewerObject *attached_obj = gAgentAvatarp->getWornAttachment(item_id); + if (!attached_obj) + { + LLAppearanceMgr::instance().removeCOFItemLinks(item_id); + } + } + return true; + } + return false; +} + +U32 LLVOAvatarSelf::getNumWearables(LLAvatarAppearanceDefines::ETextureIndex i) const +{ + LLWearableType::EType type = sAvatarDictionary->getTEWearableType(i); + return gAgentWearables.getWearableCount(type); +} + +// virtual +void LLVOAvatarSelf::localTextureLoaded(bool success, LLViewerFetchedTexture *src_vi, LLImageRaw* src_raw, LLImageRaw* aux_src, S32 discard_level, bool final, void* userdata) +{ + + const LLUUID& src_id = src_vi->getID(); + LLAvatarTexData *data = (LLAvatarTexData *)userdata; + ETextureIndex index = data->mIndex; + if (!isIndexLocalTexture(index)) return; + + LLLocalTextureObject *local_tex_obj = getLocalTextureObject(index, 0); + + // fix for EXT-268. Preventing using of NULL pointer + if(NULL == local_tex_obj) + { + LL_WARNS("TAG") << "There is no Local Texture Object with index: " << index + << ", final: " << final + << LL_ENDL; + return; + } + if (success) + { + if (!local_tex_obj->getBakedReady() && + local_tex_obj->getImage() != NULL && + (local_tex_obj->getID() == src_id) && + discard_level < local_tex_obj->getDiscard()) + { + local_tex_obj->setDiscard(discard_level); + requestLayerSetUpdate(index); + if (isEditingAppearance()) + { + LLVisualParamHint::requestHintUpdates(); + } + updateMeshTextures(); + } + } + else if (final) + { + // Failed: asset is missing + if (!local_tex_obj->getBakedReady() && + local_tex_obj->getImage() != NULL && + local_tex_obj->getImage()->getID() == src_id) + { + local_tex_obj->setDiscard(0); + requestLayerSetUpdate(index); + updateMeshTextures(); + } + } +} + +// virtual +bool LLVOAvatarSelf::getLocalTextureGL(ETextureIndex type, LLViewerTexture** tex_pp, U32 index) const +{ + *tex_pp = NULL; + + if (!isIndexLocalTexture(type)) return false; + if (getLocalTextureID(type, index) == IMG_DEFAULT_AVATAR) return true; + + const LLLocalTextureObject *local_tex_obj = getLocalTextureObject(type, index); + if (!local_tex_obj) + { + return false; + } + *tex_pp = dynamic_cast<LLViewerTexture*> (local_tex_obj->getImage()); + return true; +} + +LLViewerFetchedTexture* LLVOAvatarSelf::getLocalTextureGL(LLAvatarAppearanceDefines::ETextureIndex type, U32 index) const +{ + if (!isIndexLocalTexture(type)) + { + return NULL; + } + + const LLLocalTextureObject *local_tex_obj = getLocalTextureObject(type, index); + if (!local_tex_obj) + { + return NULL; + } + if (local_tex_obj->getID() == IMG_DEFAULT_AVATAR) + { + return LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT_AVATAR); + } + return dynamic_cast<LLViewerFetchedTexture*> (local_tex_obj->getImage()); +} + +const LLUUID& LLVOAvatarSelf::getLocalTextureID(ETextureIndex type, U32 index) const +{ + if (!isIndexLocalTexture(type)) return IMG_DEFAULT_AVATAR; + + const LLLocalTextureObject *local_tex_obj = getLocalTextureObject(type, index); + if (local_tex_obj && local_tex_obj->getImage() != NULL) + { + return local_tex_obj->getImage()->getID(); + } + return IMG_DEFAULT_AVATAR; +} + + +//----------------------------------------------------------------------------- +// isLocalTextureDataAvailable() +// Returns true if at least the lowest quality discard level exists for every texture +// in the layerset. +//----------------------------------------------------------------------------- +bool LLVOAvatarSelf::isLocalTextureDataAvailable(const LLViewerTexLayerSet* layerset) const +{ + /* if (layerset == mBakedTextureDatas[BAKED_HEAD].mTexLayerSet) + return getLocalDiscardLevel(TEX_HEAD_BODYPAINT) >= 0; */ + for (LLAvatarAppearanceDictionary::BakedTextures::const_iterator baked_iter = sAvatarDictionary->getBakedTextures().begin(); + baked_iter != sAvatarDictionary->getBakedTextures().end(); + ++baked_iter) + { + const EBakedTextureIndex baked_index = baked_iter->first; + if (layerset == mBakedTextureDatas[baked_index].mTexLayerSet) + { + bool ret = true; + const LLAvatarAppearanceDictionary::BakedEntry *baked_dict = baked_iter->second; + for (texture_vec_t::const_iterator local_tex_iter = baked_dict->mLocalTextures.begin(); + local_tex_iter != baked_dict->mLocalTextures.end(); + ++local_tex_iter) + { + const ETextureIndex tex_index = *local_tex_iter; + const LLWearableType::EType wearable_type = sAvatarDictionary->getTEWearableType(tex_index); + const U32 wearable_count = gAgentWearables.getWearableCount(wearable_type); + for (U32 wearable_index = 0; wearable_index < wearable_count; wearable_index++) + { + bool tex_avail = (getLocalDiscardLevel(tex_index, wearable_index) >= 0); + ret &= tex_avail; + } + } + return ret; + } + } + llassert(0); + return false; +} + +//----------------------------------------------------------------------------- +// virtual +// isLocalTextureDataFinal() +// Returns true if the highest quality discard level exists for every texture +// in the layerset. +//----------------------------------------------------------------------------- +bool LLVOAvatarSelf::isLocalTextureDataFinal(const LLViewerTexLayerSet* layerset) const +{ + const U32 desired_tex_discard_level = gSavedSettings.getU32("TextureDiscardLevel"); + // const U32 desired_tex_discard_level = 0; // hack to not bake textures on lower discard levels. + + for (U32 i = 0; i < mBakedTextureDatas.size(); i++) + { + if (layerset == mBakedTextureDatas[i].mTexLayerSet) + { + const LLAvatarAppearanceDictionary::BakedEntry *baked_dict = sAvatarDictionary->getBakedTexture((EBakedTextureIndex)i); + for (texture_vec_t::const_iterator local_tex_iter = baked_dict->mLocalTextures.begin(); + local_tex_iter != baked_dict->mLocalTextures.end(); + ++local_tex_iter) + { + const ETextureIndex tex_index = *local_tex_iter; + const LLWearableType::EType wearable_type = sAvatarDictionary->getTEWearableType(tex_index); + const U32 wearable_count = gAgentWearables.getWearableCount(wearable_type); + for (U32 wearable_index = 0; wearable_index < wearable_count; wearable_index++) + { + S32 local_discard_level = getLocalDiscardLevel(*local_tex_iter, wearable_index); + if ((local_discard_level > (S32)(desired_tex_discard_level)) || + (local_discard_level < 0 )) + { + return false; + } + } + } + return true; + } + } + llassert(0); + return false; +} + + +bool LLVOAvatarSelf::isAllLocalTextureDataFinal() const +{ + const U32 desired_tex_discard_level = gSavedSettings.getU32("TextureDiscardLevel"); + // const U32 desired_tex_discard_level = 0; // hack to not bake textures on lower discard levels + + for (U32 i = 0; i < mBakedTextureDatas.size(); i++) + { + const LLAvatarAppearanceDictionary::BakedEntry *baked_dict = sAvatarDictionary->getBakedTexture((EBakedTextureIndex)i); + for (texture_vec_t::const_iterator local_tex_iter = baked_dict->mLocalTextures.begin(); + local_tex_iter != baked_dict->mLocalTextures.end(); + ++local_tex_iter) + { + const ETextureIndex tex_index = *local_tex_iter; + const LLWearableType::EType wearable_type = sAvatarDictionary->getTEWearableType(tex_index); + const U32 wearable_count = gAgentWearables.getWearableCount(wearable_type); + for (U32 wearable_index = 0; wearable_index < wearable_count; wearable_index++) + { + S32 local_discard_level = getLocalDiscardLevel(*local_tex_iter, wearable_index); + if ((local_discard_level > (S32)(desired_tex_discard_level)) || + (local_discard_level < 0 )) + { + return false; + } + } + } + } + return true; +} + +bool LLVOAvatarSelf::isTextureDefined(LLAvatarAppearanceDefines::ETextureIndex type, U32 index) const +{ + LLUUID id; + bool isDefined = true; + if (isIndexLocalTexture(type)) + { + const LLWearableType::EType wearable_type = sAvatarDictionary->getTEWearableType(type); + const U32 wearable_count = gAgentWearables.getWearableCount(wearable_type); + if (index >= wearable_count) + { + // invalid index passed in. check all textures of a given type + for (U32 wearable_index = 0; wearable_index < wearable_count; wearable_index++) + { + id = getLocalTextureID(type, wearable_index); + isDefined &= (id != IMG_DEFAULT_AVATAR && id != IMG_DEFAULT); + } + } + else + { + id = getLocalTextureID(type, index); + isDefined &= (id != IMG_DEFAULT_AVATAR && id != IMG_DEFAULT); + } + } + else + { + id = getTEImage(type)->getID(); + isDefined &= (id != IMG_DEFAULT_AVATAR && id != IMG_DEFAULT); + } + + return isDefined; +} + +//virtual +bool LLVOAvatarSelf::isTextureVisible(LLAvatarAppearanceDefines::ETextureIndex type, U32 index) const +{ + if (isIndexBakedTexture(type)) + { + return LLVOAvatar::isTextureVisible(type, (U32)0); + } + + LLUUID tex_id = getLocalTextureID(type,index); + return (tex_id != IMG_INVISIBLE) + || (LLDrawPoolAlpha::sShowDebugAlpha); +} + +//virtual +bool LLVOAvatarSelf::isTextureVisible(LLAvatarAppearanceDefines::ETextureIndex type, LLViewerWearable *wearable) const +{ + if (isIndexBakedTexture(type)) + { + return LLVOAvatar::isTextureVisible(type); + } + + U32 index; + if (gAgentWearables.getWearableIndex(wearable,index)) + { + return isTextureVisible(type,index); + } + else + { + LL_WARNS() << "Wearable not found" << LL_ENDL; + return false; + } +} + +bool LLVOAvatarSelf::areTexturesCurrent() const +{ + return gAgentWearables.areWearablesLoaded(); +} + +void LLVOAvatarSelf::invalidateComposite( LLTexLayerSet* layerset) +{ + LLViewerTexLayerSet *layer_set = dynamic_cast<LLViewerTexLayerSet*>(layerset); + if( !layer_set || !layer_set->getUpdatesEnabled() ) + { + return; + } + // LL_INFOS() << "LLVOAvatar::invalidComposite() " << layerset->getBodyRegionName() << LL_ENDL; + + layer_set->requestUpdate(); + layer_set->invalidateMorphMasks(); +} + +void LLVOAvatarSelf::invalidateAll() +{ + for (U32 i = 0; i < mBakedTextureDatas.size(); i++) + { + LLViewerTexLayerSet *layerset = getTexLayerSet(i); + invalidateComposite(layerset); + } + //mDebugSelfLoadTimer.reset(); +} + +//----------------------------------------------------------------------------- +// setCompositeUpdatesEnabled() +//----------------------------------------------------------------------------- +void LLVOAvatarSelf::setCompositeUpdatesEnabled( bool b ) +{ + for (U32 i = 0; i < mBakedTextureDatas.size(); i++) + { + setCompositeUpdatesEnabled(i, b); + } +} + +void LLVOAvatarSelf::setCompositeUpdatesEnabled(U32 index, bool b) +{ + LLViewerTexLayerSet *layerset = getTexLayerSet(index); + if (layerset ) + { + layerset->setUpdatesEnabled( b ); + } +} + +bool LLVOAvatarSelf::isCompositeUpdateEnabled(U32 index) +{ + LLViewerTexLayerSet *layerset = getTexLayerSet(index); + if (layerset) + { + return layerset->getUpdatesEnabled(); + } + return false; +} + +void LLVOAvatarSelf::setupComposites() +{ + for (U32 i = 0; i < mBakedTextureDatas.size(); i++) + { + ETextureIndex tex_index = mBakedTextureDatas[i].mTextureIndex; + bool layer_baked = isTextureDefined(tex_index, gAgentWearables.getWearableCount(tex_index)); + LLViewerTexLayerSet *layerset = getTexLayerSet(i); + if (layerset) + { + layerset->setUpdatesEnabled(!layer_baked); + } + } +} + +void LLVOAvatarSelf::updateComposites() +{ + for (U32 i = 0; i < mBakedTextureDatas.size(); i++) + { + LLViewerTexLayerSet *layerset = getTexLayerSet(i); + if (layerset + && ((i != BAKED_SKIRT) || isWearingWearableType(LLWearableType::WT_SKIRT))) + { + layerset->updateComposite(); + } + } +} + +// virtual +S32 LLVOAvatarSelf::getLocalDiscardLevel(ETextureIndex type, U32 wearable_index) const +{ + if (!isIndexLocalTexture(type)) return false; + + const LLLocalTextureObject *local_tex_obj = getLocalTextureObject(type, wearable_index); + if (local_tex_obj) + { + const LLViewerFetchedTexture* image = dynamic_cast<LLViewerFetchedTexture*>( local_tex_obj->getImage() ); + if (type >= 0 + && local_tex_obj->getID() != IMG_DEFAULT_AVATAR + && !image->isMissingAsset()) + { + return image->getDiscardLevel(); + } + else + { + // We don't care about this (no image associated with the layer) treat as fully loaded. + return 0; + } + } + return 0; +} + +// virtual +// Counts the memory footprint of local textures. +void LLVOAvatarSelf::getLocalTextureByteCount(S32* gl_bytes) const +{ + *gl_bytes = 0; + for (S32 type = 0; type < TEX_NUM_INDICES; type++) + { + if (!isIndexLocalTexture((ETextureIndex)type)) continue; + U32 max_tex = getNumWearables((ETextureIndex) type); + for (U32 num = 0; num < max_tex; num++) + { + const LLLocalTextureObject *local_tex_obj = getLocalTextureObject((ETextureIndex) type, num); + if (local_tex_obj) + { + const LLViewerFetchedTexture* image_gl = dynamic_cast<LLViewerFetchedTexture*>( local_tex_obj->getImage() ); + if (image_gl) + { + S32 bytes = (S32)image_gl->getWidth() * image_gl->getHeight() * image_gl->getComponents(); + + if (image_gl->hasGLTexture()) + { + *gl_bytes += bytes; + } + } + } + } + } +} + +// virtual +void LLVOAvatarSelf::setLocalTexture(ETextureIndex type, LLViewerTexture* src_tex, bool baked_version_ready, U32 index) +{ + if (!isIndexLocalTexture(type)) return; + + LLViewerFetchedTexture* tex = LLViewerTextureManager::staticCastToFetchedTexture(src_tex, true) ; + if(!tex) + { + return ; + } + + S32 desired_discard = isSelf() ? 0 : 2; + LLLocalTextureObject *local_tex_obj = getLocalTextureObject(type,index); + if (!local_tex_obj) + { + if (type >= TEX_NUM_INDICES) + { + LL_ERRS() << "Tried to set local texture with invalid type: (" << (U32) type << ", " << index << ")" << LL_ENDL; + return; + } + LLWearableType::EType wearable_type = sAvatarDictionary->getTEWearableType(type); + if (!gAgentWearables.getViewerWearable(wearable_type,index)) + { + // no wearable is loaded, cannot set the texture. + return; + } + gAgentWearables.addLocalTextureObject(wearable_type,type,index); + local_tex_obj = getLocalTextureObject(type,index); + if (!local_tex_obj) + { + LL_ERRS() << "Unable to create LocalTextureObject for wearable type & index: (" << (U32) wearable_type << ", " << index << ")" << LL_ENDL; + return; + } + + LLViewerTexLayerSet *layer_set = getLayerSet(type); + if (layer_set) + { + layer_set->cloneTemplates(local_tex_obj, type, gAgentWearables.getViewerWearable(wearable_type,index)); + } + + } + if (!baked_version_ready) + { + if (tex != local_tex_obj->getImage() || local_tex_obj->getBakedReady()) + { + local_tex_obj->setDiscard(MAX_DISCARD_LEVEL+1); + } + if (tex->getID() != IMG_DEFAULT_AVATAR) + { + if (local_tex_obj->getDiscard() > desired_discard) + { + S32 tex_discard = tex->getDiscardLevel(); + if (tex_discard >= 0 && tex_discard <= desired_discard) + { + local_tex_obj->setDiscard(tex_discard); + if (isSelf()) + { + requestLayerSetUpdate(type); + if (isEditingAppearance()) + { + LLVisualParamHint::requestHintUpdates(); + } + } + } + else + { + tex->setLoadedCallback(onLocalTextureLoaded, desired_discard, true, false, new LLAvatarTexData(getID(), type), NULL); + } + } + tex->setMinDiscardLevel(desired_discard); + } + } + local_tex_obj->setImage(tex); + local_tex_obj->setID(tex->getID()); + setBakedReady(type,baked_version_ready,index); +} + +//virtual +void LLVOAvatarSelf::setBakedReady(LLAvatarAppearanceDefines::ETextureIndex type, bool baked_version_exists, U32 index) +{ + if (!isIndexLocalTexture(type)) return; + LLLocalTextureObject *local_tex_obj = getLocalTextureObject(type,index); + if (local_tex_obj) + { + local_tex_obj->setBakedReady( baked_version_exists ); + } +} + + +// virtual +void LLVOAvatarSelf::dumpLocalTextures() const +{ + LL_INFOS() << "Local Textures:" << LL_ENDL; + + /* ETextureIndex baked_equiv[] = { + TEX_UPPER_BAKED, + if (isTextureDefined(baked_equiv[i])) */ + for (LLAvatarAppearanceDictionary::Textures::const_iterator iter = sAvatarDictionary->getTextures().begin(); + iter != sAvatarDictionary->getTextures().end(); + ++iter) + { + const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = iter->second; + if (!texture_dict->mIsLocalTexture || !texture_dict->mIsUsedByBakedTexture) + continue; + + const EBakedTextureIndex baked_index = texture_dict->mBakedTextureIndex; + const ETextureIndex baked_equiv = sAvatarDictionary->getBakedTexture(baked_index)->mTextureIndex; + + const std::string &name = texture_dict->mName; + const LLLocalTextureObject *local_tex_obj = getLocalTextureObject(iter->first, 0); + // index is baked texture - index is not relevant. putting in 0 as placeholder + if (isTextureDefined(baked_equiv, 0)) + { +#if LL_RELEASE_FOR_DOWNLOAD + // End users don't get to trivially see avatar texture IDs, makes textures + // easier to steal. JC + LL_INFOS() << "LocTex " << name << ": Baked " << LL_ENDL; +#else + LL_INFOS() << "LocTex " << name << ": Baked " << getTEImage(baked_equiv)->getID() << LL_ENDL; +#endif + } + else if (local_tex_obj && local_tex_obj->getImage() != NULL) + { + if (local_tex_obj->getImage()->getID() == IMG_DEFAULT_AVATAR) + { + LL_INFOS() << "LocTex " << name << ": None" << LL_ENDL; + } + else + { + LLViewerFetchedTexture* image = dynamic_cast<LLViewerFetchedTexture*>( local_tex_obj->getImage() ); + + LL_INFOS() << "LocTex " << name << ": " + << "Discard " << image->getDiscardLevel() << ", " + << "(" << image->getWidth() << ", " << image->getHeight() << ") " +#if !LL_RELEASE_FOR_DOWNLOAD + // End users don't get to trivially see avatar texture IDs, + // makes textures easier to steal + << image->getID() << " " +#endif + << "Priority: " << image->getMaxVirtualSize() + << LL_ENDL; + } + } + else + { + LL_INFOS() << "LocTex " << name << ": No LLViewerTexture" << LL_ENDL; + } + } +} + +//----------------------------------------------------------------------------- +// static +// onLocalTextureLoaded() +//----------------------------------------------------------------------------- + +void LLVOAvatarSelf::onLocalTextureLoaded(bool success, LLViewerFetchedTexture *src_vi, LLImageRaw* src_raw, LLImageRaw* aux_src, S32 discard_level, bool final, void* userdata) +{ + LLAvatarTexData *data = (LLAvatarTexData *)userdata; + LLVOAvatarSelf *self = (LLVOAvatarSelf *)gObjectList.findObject(data->mAvatarID); + if (self) + { + // We should only be handling local textures for ourself + self->localTextureLoaded(success, src_vi, src_raw, aux_src, discard_level, final, userdata); + } + // ensure data is cleaned up + if (final || !success) + { + delete data; + } +} + +/*virtual*/ void LLVOAvatarSelf::setImage(const U8 te, LLViewerTexture *imagep, const U32 index) +{ + if (isIndexLocalTexture((ETextureIndex)te)) + { + setLocalTexture((ETextureIndex)te, imagep, false ,index); + } + else + { + setTEImage(te,imagep); + } +} + +/*virtual*/ LLViewerTexture* LLVOAvatarSelf::getImage(const U8 te, const U32 index) const +{ + if (isIndexLocalTexture((ETextureIndex)te)) + { + return getLocalTextureGL((ETextureIndex)te,index); + } + else + { + return getTEImage(te); + } +} + + +// static +void LLVOAvatarSelf::dumpTotalLocalTextureByteCount() +{ + S32 gl_bytes = 0; + gAgentAvatarp->getLocalTextureByteCount(&gl_bytes); + LL_INFOS() << "Total Avatar LocTex GL:" << (gl_bytes/1024) << "KB" << LL_ENDL; +} + +bool LLVOAvatarSelf::getIsCloud() const +{ + // Let people know why they're clouded without spamming them into oblivion. + bool do_warn = false; + static LLTimer time_since_notice; + F32 update_freq = 30.0; + if (time_since_notice.getElapsedTimeF32() > update_freq) + { + time_since_notice.reset(); + do_warn = true; + } + + // do we have our body parts? + S32 shape_count = gAgentWearables.getWearableCount(LLWearableType::WT_SHAPE); + S32 hair_count = gAgentWearables.getWearableCount(LLWearableType::WT_HAIR); + S32 eye_count = gAgentWearables.getWearableCount(LLWearableType::WT_EYES); + S32 skin_count = gAgentWearables.getWearableCount(LLWearableType::WT_SKIN); + if (!shape_count || !hair_count || !eye_count || !skin_count) + { + if (do_warn) + { + LL_INFOS() << "Self is clouded due to missing one or more required body parts: " + << (shape_count ? "" : "SHAPE ") + << (hair_count ? "" : "HAIR ") + << (eye_count ? "" : "EYES ") + << (skin_count ? "" : "SKIN ") + << LL_ENDL; + } + return true; + } + + if (!isTextureDefined(TEX_HAIR, 0)) + { + if (do_warn) + { + LL_INFOS() << "Self is clouded because of no hair texture" << LL_ENDL; + } + return true; + } + + if (!mPreviousFullyLoaded) + { + if (!isLocalTextureDataAvailable(getLayerSet(BAKED_LOWER)) && + (!isTextureDefined(TEX_LOWER_BAKED, 0))) + { + if (do_warn) + { + LL_INFOS() << "Self is clouded because lower textures not baked" << LL_ENDL; + } + return true; + } + + if (!isLocalTextureDataAvailable(getLayerSet(BAKED_UPPER)) && + (!isTextureDefined(TEX_UPPER_BAKED, 0))) + { + if (do_warn) + { + LL_INFOS() << "Self is clouded because upper textures not baked" << LL_ENDL; + } + return true; + } + + for (U32 i = 0; i < mBakedTextureDatas.size(); i++) + { + if (i == BAKED_SKIRT && !isWearingWearableType(LLWearableType::WT_SKIRT)) + continue; + + const BakedTextureData& texture_data = mBakedTextureDatas[i]; + if (!isTextureDefined(texture_data.mTextureIndex, 0)) + continue; + + // Check for the case that texture is defined but not sufficiently loaded to display anything. + const LLViewerTexture* baked_img = getImage( texture_data.mTextureIndex, 0 ); + if (!baked_img || !baked_img->hasGLTexture()) + { + if (do_warn) + { + LL_INFOS() << "Self is clouded because texture at index " << i + << " (texture index is " << texture_data.mTextureIndex << ") is not loaded" << LL_ENDL; + } + return true; + } + } + + LL_DEBUGS() << "Avatar de-clouded" << LL_ENDL; + } + return false; +} + +/*static*/ +void LLVOAvatarSelf::debugOnTimingLocalTexLoaded(bool success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, bool final, void* userdata) +{ + if (gAgentAvatarp.notNull()) + { + gAgentAvatarp->debugTimingLocalTexLoaded(success, src_vi, src, aux_src, discard_level, final, userdata); + } +} + +void LLVOAvatarSelf::debugTimingLocalTexLoaded(bool success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, bool final, void* userdata) +{ + LLAvatarTexData *data = (LLAvatarTexData *)userdata; + if (!data) + { + return; + } + + ETextureIndex index = data->mIndex; + + if (index < 0 || index >= TEX_NUM_INDICES) + { + return; + } + + if (discard_level >=0 && discard_level <= MAX_DISCARD_LEVEL) // ignore discard level -1, as it means we have no data. + { + mDebugTextureLoadTimes[(U32)index][(U32)discard_level] = mDebugSelfLoadTimer.getElapsedTimeF32(); + } + if (final) + { + delete data; + } +} + +void LLVOAvatarSelf::debugBakedTextureUpload(EBakedTextureIndex index, bool finished) +{ + U32 done = 0; + if (finished) + { + done = 1; + } + mDebugBakedTextureTimes[index][done] = mDebugSelfLoadTimer.getElapsedTimeF32(); +} + +const std::string LLVOAvatarSelf::verboseDebugDumpLocalTextureDataInfo(const LLViewerTexLayerSet* layerset) const +{ + std::ostringstream outbuf; + LLWearableType *wr_inst = LLWearableType::getInstance(); + for (LLAvatarAppearanceDictionary::BakedTextures::const_iterator baked_iter = + sAvatarDictionary->getBakedTextures().begin(); + baked_iter != sAvatarDictionary->getBakedTextures().end(); + ++baked_iter) + { + const EBakedTextureIndex baked_index = baked_iter->first; + if (layerset == mBakedTextureDatas[baked_index].mTexLayerSet) + { + outbuf << "baked_index: " << baked_index << "\n"; + const LLAvatarAppearanceDictionary::BakedEntry *baked_dict = baked_iter->second; + for (texture_vec_t::const_iterator local_tex_iter = baked_dict->mLocalTextures.begin(); + local_tex_iter != baked_dict->mLocalTextures.end(); + ++local_tex_iter) + { + const ETextureIndex tex_index = *local_tex_iter; + const std::string tex_name = sAvatarDictionary->getTexture(tex_index)->mName; + outbuf << " tex_index " << (S32) tex_index << " name " << tex_name << "\n"; + const LLWearableType::EType wearable_type = sAvatarDictionary->getTEWearableType(tex_index); + const U32 wearable_count = gAgentWearables.getWearableCount(wearable_type); + if (wearable_count > 0) + { + for (U32 wearable_index = 0; wearable_index < wearable_count; wearable_index++) + { + outbuf << " " << wr_inst->getTypeName(wearable_type) << " " << wearable_index << ":"; + const LLLocalTextureObject *local_tex_obj = getLocalTextureObject(tex_index, wearable_index); + if (local_tex_obj) + { + LLViewerFetchedTexture* image = dynamic_cast<LLViewerFetchedTexture*>( local_tex_obj->getImage() ); + if (tex_index >= 0 + && local_tex_obj->getID() != IMG_DEFAULT_AVATAR + && !image->isMissingAsset()) + { + outbuf << " id: " << image->getID() + << " refs: " << image->getNumRefs() + << " glocdisc: " << getLocalDiscardLevel(tex_index, wearable_index) + << " discard: " << image->getDiscardLevel() + << " desired: " << image->getDesiredDiscardLevel() + << " vsize: " << image->getMaxVirtualSize() + << " ts: " << image->getTextureState() + << " bl: " << image->getBoostLevel() + << " fl: " << image->isFullyLoaded() // this is not an accessor for mFullyLoaded - see comment there. + << " cl: " << (image->isFullyLoaded() && image->getDiscardLevel()==0) // "completely loaded" + << " mvs: " << image->getMaxVirtualSize() + << " mvsc: " << image->getMaxVirtualSizeResetCounter() + << " mem: " << image->getTextureMemory(); + } + } + outbuf << "\n"; + } + } + } + break; + } + } + return outbuf.str(); +} + +void LLVOAvatarSelf::dumpAllTextures() const +{ + std::string vd_text = "Local textures per baked index and wearable:\n"; + for (LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary::BakedTextures::const_iterator baked_iter = sAvatarDictionary->getBakedTextures().begin(); + baked_iter != sAvatarDictionary->getBakedTextures().end(); + ++baked_iter) + { + const LLAvatarAppearanceDefines::EBakedTextureIndex baked_index = baked_iter->first; + const LLViewerTexLayerSet *layerset = debugGetLayerSet(baked_index); + if (!layerset) continue; + const LLViewerTexLayerSetBuffer *layerset_buffer = layerset->getViewerComposite(); + if (!layerset_buffer) continue; + vd_text += verboseDebugDumpLocalTextureDataInfo(layerset); + } + LL_DEBUGS("Avatar") << vd_text << LL_ENDL; +} + +const std::string LLVOAvatarSelf::debugDumpLocalTextureDataInfo(const LLViewerTexLayerSet* layerset) const +{ + std::string text=""; + LLWearableType *wr_inst = LLWearableType::getInstance(); + + text = llformat("[Final:%d Avail:%d] ",isLocalTextureDataFinal(layerset), isLocalTextureDataAvailable(layerset)); + + /* if (layerset == mBakedTextureDatas[BAKED_HEAD].mTexLayerSet) + return getLocalDiscardLevel(TEX_HEAD_BODYPAINT) >= 0; */ + for (LLAvatarAppearanceDictionary::BakedTextures::const_iterator baked_iter = sAvatarDictionary->getBakedTextures().begin(); + baked_iter != sAvatarDictionary->getBakedTextures().end(); + ++baked_iter) + { + const EBakedTextureIndex baked_index = baked_iter->first; + if (layerset == mBakedTextureDatas[baked_index].mTexLayerSet) + { + const LLAvatarAppearanceDictionary::BakedEntry *baked_dict = baked_iter->second; + text += llformat("%d-%s ( ",baked_index, baked_dict->mName.c_str()); + for (texture_vec_t::const_iterator local_tex_iter = baked_dict->mLocalTextures.begin(); + local_tex_iter != baked_dict->mLocalTextures.end(); + ++local_tex_iter) + { + const ETextureIndex tex_index = *local_tex_iter; + const LLWearableType::EType wearable_type = sAvatarDictionary->getTEWearableType(tex_index); + const U32 wearable_count = gAgentWearables.getWearableCount(wearable_type); + if (wearable_count > 0) + { + text += wr_inst->getTypeName(wearable_type) + ":"; + for (U32 wearable_index = 0; wearable_index < wearable_count; wearable_index++) + { + const U32 discard_level = getLocalDiscardLevel(tex_index, wearable_index); + std::string discard_str = llformat("%d ",discard_level); + text += llformat("%d ",discard_level); + } + } + } + text += ")"; + break; + } + } + return text; +} + +const std::string LLVOAvatarSelf::debugDumpAllLocalTextureDataInfo() const +{ + std::string text; + const U32 override_tex_discard_level = gSavedSettings.getU32("TextureDiscardLevel"); + + for (U32 i = 0; i < mBakedTextureDatas.size(); i++) + { + const LLAvatarAppearanceDictionary::BakedEntry *baked_dict = sAvatarDictionary->getBakedTexture((EBakedTextureIndex)i); + bool is_texture_final = true; + for (texture_vec_t::const_iterator local_tex_iter = baked_dict->mLocalTextures.begin(); + local_tex_iter != baked_dict->mLocalTextures.end(); + ++local_tex_iter) + { + const ETextureIndex tex_index = *local_tex_iter; + const LLWearableType::EType wearable_type = sAvatarDictionary->getTEWearableType(tex_index); + const U32 wearable_count = gAgentWearables.getWearableCount(wearable_type); + for (U32 wearable_index = 0; wearable_index < wearable_count; wearable_index++) + { + is_texture_final &= (getLocalDiscardLevel(*local_tex_iter, wearable_index) <= (S32)(override_tex_discard_level)); + } + } + text += llformat("%s:%d ",baked_dict->mName.c_str(),is_texture_final); + } + return text; +} + +void LLVOAvatarSelf::appearanceChangeMetricsCoro(std::string url) +{ + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("appearanceChangeMetrics", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + LLCore::HttpOptions::ptr_t httpOpts = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions); + + S32 currentSequence = mMetricSequence; + if (S32_MAX == ++mMetricSequence) + mMetricSequence = 0; + + LLSD msg; + msg["message"] = "ViewerAppearanceChangeMetrics"; + msg["session_id"] = gAgentSessionID; + msg["agent_id"] = gAgentID; + msg["sequence"] = currentSequence; + msg["initial"] = mInitialMetric; + msg["break"] = false; + msg["duration"] = mTimeSinceLastRezMessage.getElapsedTimeF32(); + + // Status of our own rezzing. + msg["rez_status"] = LLVOAvatar::rezStatusToString(getRezzedStatus()); + msg["first_decloud_time"] = getFirstDecloudTime(); + + // Status of all nearby avs including ourself. + msg["nearby"] = LLSD::emptyArray(); + std::vector<S32> rez_counts; + F32 avg_time; + S32 total_cloud_avatars; + LLVOAvatar::getNearbyRezzedStats(rez_counts, avg_time, total_cloud_avatars); + for (S32 rez_stat = 0; rez_stat < rez_counts.size(); ++rez_stat) + { + std::string rez_status_name = LLVOAvatar::rezStatusToString(rez_stat); + msg["nearby"][rez_status_name] = rez_counts[rez_stat]; + } + msg["nearby"]["avg_decloud_time"] = avg_time; + msg["nearby"]["cloud_total"] = total_cloud_avatars; + + // std::vector<std::string> bucket_fields("timer_name","is_self","grid_x","grid_y","is_using_server_bake"); + std::vector<std::string> by_fields; + by_fields.push_back("timer_name"); + by_fields.push_back("completed"); + by_fields.push_back("grid_x"); + by_fields.push_back("grid_y"); + by_fields.push_back("is_using_server_bakes"); + by_fields.push_back("is_self"); + by_fields.push_back("central_bake_version"); + LLSD summary = summarize_by_buckets(mPendingTimerRecords, by_fields, std::string("elapsed")); + msg["timers"] = summary; + + mPendingTimerRecords.clear(); + + LL_DEBUGS("Avatar") << avString() << "message: " << ll_pretty_print_sd(msg) << LL_ENDL; + + gPendingMetricsUploads++; + + LLSD result = httpAdapter->postAndSuspend(httpRequest, url, msg); + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + gPendingMetricsUploads--; + + if (!status) + { + LL_WARNS("Avatar") << "Unable to upload statistics" << LL_ENDL; + return; + } + else + { + LL_INFOS("Avatar") << "Statistics upload OK" << LL_ENDL; + mInitialMetric = false; + } +} + +bool LLVOAvatarSelf::updateAvatarRezMetrics(bool force_send) +{ + const F32 AV_METRICS_INTERVAL_QA = 30.0; + F32 send_period = 300.0; + + static LLCachedControl<bool> qa_mode_metrics(gSavedSettings,"QAModeMetrics"); + if (qa_mode_metrics) + { + send_period = AV_METRICS_INTERVAL_QA; + } + + if (force_send || mTimeSinceLastRezMessage.getElapsedTimeF32() > send_period) + { + // Stats for completed phases have been getting logged as they + // complete. This will give us stats for any timers that + // haven't finished as of the metric's being sent. + + if (force_send) + { + LLVOAvatar::logPendingPhasesAllAvatars(); + } + sendViewerAppearanceChangeMetrics(); + } + + return false; +} + +void LLVOAvatarSelf::addMetricsTimerRecord(const LLSD& record) +{ + mPendingTimerRecords.push_back(record); +} + +bool operator<(const LLSD& a, const LLSD& b) +{ + std::ostringstream aout, bout; + aout << LLSDNotationStreamer(a); + bout << LLSDNotationStreamer(b); + std::string astring = aout.str(); + std::string bstring = bout.str(); + + return astring < bstring; + +} + +// Given a vector of LLSD records, return an LLSD array of bucketed stats for val_field. +LLSD summarize_by_buckets(std::vector<LLSD> in_records, + std::vector<std::string> by_fields, + std::string val_field) +{ + LLSD result = LLSD::emptyArray(); + std::map<LLSD,LLViewerStats::StatsAccumulator> accum; + for (std::vector<LLSD>::iterator in_record_iter = in_records.begin(); + in_record_iter != in_records.end(); ++in_record_iter) + { + LLSD& record = *in_record_iter; + LLSD key; + for (std::vector<std::string>::iterator field_iter = by_fields.begin(); + field_iter != by_fields.end(); ++field_iter) + { + const std::string& field = *field_iter; + key[field] = record[field]; + } + LLViewerStats::StatsAccumulator& stats = accum[key]; + F32 value = record[val_field].asReal(); + stats.push(value); + } + for (std::map<LLSD,LLViewerStats::StatsAccumulator>::iterator accum_it = accum.begin(); + accum_it != accum.end(); ++accum_it) + { + LLSD out_record = accum_it->first; + out_record["stats"] = accum_it->second.asLLSD(); + result.append(out_record); + } + return result; +} + +void LLVOAvatarSelf::sendViewerAppearanceChangeMetrics() +{ + std::string caps_url; + if (getRegion()) + { + // runway - change here to activate. + caps_url = getRegion()->getCapability("ViewerMetrics"); + } + if (!caps_url.empty()) + { + + LLCoros::instance().launch("LLVOAvatarSelf::appearanceChangeMetricsCoro", + boost::bind(&LLVOAvatarSelf::appearanceChangeMetricsCoro, this, caps_url)); + mTimeSinceLastRezMessage.reset(); + } +} + +const LLUUID& LLVOAvatarSelf::grabBakedTexture(EBakedTextureIndex baked_index) const +{ + if (canGrabBakedTexture(baked_index)) + { + ETextureIndex tex_index = sAvatarDictionary->bakedToLocalTextureIndex(baked_index); + if (tex_index == TEX_NUM_INDICES) + { + return LLUUID::null; + } + return getTEImage( tex_index )->getID(); + } + return LLUUID::null; +} + +bool LLVOAvatarSelf::canGrabBakedTexture(EBakedTextureIndex baked_index) const +{ + ETextureIndex tex_index = sAvatarDictionary->bakedToLocalTextureIndex(baked_index); + if (tex_index == TEX_NUM_INDICES) + { + return false; + } + // Check if the texture hasn't been baked yet. + if (!isTextureDefined(tex_index, 0)) + { + LL_DEBUGS() << "getTEImage( " << (U32) tex_index << " )->getID() == IMG_DEFAULT_AVATAR" << LL_ENDL; + return false; + } + + if (gAgent.isGodlikeWithoutAdminMenuFakery()) + return true; + + // Check permissions of textures that show up in the + // baked texture. We don't want people copying people's + // work via baked textures. + + const LLAvatarAppearanceDictionary::BakedEntry *baked_dict = sAvatarDictionary->getBakedTexture(baked_index); + for (texture_vec_t::const_iterator iter = baked_dict->mLocalTextures.begin(); + iter != baked_dict->mLocalTextures.end(); + ++iter) + { + const ETextureIndex t_index = (*iter); + LLWearableType::EType wearable_type = sAvatarDictionary->getTEWearableType(t_index); + U32 count = gAgentWearables.getWearableCount(wearable_type); + LL_DEBUGS() << "Checking index " << (U32) t_index << " count: " << count << LL_ENDL; + + for (U32 wearable_index = 0; wearable_index < count; ++wearable_index) + { + LLViewerWearable *wearable = gAgentWearables.getViewerWearable(wearable_type, wearable_index); + if (wearable) + { + const LLLocalTextureObject *texture = wearable->getLocalTextureObject((S32)t_index); + const LLUUID& texture_id = texture->getID(); + if (texture_id != IMG_DEFAULT_AVATAR) + { + // Search inventory for this texture. + LLViewerInventoryCategory::cat_array_t cats; + LLViewerInventoryItem::item_array_t items; + LLAssetIDMatches asset_id_matches(texture_id); + gInventory.collectDescendentsIf(LLUUID::null, + cats, + items, + LLInventoryModel::INCLUDE_TRASH, + asset_id_matches); + + bool can_grab = false; + LL_DEBUGS() << "item count for asset " << texture_id << ": " << items.size() << LL_ENDL; + if (items.size()) + { + // search for full permissions version + for (S32 i = 0; i < items.size(); i++) + { + LLViewerInventoryItem* itemp = items[i]; + if (itemp->getIsFullPerm()) + { + can_grab = true; + break; + } + } + } + if (!can_grab) return false; + } + } + } + } + + return true; +} + +void LLVOAvatarSelf::addLocalTextureStats( ETextureIndex type, LLViewerFetchedTexture* imagep, + F32 texel_area_ratio, bool render_avatar, bool covered_by_baked) +{ + if (!isIndexLocalTexture(type)) return; + + // Sunshine - ignoring covered_by_baked will force local textures + // to always load. Fix for SH-4001 and many related issues. Do + // not restore this without some more targetted fix for the local + // textures failing to load issue. + //if (!covered_by_baked) + { + if (imagep->getID() != IMG_DEFAULT_AVATAR) + { + imagep->setNoDelete(); + if (imagep->getDiscardLevel() != 0) + { + F32 desired_pixels; + desired_pixels = llmin(mPixelArea, (F32)getTexImageArea()); + + imagep->setBoostLevel(getAvatarBoostLevel()); + imagep->resetTextureStats(); + imagep->setMaxVirtualSizeResetInterval(MAX_TEXTURE_VIRTUAL_SIZE_RESET_INTERVAL); + imagep->addTextureStats( desired_pixels / texel_area_ratio ); + imagep->forceUpdateBindStats() ; + if (imagep->getDiscardLevel() < 0) + { + mHasGrey = true; // for statistics gathering + } + } + } + else + { + // texture asset is missing + mHasGrey = true; // for statistics gathering + } + } +} + +LLLocalTextureObject* LLVOAvatarSelf::getLocalTextureObject(LLAvatarAppearanceDefines::ETextureIndex i, U32 wearable_index) const +{ + LLWearableType::EType type = sAvatarDictionary->getTEWearableType(i); + LLViewerWearable* wearable = gAgentWearables.getViewerWearable(type, wearable_index); + if (wearable) + { + return wearable->getLocalTextureObject(i); + } + + return NULL; +} + +//----------------------------------------------------------------------------- +// getBakedTE() +// Used by the LayerSet. (Layer sets don't in general know what textures depend on them.) +//----------------------------------------------------------------------------- +ETextureIndex LLVOAvatarSelf::getBakedTE( const LLViewerTexLayerSet* layerset ) const +{ + for (U32 i = 0; i < mBakedTextureDatas.size(); i++) + { + if (layerset == mBakedTextureDatas[i].mTexLayerSet ) + { + return mBakedTextureDatas[i].mTextureIndex; + } + } + llassert(0); + return TEX_HEAD_BAKED; +} + +// FIXME: This is not called consistently. Something may be broken. +void LLVOAvatarSelf::outputRezDiagnostics() const +{ + if(!gSavedSettings.getBOOL("DebugAvatarLocalTexLoadedTime")) + { + return ; + } + + const F32 final_time = mDebugSelfLoadTimer.getElapsedTimeF32(); + LL_DEBUGS("Avatar") << "REZTIME: Myself rez stats:" << LL_ENDL; + LL_DEBUGS("Avatar") << "\t Time from avatar creation to load wearables: " << (S32)mDebugTimeWearablesLoaded << LL_ENDL; + LL_DEBUGS("Avatar") << "\t Time from avatar creation to de-cloud: " << (S32)mDebugTimeAvatarVisible << LL_ENDL; + LL_DEBUGS("Avatar") << "\t Time from avatar creation to de-cloud for others: " << (S32)final_time << LL_ENDL; + LL_DEBUGS("Avatar") << "\t Load time for each texture: " << LL_ENDL; + for (U32 i = 0; i < LLAvatarAppearanceDefines::TEX_NUM_INDICES; ++i) + { + std::stringstream out; + out << "\t\t (" << i << ") "; + U32 j=0; + for (j=0; j <= MAX_DISCARD_LEVEL; j++) + { + out << "\t"; + S32 load_time = (S32)mDebugTextureLoadTimes[i][j]; + if (load_time == -1) + { + out << "*"; + if (j == 0) + break; + } + else + { + out << load_time; + } + } + + // Don't print out non-existent textures. + if (j != 0) + { + LL_DEBUGS("Avatar") << out.str() << LL_ENDL; + } + } + LL_DEBUGS("Avatar") << "\t Time points for each upload (start / finish)" << LL_ENDL; + for (U32 i = 0; i < LLAvatarAppearanceDefines::BAKED_NUM_INDICES; ++i) + { + LL_DEBUGS("Avatar") << "\t\t (" << i << ") \t" << (S32)mDebugBakedTextureTimes[i][0] << " / " << (S32)mDebugBakedTextureTimes[i][1] << LL_ENDL; + } + + for (LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary::BakedTextures::const_iterator baked_iter = sAvatarDictionary->getBakedTextures().begin(); + baked_iter != sAvatarDictionary->getBakedTextures().end(); + ++baked_iter) + { + const LLAvatarAppearanceDefines::EBakedTextureIndex baked_index = baked_iter->first; + const LLViewerTexLayerSet *layerset = debugGetLayerSet(baked_index); + if (!layerset) continue; + const LLViewerTexLayerSetBuffer *layerset_buffer = layerset->getViewerComposite(); + if (!layerset_buffer) continue; + LL_DEBUGS("Avatar") << layerset_buffer->dumpTextureInfo() << LL_ENDL; + } + + dumpAllTextures(); +} + +void LLVOAvatarSelf::outputRezTiming(const std::string& msg) const +{ + LL_DEBUGS("Avatar") + << avString() + << llformat("%s. Time from avatar creation: %.2f", msg.c_str(), mDebugSelfLoadTimer.getElapsedTimeF32()) + << LL_ENDL; +} + +void LLVOAvatarSelf::reportAvatarRezTime() const +{ + // TODO: report mDebugSelfLoadTimer.getElapsedTimeF32() somehow. +} + +// SUNSHINE CLEANUP - not clear we need any of this, may be sufficient to request server appearance in llviewermenu.cpp:handle_rebake_textures() +void LLVOAvatarSelf::forceBakeAllTextures(bool slam_for_debug) +{ + LL_INFOS() << "TAT: forced full rebake. " << LL_ENDL; + + for (U32 i = 0; i < mBakedTextureDatas.size(); i++) + { + ETextureIndex baked_index = mBakedTextureDatas[i].mTextureIndex; + LLViewerTexLayerSet* layer_set = getLayerSet(baked_index); + if (layer_set) + { + if (slam_for_debug) + { + layer_set->setUpdatesEnabled(true); + } + + invalidateComposite(layer_set); + add(LLStatViewer::TEX_REBAKES, 1); + } + else + { + LL_WARNS() << "TAT: NO LAYER SET FOR " << (S32)baked_index << LL_ENDL; + } + } + + // Don't know if this is needed + updateMeshTextures(); +} + +//----------------------------------------------------------------------------- +// requestLayerSetUpdate() +//----------------------------------------------------------------------------- +void LLVOAvatarSelf::requestLayerSetUpdate(ETextureIndex index ) +{ + /* switch(index) + case LOCTEX_UPPER_BODYPAINT: + case LOCTEX_UPPER_SHIRT: + if( mUpperBodyLayerSet ) + mUpperBodyLayerSet->requestUpdate(); */ + const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = sAvatarDictionary->getTexture(index); + if (!texture_dict) + return; + if (!texture_dict->mIsLocalTexture || !texture_dict->mIsUsedByBakedTexture) + return; + const EBakedTextureIndex baked_index = texture_dict->mBakedTextureIndex; + if (mBakedTextureDatas[baked_index].mTexLayerSet) + { + mBakedTextureDatas[baked_index].mTexLayerSet->requestUpdate(); + } +} + +LLViewerTexLayerSet* LLVOAvatarSelf::getLayerSet(ETextureIndex index) const +{ + /* switch(index) + case TEX_HEAD_BAKED: + case TEX_HEAD_BODYPAINT: + return mHeadLayerSet; */ + const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = sAvatarDictionary->getTexture(index); + if (texture_dict && texture_dict->mIsUsedByBakedTexture) + { + const EBakedTextureIndex baked_index = texture_dict->mBakedTextureIndex; + return getLayerSet(baked_index); + } + return NULL; +} + +LLViewerTexLayerSet* LLVOAvatarSelf::getLayerSet(EBakedTextureIndex baked_index) const +{ + /* switch(index) + case TEX_HEAD_BAKED: + case TEX_HEAD_BODYPAINT: + return mHeadLayerSet; */ + if (baked_index >= 0 && baked_index < BAKED_NUM_INDICES) + { + return getTexLayerSet(baked_index); + } + return NULL; +} + + + + +// static +void LLVOAvatarSelf::onCustomizeStart(bool disable_camera_switch) +{ + if (isAgentAvatarValid()) + { + LLUIUsage::instance().logCommand("Avatar.CustomizeStart"); + if (!gAgentAvatarp->mEndCustomizeCallback.get()) + { + gAgentAvatarp->mEndCustomizeCallback = new LLUpdateAppearanceOnDestroy; + } + + gAgentAvatarp->mIsEditingAppearance = true; + gAgentAvatarp->mUseLocalAppearance = true; + + if (gSavedSettings.getBOOL("AppearanceCameraMovement") && !disable_camera_switch) + { + gAgentCamera.changeCameraToCustomizeAvatar(); + } + + gAgentAvatarp->invalidateAll(); // mark all bakes as dirty, request updates + gAgentAvatarp->updateMeshTextures(); // make sure correct textures are applied to the avatar mesh. + gAgentAvatarp->updateTextures(); // call updateTextureStats + } +} + +// static +void LLVOAvatarSelf::onCustomizeEnd(bool disable_camera_switch) +{ + + if (isAgentAvatarValid()) + { + gAgentAvatarp->mIsEditingAppearance = false; + gAgentAvatarp->invalidateAll(); + + if (gSavedSettings.getBOOL("AppearanceCameraMovement") && !disable_camera_switch) + { + gAgentCamera.changeCameraToDefault(); + gAgentCamera.resetView(); + } + + // Dereferencing the previous callback will cause + // updateAppearanceFromCOF to be called, whenever all refs + // have resolved. + gAgentAvatarp->mEndCustomizeCallback = NULL; + } +} + +// virtual +bool LLVOAvatarSelf::shouldRenderRigged() const +{ + return gAgent.needsRenderAvatar(); +} + +// HACK: this will null out the avatar's local texture IDs before the TE message is sent +// to ensure local texture IDs are not sent to other clients in the area. +// this is a short-term solution. The long term solution will be to not set the texture +// IDs in the avatar object, and keep them only in the wearable. +// This will involve further refactoring that is too risky for the initial release of 2.0. +bool LLVOAvatarSelf::sendAppearanceMessage(LLMessageSystem *mesgsys) const +{ + LLUUID texture_id[TEX_NUM_INDICES]; + // pack away current TEs to make sure we don't send them out + for (LLAvatarAppearanceDictionary::Textures::const_iterator iter = sAvatarDictionary->getTextures().begin(); + iter != sAvatarDictionary->getTextures().end(); + ++iter) + { + const ETextureIndex index = iter->first; + const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = iter->second; + if (!texture_dict->mIsBakedTexture) + { + LLTextureEntry* entry = getTE((U8) index); + texture_id[index] = entry->getID(); + entry->setID(IMG_DEFAULT_AVATAR); + } + } + + bool success = packTEMessage(mesgsys); + + // unpack TEs to make sure we don't re-trigger a bake + for (LLAvatarAppearanceDictionary::Textures::const_iterator iter = sAvatarDictionary->getTextures().begin(); + iter != sAvatarDictionary->getTextures().end(); + ++iter) + { + const ETextureIndex index = iter->first; + const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = iter->second; + if (!texture_dict->mIsBakedTexture) + { + LLTextureEntry* entry = getTE((U8) index); + entry->setID(texture_id[index]); + } + } + + return success; +} + +//------------------------------------------------------------------------ +// sendHoverHeight() +//------------------------------------------------------------------------ +void LLVOAvatarSelf::sendHoverHeight() const +{ + std::string url = gAgent.getRegionCapability("AgentPreferences"); + + if (!url.empty()) + { + LLSD update = LLSD::emptyMap(); + const LLVector3& hover_offset = getHoverOffset(); + update["hover_height"] = hover_offset[2]; + + LL_DEBUGS("Avatar") << avString() << "sending hover height value " << hover_offset[2] << LL_ENDL; + + // *TODO: - this class doesn't really do anything, could just use a base + // class responder if nothing else gets added. + // (comment from removed Responder) + LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost(url, update, + "Hover height sent to sim", "Hover height not sent to sim"); + mLastHoverOffsetSent = hover_offset; + } +} + +void LLVOAvatarSelf::setHoverOffset(const LLVector3& hover_offset, bool send_update) +{ + if (getHoverOffset() != hover_offset) + { + LL_INFOS("Avatar") << avString() << " setting hover due to change " << hover_offset[2] << LL_ENDL; + LLVOAvatar::setHoverOffset(hover_offset, send_update); + } + if (send_update && (hover_offset != mLastHoverOffsetSent)) + { + LL_INFOS("Avatar") << avString() << " sending hover due to change " << hover_offset[2] << LL_ENDL; + sendHoverHeight(); + } +} + +//------------------------------------------------------------------------ +// needsRenderBeam() +//------------------------------------------------------------------------ +bool LLVOAvatarSelf::needsRenderBeam() +{ + LLTool *tool = LLToolMgr::getInstance()->getCurrentTool(); + + bool is_touching_or_grabbing = (tool == LLToolGrab::getInstance() && LLToolGrab::getInstance()->isEditing()); + LLViewerObject* objp = LLToolGrab::getInstance()->getEditingObject(); + if (objp // might need to be "!objp ||" instead of "objp &&". + && (objp->isAttachment() || objp->isAvatar())) + { + // don't render grab tool's selection beam on hud objects, + // attachments or avatars + is_touching_or_grabbing = false; + } + return is_touching_or_grabbing || (getAttachmentState() & AGENT_STATE_EDITING && LLSelectMgr::getInstance()->shouldShowSelection()); +} + +// static +void LLVOAvatarSelf::deleteScratchTextures() +{ + for(std::map< LLGLenum, LLGLuint*>::iterator it = sScratchTexNames.begin(), end_it = sScratchTexNames.end(); + it != end_it; + ++it) + { + LLImageGL::deleteTextures(1, (U32 *)it->second ); + stop_glerror(); + } + + if( sScratchTexBytes.value() ) + { + LL_DEBUGS() << "Clearing Scratch Textures " << (S32Kilobytes)sScratchTexBytes << LL_ENDL; + + delete_and_clear(sScratchTexNames); + sScratchTexBytes = S32Bytes(0); + } +} + +// static +void LLVOAvatarSelf::dumpScratchTextureByteCount() +{ + LL_INFOS() << "Scratch Texture GL: " << (sScratchTexBytes/1024) << "KB" << LL_ENDL; +} + +void LLVOAvatarSelf::dumpWearableInfo(LLAPRFile& outfile) +{ + apr_file_t* file = outfile.getFileHandle(); + if (!file) + { + return; + } + + + apr_file_printf( file, "\n<wearable_info>\n" ); + + LLWearableData *wd = getWearableData(); + LLWearableType *wr_inst = LLWearableType::getInstance(); + for (S32 type = 0; type < LLWearableType::WT_COUNT; type++) + { + const std::string& type_name = wr_inst->getTypeName((LLWearableType::EType)type); + for (U32 j=0; j< wd->getWearableCount((LLWearableType::EType)type); j++) + { + LLViewerWearable *wearable = gAgentWearables.getViewerWearable((LLWearableType::EType)type,j); + apr_file_printf( file, "\n\t <wearable type=\"%s\" name=\"%s\"/>\n", + type_name.c_str(), wearable->getName().c_str() ); + LLWearable::visual_param_vec_t v_params; + wearable->getVisualParams(v_params); + for (LLWearable::visual_param_vec_t::iterator it = v_params.begin(); + it != v_params.end(); ++it) + { + LLVisualParam *param = *it; + dump_visual_param(file, param, param->getWeight()); + } + } + } + apr_file_printf( file, "\n</wearable_info>\n" ); +} |