From fb1594535ec578d6601d54557ca5bf1a77c45351 Mon Sep 17 00:00:00 2001 From: Shyotl Date: Sat, 2 Jun 2012 17:32:19 -0500 Subject: [PATCH 01/28] Intermediate step in refactoring appearance panel --- indra/llui/llscrollingpanellist.h | 12 +- indra/newview/CMakeLists.txt | 6 + indra/newview/llfloatercustomize.cpp | 1707 +------------------ indra/newview/llfloatercustomize.h | 1 - indra/newview/llpaneleditwearable.cpp | 1405 +++++++++++++++ indra/newview/llpaneleditwearable.h | 114 ++ indra/newview/llscrollingpanelparam.cpp | 329 ++++ indra/newview/llscrollingpanelparam.h | 76 + indra/newview/llscrollingpanelparambase.cpp | 139 ++ indra/newview/llscrollingpanelparambase.h | 61 + indra/newview/lltoolmorph.cpp | 9 +- indra/newview/llwearable.cpp | 43 + 12 files changed, 2201 insertions(+), 1701 deletions(-) create mode 100644 indra/newview/llpaneleditwearable.cpp create mode 100644 indra/newview/llpaneleditwearable.h create mode 100644 indra/newview/llscrollingpanelparam.cpp create mode 100644 indra/newview/llscrollingpanelparam.h create mode 100644 indra/newview/llscrollingpanelparambase.cpp create mode 100644 indra/newview/llscrollingpanelparambase.h diff --git a/indra/llui/llscrollingpanellist.h b/indra/llui/llscrollingpanellist.h index 96604270d..946073b97 100644 --- a/indra/llui/llscrollingpanellist.h +++ b/indra/llui/llscrollingpanellist.h @@ -29,6 +29,9 @@ * $/LicenseInfo$ */ +#ifndef LL_LLSCROLLINGPANELLIST_H +#define LL_LLSCROLLINGPANELLIST_H + #include #include "llui.h" @@ -56,6 +59,8 @@ public: LLScrollingPanelList(const std::string& name, const LLRect& rect) : LLUICtrl(name, rect, TRUE, NULL, NULL, FOLLOWS_LEFT | FOLLOWS_BOTTOM ) {} + typedef std::deque panel_list_t; + virtual void setValue(const LLSD& value) {}; virtual void draw(); @@ -64,11 +69,16 @@ public: void addPanel( LLScrollingPanel* panel ); void updatePanels(BOOL allow_modify); + const panel_list_t& getPanelList() { return mPanelList; } + virtual LLXMLNodePtr getXML(bool save_children = true) const; static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory); private: void updatePanelVisiblilty(); - std::deque mPanelList; + + panel_list_t mPanelList; }; + +#endif //LL_LLSCROLLINGPANELLIST_H diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 7b06d351d..4959adaa5 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -341,6 +341,7 @@ set(viewer_SOURCE_FILES llpanelavatar.cpp llpanelclassified.cpp llpanelcontents.cpp + llpaneleditwearable.cpp llpaneldebug.cpp llpaneldirbrowser.cpp llpaneldirclassified.cpp @@ -404,6 +405,8 @@ set(viewer_SOURCE_FILES llregionposition.cpp llremoteparcelrequest.cpp llsavedsettingsglue.cpp + llscrollingpanelparam.cpp + llscrollingpanelparambase.cpp llselectmgr.cpp llsky.cpp llspatialpartition.cpp @@ -833,6 +836,7 @@ set(viewer_HEADER_FILES llpanelavatar.h llpanelclassified.h llpanelcontents.h + llpaneleditwearable.h llpaneldebug.h llpaneldirbrowser.h llpaneldirclassified.h @@ -898,6 +902,8 @@ set(viewer_HEADER_FILES llremoteparcelrequest.h llresourcedata.h llsavedsettingsglue.h + llscrollingpanelparam.h + llscrollingpanelparambase.h llselectmgr.h llsky.h llspatialpartition.h diff --git a/indra/newview/llfloatercustomize.cpp b/indra/newview/llfloatercustomize.cpp index 61d1671e9..03a789c45 100644 --- a/indra/newview/llfloatercustomize.cpp +++ b/indra/newview/llfloatercustomize.cpp @@ -49,7 +49,7 @@ #include "lltoolmgr.h" #include "llviewermenu.h" #include "llscrollcontainer.h" -#include "llscrollingpanellist.h" +#include "llscrollingpanelparam.h" #include "llsliderctrl.h" #include "lltabcontainervertical.h" #include "llviewerwindow.h" @@ -78,6 +78,7 @@ #include "llviewercontrol.h" #include "lluictrlfactory.h" #include "llnotificationsutil.h" +#include "llpaneleditwearable.h" #include "statemachine/aifilepicker.h" #include "hippogridmanager.h" @@ -89,8 +90,6 @@ using namespace LLVOAvatarDefines; // Globals LLFloaterCustomize* gFloaterCustomize = NULL; -const F32 PARAM_STEP_TIME_THRESHOLD = 0.25f; - ///////////////////////////////////////////////////////////////////// // LLFloaterCustomizeObserver @@ -108,62 +107,6 @@ protected: // Local Constants -class LLWearableSaveAsDialog : public LLModalDialog -{ -private: - std::string mItemName; - void (*mCommitCallback)(LLWearableSaveAsDialog*,void*); - void* mCallbackUserData; - -public: - LLWearableSaveAsDialog( const std::string& desc, void(*commit_cb)(LLWearableSaveAsDialog*,void*), void* userdata ) - : LLModalDialog( LLStringUtil::null, 240, 100 ), - mCommitCallback( commit_cb ), - mCallbackUserData( userdata ) - { - LLUICtrlFactory::getInstance()->buildFloater(this, "floater_wearable_save_as.xml"); - - childSetAction("Save", LLWearableSaveAsDialog::onSave, this ); - childSetAction("Cancel", LLWearableSaveAsDialog::onCancel, this ); - - childSetTextArg("name ed", "[DESC]", desc); - } - - virtual void startModal() - { - LLModalDialog::startModal(); - LLLineEditor* edit = getChild("name ed"); - if (!edit) return; - edit->setFocus(TRUE); - edit->selectAll(); - } - - const std::string& getItemName() { return mItemName; } - - static void onSave( void* userdata ) - { - LLWearableSaveAsDialog* self = (LLWearableSaveAsDialog*) userdata; - self->mItemName = self->childGetValue("name ed").asString(); - LLStringUtil::trim(self->mItemName); - if( !self->mItemName.empty() ) - { - if( self->mCommitCallback ) - { - self->mCommitCallback( self, self->mCallbackUserData ); - } - self->close(); // destroys this object - } - } - - static void onCancel( void* userdata ) - { - LLWearableSaveAsDialog* self = (LLWearableSaveAsDialog*) userdata; - self->close(); // destroys this object - } -}; - -//////////////////////////////////////////////////////////////////////////// - BOOL edit_wearable_for_teens(LLWearableType::EType type) { switch(type) @@ -390,1331 +333,20 @@ public: } }; -///////////////////////////////////////////////////////////////////// -// LLPanelEditWearable - -enum ESubpart { - SUBPART_SHAPE_HEAD = 1, // avoid 0 - SUBPART_SHAPE_EYES, - SUBPART_SHAPE_EARS, - SUBPART_SHAPE_NOSE, - SUBPART_SHAPE_MOUTH, - SUBPART_SHAPE_CHIN, - SUBPART_SHAPE_TORSO, - SUBPART_SHAPE_LEGS, - SUBPART_SHAPE_WHOLE, - SUBPART_SHAPE_DETAIL, - SUBPART_SKIN_COLOR, - SUBPART_SKIN_FACEDETAIL, - SUBPART_SKIN_MAKEUP, - SUBPART_SKIN_BODYDETAIL, - SUBPART_HAIR_COLOR, - SUBPART_HAIR_STYLE, - SUBPART_HAIR_EYEBROWS, - SUBPART_HAIR_FACIAL, - SUBPART_EYES, - SUBPART_SHIRT, - SUBPART_PANTS, - SUBPART_SHOES, - SUBPART_SOCKS, - SUBPART_JACKET, - SUBPART_GLOVES, - SUBPART_UNDERSHIRT, - SUBPART_UNDERPANTS, - SUBPART_SKIRT, - SUBPART_ALPHA, - SUBPART_TATTOO, - SUBPART_PHYSICS_BREASTS_UPDOWN, - SUBPART_PHYSICS_BREASTS_INOUT, - SUBPART_PHYSICS_BREASTS_LEFTRIGHT, - SUBPART_PHYSICS_BELLY_UPDOWN, - SUBPART_PHYSICS_BUTT_UPDOWN, - SUBPART_PHYSICS_BUTT_LEFTRIGHT, - SUBPART_PHYSICS_ADVANCED - }; - -struct LLSubpart -{ - LLSubpart(const char* pJoint, const char* pGroup, const LLVector3d &target_offs, const LLVector3d &cam_offs, const ESex sex=SEX_BOTH, bool visual_hint=true ) - : mSex( sex ), mVisualHint(visual_hint), mTargetJoint(pJoint), mEditGroup(pGroup), mTargetOffset(target_offs), mCameraOffset(cam_offs) - {} - LLSubpart(const char* pJoint, const char* pGroup, const LLVector3d &target_offs, const LLVector3d &cam_offs, bool visual_hint) - : mSex( SEX_BOTH ), mVisualHint(visual_hint), mTargetJoint(pJoint), mEditGroup(pGroup), mTargetOffset(target_offs), mCameraOffset(cam_offs) - {} - std::string mButtonName; - std::string mTargetJoint; - std::string mEditGroup; - LLVector3d mTargetOffset; - LLVector3d mCameraOffset; - ESex mSex; - - bool mVisualHint; -}; - //////////////////////////////////////////////////////////////////////////// -class LLPanelEditWearable : public LLPanel -{ -public: - LLPanelEditWearable( LLWearableType::EType type ); - virtual ~LLPanelEditWearable(); - - virtual BOOL postBuild(); - virtual void draw(); - virtual BOOL isDirty() const; // LLUICtrl - - void addSubpart(const std::string& name, ESubpart id, LLSubpart* part ); - void addTextureDropTarget( ETextureIndex te, const std::string& name, const LLUUID& default_image_id, BOOL allow_no_texture ); - void addInvisibilityCheckbox(ETextureIndex te, const std::string& name); - void addColorSwatch( ETextureIndex te, const std::string& name ); - - const std::string& getLabel() { return LLWearableType::getTypeLabel( mType ); } - LLWearableType::EType getType() { return mType; } - - LLSubpart* getCurrentSubpart() { return mSubpartList[mCurrentSubpart]; } - ESubpart getDefaultSubpart(); - void setSubpart( ESubpart subpart ); - void switchToDefaultSubpart(); - - void setWearable(LLWearable* wearable, U32 perm_mask, BOOL is_complete); - - void setUIPermissions(U32 perm_mask, BOOL is_complete); - - void hideTextureControls(); - bool textureIsInvisible(ETextureIndex te); - void initPreviousTextureList(); - void initPreviousTextureListEntry(ETextureIndex te); - - virtual void setVisible( BOOL visible ); - - // Callbacks - static void onBtnSubpart( void* userdata ); - static void onBtnTakeOff( void* userdata ); - static void onBtnSave( void* userdata ); - - static void onBtnSaveAs( void* userdata ); - static void onSaveAsCommit( LLWearableSaveAsDialog* save_as_dialog, void* userdata ); - - static void onBtnRevert( void* userdata ); - static void onBtnTakeOffDialog( S32 option, void* userdata ); - static void onBtnCreateNew( void* userdata ); - static void onTextureCommit( LLUICtrl* ctrl, void* userdata ); - static void onInvisibilityCommit( LLUICtrl* ctrl, void* userdata ); - static void onColorCommit( LLUICtrl* ctrl, void* userdata ); - static void onCommitSexChange( LLUICtrl*, void* userdata ); - static bool onSelectAutoWearOption(const LLSD& notification, const LLSD& response); - - - -private: - LLWearableType::EType mType; - BOOL mCanTakeOff; - std::map mTextureList; - std::map mInvisibilityList; - std::map mColorList; - std::map mSubpartList; - std::map mPreviousTextureList; - ESubpart mCurrentSubpart; -}; - -//////////////////////////////////////////////////////////////////////////// - -LLPanelEditWearable::LLPanelEditWearable( LLWearableType::EType type ) - : LLPanel( LLWearableType::getTypeLabel( type ) ), - mType( type ) -{ -} - -BOOL LLPanelEditWearable::postBuild() -{ - LLAssetType::EType asset_type = LLWearableType::getAssetType( mType ); - /*std::string icon_name = (asset_type == LLAssetType::AT_CLOTHING ? - "inv_item_clothing.tga" : - "inv_item_skin.tga" );*/ - std::string icon_name = LLInventoryIcon::getIconName(asset_type,LLInventoryType::IT_WEARABLE,mType,FALSE); - - childSetValue("icon", icon_name); - - childSetAction("Create New", LLPanelEditWearable::onBtnCreateNew, this ); - - // If PG, can't take off underclothing or shirt - mCanTakeOff = - LLWearableType::getAssetType( mType ) == LLAssetType::AT_CLOTHING && - !( gAgent.isTeen() && (mType == LLWearableType::WT_UNDERSHIRT || mType == LLWearableType::WT_UNDERPANTS) ); - childSetVisible("Take Off", mCanTakeOff); - childSetAction("Take Off", LLPanelEditWearable::onBtnTakeOff, this ); - - childSetAction("Save", &LLPanelEditWearable::onBtnSave, (void*)this ); - - childSetAction("Save As", &LLPanelEditWearable::onBtnSaveAs, (void*)this ); - - childSetAction("Revert", &LLPanelEditWearable::onBtnRevert, (void*)this ); - - return TRUE; -} - -LLPanelEditWearable::~LLPanelEditWearable() -{ - std::for_each(mSubpartList.begin(), mSubpartList.end(), DeletePairedPointer()); - - // Clear colorswatch commit callbacks that point to this object. - for( std::map::iterator iter = mColorList.begin(); - iter != mColorList.end(); ++iter ) - { - childSetCommitCallback(iter->first, NULL, NULL); - } -} - -void LLPanelEditWearable::addSubpart( const std::string& name, ESubpart id, LLSubpart* part ) -{ - if (!name.empty()) - { - childSetAction(name, &LLPanelEditWearable::onBtnSubpart, (void*)id); - part->mButtonName = name; - } - mSubpartList[id] = part; - -} - -// static -void LLPanelEditWearable::onBtnSubpart(void* userdata) -{ - LLFloaterCustomize* floater_customize = gFloaterCustomize; - if (!floater_customize) return; - LLPanelEditWearable* self = floater_customize->getCurrentWearablePanel(); - if (!self) return; - ESubpart subpart = (ESubpart) (intptr_t)userdata; - self->setSubpart( subpart ); -} - -void LLPanelEditWearable::setSubpart( ESubpart subpart ) -{ - mCurrentSubpart = subpart; - - for (std::map::iterator iter = mSubpartList.begin(); - iter != mSubpartList.end(); ++iter) - { - LLButton* btn = getChild(iter->second->mButtonName); - if (btn) - { - btn->setToggleState( subpart == iter->first ); - } - } - - LLSubpart* part = get_if_there(mSubpartList, (ESubpart)subpart, (LLSubpart*)NULL); - if( part ) - { - // Update the thumbnails we display - LLFloaterCustomize::param_map sorted_params; - LLVOAvatar* avatar = gAgentAvatarp; - ESex avatar_sex = avatar->getSex(); - LLViewerInventoryItem* item; - item = (LLViewerInventoryItem*)gAgentWearables.getWearableInventoryItem(mType,0); // TODO: MULTI-WEARABLE - U32 perm_mask = 0x0; - BOOL is_complete = FALSE; - bool can_export = false; - bool can_import = false; - if(item) - { - perm_mask = item->getPermissions().getMaskOwner(); - is_complete = item->isComplete(); - - if (subpart <= 18) // body parts only - { - can_import = true; - - if (is_complete && - gAgent.getID() == item->getPermissions().getOwner() && - gAgent.getID() == item->getPermissions().getCreator() && - (PERM_ITEM_UNRESTRICTED & - perm_mask) == PERM_ITEM_UNRESTRICTED) - { - can_export = true; - } - } - } - setUIPermissions(perm_mask, is_complete); - BOOL editable = ((perm_mask & PERM_MODIFY) && is_complete) ? TRUE : FALSE; - - for(LLViewerVisualParam* param = (LLViewerVisualParam *)avatar->getFirstVisualParam(); - param; - param = (LLViewerVisualParam *)avatar->getNextVisualParam()) - { - if (param->getID() == -1 - || !param->isTweakable() - || param->getEditGroup() != part->mEditGroup - || !(param->getSex() & avatar_sex)) - { - continue; - } - - // negative getDisplayOrder() to make lowest order the highest priority - LLFloaterCustomize::param_map::value_type vt(-param->getDisplayOrder(), LLFloaterCustomize::editable_param(editable, param)); - llassert( sorted_params.find(-param->getDisplayOrder()) == sorted_params.end() ); // Check for duplicates - sorted_params.insert(vt); - } - gFloaterCustomize->generateVisualParamHints(NULL, sorted_params, part->mVisualHint); - gFloaterCustomize->updateScrollingPanelUI(); - gFloaterCustomize->childSetEnabled("Export", can_export); - gFloaterCustomize->childSetEnabled("Import", can_import); - - // Update the camera - gMorphView->setCameraTargetJoint( gAgentAvatarp->getJoint( part->mTargetJoint ) ); - gMorphView->setCameraTargetOffset( part->mTargetOffset ); - gMorphView->setCameraOffset( part->mCameraOffset ); - gMorphView->setCameraDistToDefault(); - if (gSavedSettings.getBOOL("AppearanceCameraMovement")) - { - gMorphView->updateCamera(); - } - } -} - -// static -void LLPanelEditWearable::onBtnTakeOff( void* userdata ) -{ - LLPanelEditWearable* self = (LLPanelEditWearable*) userdata; - - LLWearable* wearable = gAgentWearables.getWearable( self->mType, 0 ); // TODO: MULTI-WEARABLE - if( !wearable ) - { - return; - } - - gAgentWearables.removeWearable( self->mType, false, 0 ); // TODO: MULTI-WEARABLE -} - -// static -void LLPanelEditWearable::onBtnSave( void* userdata ) -{ - LLPanelEditWearable* self = (LLPanelEditWearable*) userdata; - gAgentWearables.saveWearable( self->mType, 0 ); // TODO: MULTI-WEARABLE -} - -// static -void LLPanelEditWearable::onBtnSaveAs( void* userdata ) -{ - LLPanelEditWearable* self = (LLPanelEditWearable*) userdata; - LLWearable* wearable = gAgentWearables.getWearable( self->getType(), 0 ); // TODO: MULTI-WEARABLE - if( wearable ) - { - LLWearableSaveAsDialog* save_as_dialog = new LLWearableSaveAsDialog( wearable->getName(), onSaveAsCommit, self ); - save_as_dialog->startModal(); - // LLWearableSaveAsDialog deletes itself. - } -} - -// static -void LLPanelEditWearable::onSaveAsCommit( LLWearableSaveAsDialog* save_as_dialog, void* userdata ) -{ - LLPanelEditWearable* self = (LLPanelEditWearable*) userdata; - LLVOAvatar* avatar = gAgentAvatarp; - if( avatar ) - { - gAgentWearables.saveWearableAs( self->getType(), 0, save_as_dialog->getItemName(), FALSE ); // TODO: MULTI-WEARABLE - } -} - - -// static -void LLPanelEditWearable::onBtnRevert( void* userdata ) -{ - LLPanelEditWearable* self = (LLPanelEditWearable*) userdata; - gAgentWearables.revertWearable( self->mType, 0 ); // TODO: MULTI-WEARABLE -} - -// static -void LLPanelEditWearable::onBtnCreateNew( void* userdata ) -{ - LLPanelEditWearable* self = (LLPanelEditWearable*) userdata; - LLSD payload; - payload["wearable_type"] = (S32)self->getType(); - LLNotificationsUtil::add("AutoWearNewClothing", LLSD(), payload, &onSelectAutoWearOption); -} - -bool LLPanelEditWearable::onSelectAutoWearOption(const LLSD& notification, const LLSD& response) -{ - S32 option = LLNotification::getSelectedOption(notification, response); - LLVOAvatar* avatar = gAgentAvatarp; - if(avatar) - { - // Create a new wearable in the default folder for the wearable's asset type. - LLWearable* wearable = LLWearableList::instance().createNewWearable( (LLWearableType::EType)notification["payload"]["wearable_type"].asInteger() ); - LLAssetType::EType asset_type = wearable->getAssetType(); - - LLUUID folder_id; - // regular UI, items get created in normal folder - folder_id = gInventory.findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(asset_type)); - - // Only auto wear the new item if the AutoWearNewClothing checkbox is selected. - LLPointer cb = option == 0 ? - new WearOnAvatarCallback : NULL; - create_inventory_item(gAgent.getID(), gAgent.getSessionID(), - folder_id, wearable->getTransactionID(), wearable->getName(), wearable->getDescription(), - asset_type, LLInventoryType::IT_WEARABLE, wearable->getType(), - wearable->getPermissions().getMaskNextOwner(), cb); - } - return false; -} - -bool LLPanelEditWearable::textureIsInvisible(ETextureIndex te) -{ - const LLWearable* wearable = gAgentWearables.getWearable(mType, 0); // TODO: MULTI-WEARABLE - if(wearable) - { - const LLLocalTextureObject* lto = wearable->getLocalTextureObject(te); - return (lto && lto->getID() == IMG_INVISIBLE); - } - return false; -} - -void LLPanelEditWearable::addInvisibilityCheckbox(ETextureIndex te, const std::string& name) -{ - childSetCommitCallback(name, LLPanelEditWearable::onInvisibilityCommit, this); - - mInvisibilityList[name] = te; -} - -// static -void LLPanelEditWearable::onInvisibilityCommit(LLUICtrl* ctrl, void* userdata) -{ - LLPanelEditWearable* self = (LLPanelEditWearable*) userdata; - LLCheckBoxCtrl* checkbox_ctrl = (LLCheckBoxCtrl*) ctrl; - if (!gAgentAvatarp) - { - return; - } - - ETextureIndex te = (ETextureIndex)(self->mInvisibilityList[ctrl->getName()]); - - bool new_invis_state = checkbox_ctrl->get(); - if (new_invis_state) - { - - LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTexture(IMG_INVISIBLE); - - LLWearable* wearable = gAgentWearables.getWearable(self->mType,0); // TODO: MULTI-WEARABLE - const LLLocalTextureObject* lto = wearable ? wearable->getLocalTextureObject(te) : NULL; - - if(lto) - { - self->mPreviousTextureList[(S32)te] = lto->getID(); - } - if(wearable) - { - LLLocalTextureObject new_lto(image, IMG_INVISIBLE); - wearable->setLocalTextureObject(te, new_lto); - wearable->writeToAvatar(); - gAgentAvatarp->wearableUpdated(self->mType, FALSE); - } - - } - else - { - // Try to restore previous texture, if any. - LLUUID prev_id = self->mPreviousTextureList[(S32)te]; - if (prev_id.isNull() || (prev_id == IMG_INVISIBLE)) - { - prev_id = LLUUID(gSavedSettings.getString("UIImgDefaultAlphaUUID")); - } - if (prev_id.notNull()) - { - LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTexture(prev_id); - LLWearable* wearable = gAgentWearables.getWearable(self->mType,0); // TODO: MULTI-WEARABLE - if(wearable) - { - LLLocalTextureObject new_lto(image, prev_id); - wearable->setLocalTextureObject(te, new_lto); - wearable->writeToAvatar(); - gAgentAvatarp->wearableUpdated(self->mType, FALSE); - } - } - - } -} - -void LLPanelEditWearable::addColorSwatch( ETextureIndex te, const std::string& name ) -{ - childSetCommitCallback(name, LLPanelEditWearable::onColorCommit, this); - mColorList[name] = te; -} - -// static -void LLPanelEditWearable::onColorCommit( LLUICtrl* ctrl, void* userdata ) -{ - LLPanelEditWearable* self = (LLPanelEditWearable*) userdata; - LLColorSwatchCtrl* color_ctrl = (LLColorSwatchCtrl*) ctrl; - - if( self && color_ctrl && gAgentAvatarp ) - { - std::map::const_iterator cl_itr = self->mColorList.find(ctrl->getName()); - if(cl_itr != self->mColorList.end()) - { - ETextureIndex te = (ETextureIndex)cl_itr->second; - - LLWearable* wearable = gAgentWearables.getWearable(self->mType, 0); // TODO: MULTI-WEARABLE - if(!wearable) - return; - - LLColor4 old_color = wearable->getClothesColor( te ); - const LLColor4& new_color = color_ctrl->get(); - if( old_color != new_color ) - { - // Set the new version - wearable->setClothesColor(te, new_color, TRUE); - wearable->writeToAvatar(); - gAgentAvatarp->wearableUpdated(self->mType, FALSE); - LLVisualParamHint::requestHintUpdates(); - } - } - } -} - -void LLPanelEditWearable::initPreviousTextureList() -{ - initPreviousTextureListEntry(TEX_LOWER_ALPHA); - initPreviousTextureListEntry(TEX_UPPER_ALPHA); - initPreviousTextureListEntry(TEX_HEAD_ALPHA); - initPreviousTextureListEntry(TEX_EYES_ALPHA); - initPreviousTextureListEntry(TEX_LOWER_ALPHA); -} - -void LLPanelEditWearable::initPreviousTextureListEntry(ETextureIndex te) -{ - LLVOAvatar* avatar = gAgentAvatarp; - if (!avatar) - { - return; - } - - LLWearable* wearable = gAgentWearables.getWearable(mType, 0); // TODO: MULTI-WEARABLE - if(!wearable) - return; - - const LLLocalTextureObject* lto = wearable->getLocalTextureObject(te); - if (lto) - { - mPreviousTextureList[te] = lto->getID(); - } -} - -void LLPanelEditWearable::addTextureDropTarget( ETextureIndex te, const std::string& name, - const LLUUID& default_image_id, BOOL allow_no_texture ) -{ - childSetCommitCallback(name, LLPanelEditWearable::onTextureCommit, this); - LLTextureCtrl* texture_ctrl = getChild(name); - if (texture_ctrl) - { - texture_ctrl->setDefaultImageAssetID(default_image_id); - texture_ctrl->setAllowNoTexture( allow_no_texture ); - // Don't allow (no copy) or (no transfer) textures to be selected. - texture_ctrl->setImmediateFilterPermMask(PERM_NONE);//PERM_COPY | PERM_TRANSFER); - texture_ctrl->setNonImmediateFilterPermMask(PERM_NONE);//PERM_COPY | PERM_TRANSFER); - } - mTextureList[name] = te; - LLVOAvatar* avatar = gAgentAvatarp; - if (avatar) - { - LLWearable* wearable = gAgentWearables.getWearable(mType, 0); // TODO: MULTI-WEARABLE - if (wearable && mType == LLWearableType::WT_ALPHA) - { - const LLLocalTextureObject* lto = wearable->getLocalTextureObject(te); - if (lto) - { - mPreviousTextureList[te] = lto->getID(); - } - } - } -} - -// static -void LLPanelEditWearable::onTextureCommit( LLUICtrl* ctrl, void* userdata ) -{ - LLPanelEditWearable* self = (LLPanelEditWearable*) userdata; - LLTextureCtrl* texture_ctrl = (LLTextureCtrl*) ctrl; - - if( gAgentAvatarp ) - { - ETextureIndex te = (ETextureIndex)(self->mTextureList[ctrl->getName()]); - - // Set the new version - LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTexture( texture_ctrl->getImageAssetID() ); - if (image->getID().isNull()) - { - image = LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT_AVATAR); - } - self->mTextureList[ctrl->getName()] = te; - - LLWearable* wearable = gAgentWearables.getWearable(self->mType, 0); // TODO: MULTI-WEARABLE - if (wearable) - { - LLLocalTextureObject lto(image, texture_ctrl->getImageAssetID()); - wearable->setLocalTextureObject(te, lto); - wearable->writeToAvatar(); - gAgentAvatarp->wearableUpdated(self->mType, FALSE); - } - if (self->mType == LLWearableType::WT_ALPHA && image->getID() != IMG_INVISIBLE) - { - self->mPreviousTextureList[te] = image->getID(); - } - } -} - - -ESubpart LLPanelEditWearable::getDefaultSubpart() -{ - switch( mType ) - { - case LLWearableType::WT_SHAPE: return SUBPART_SHAPE_WHOLE; - case LLWearableType::WT_SKIN: return SUBPART_SKIN_COLOR; - case LLWearableType::WT_HAIR: return SUBPART_HAIR_COLOR; - case LLWearableType::WT_EYES: return SUBPART_EYES; - case LLWearableType::WT_SHIRT: return SUBPART_SHIRT; - case LLWearableType::WT_PANTS: return SUBPART_PANTS; - case LLWearableType::WT_SHOES: return SUBPART_SHOES; - case LLWearableType::WT_SOCKS: return SUBPART_SOCKS; - case LLWearableType::WT_JACKET: return SUBPART_JACKET; - case LLWearableType::WT_GLOVES: return SUBPART_GLOVES; - case LLWearableType::WT_UNDERSHIRT: return SUBPART_UNDERSHIRT; - case LLWearableType::WT_UNDERPANTS: return SUBPART_UNDERPANTS; - case LLWearableType::WT_SKIRT: return SUBPART_SKIRT; - case LLWearableType::WT_ALPHA: return SUBPART_ALPHA; - case LLWearableType::WT_TATTOO: return SUBPART_TATTOO; - case LLWearableType::WT_PHYSICS: return SUBPART_PHYSICS_BELLY_UPDOWN; - - default: llassert(0); return SUBPART_SHAPE_WHOLE; - } -} - - -void LLPanelEditWearable::draw() -{ - if( gFloaterCustomize->isMinimized() ) - { - return; - } - - LLVOAvatar* avatar = gAgentAvatarp; - if( !avatar ) - { - return; - } - - LLWearable* wearable = gAgentWearables.getWearable( mType, 0 ); // TODO: MULTI-WEARABLE - BOOL has_wearable = (wearable != NULL ); - BOOL is_dirty = isDirty(); - BOOL is_modifiable = FALSE; - BOOL is_copyable = FALSE; - BOOL is_complete = FALSE; - LLViewerInventoryItem* item; - item = (LLViewerInventoryItem*)gAgentWearables.getWearableInventoryItem(mType, 0); // TODO: MULTI-WEARABLE - if(item) - { - const LLPermissions& perm = item->getPermissions(); - is_modifiable = perm.allowModifyBy(gAgent.getID(), gAgent.getGroupID()); - is_copyable = perm.allowCopyBy(gAgent.getID(), gAgent.getGroupID()); - is_complete = item->isComplete(); - } - - childSetEnabled("Save", is_modifiable && is_complete && has_wearable && is_dirty); - childSetEnabled("Save As", is_copyable && is_complete && has_wearable); - childSetEnabled("Revert", has_wearable && is_dirty ); - childSetEnabled("Take Off", has_wearable ); - childSetVisible("Take Off", mCanTakeOff && has_wearable ); - childSetVisible("Create New", !has_wearable ); - - childSetVisible("not worn instructions", !has_wearable ); - childSetVisible("no modify instructions", has_wearable && !is_modifiable); - - for (std::map::iterator iter = mSubpartList.begin(); - iter != mSubpartList.end(); ++iter) - { - childSetVisible(iter->second->mButtonName,has_wearable); - if( has_wearable && is_complete && is_modifiable ) - { - childSetEnabled(iter->second->mButtonName, iter->second->mSex & avatar->getSex() ); - } - else - { - childSetEnabled(iter->second->mButtonName, FALSE ); - } - } - - childSetVisible("square", !is_modifiable); - - childSetVisible("title", FALSE); - childSetVisible("title_no_modify", FALSE); - childSetVisible("title_not_worn", FALSE); - childSetVisible("title_loading", FALSE); - - childSetVisible("path", FALSE); - - LLTextBox *av_height = getChild("avheight",FALSE,FALSE); - if(av_height) //Only display this if the element exists - { - // Display the shape's nominal height. - // - // The value for avsize is the best available estimate from - // measuring against prims. - float avsize = avatar->mBodySize.mV[VZ] + .195; - int inches = (int)(avsize / .0254f); - int feet = inches / 12; - inches %= 12; - - std::ostringstream avheight(std::ostringstream::trunc); - avheight << std::fixed << std::setprecision(2) << avsize << " m (" - << feet << "' " << inches << "\")"; - av_height->setVisible(TRUE); - av_height->setTextArg("[AVHEIGHT]",avheight.str()); - } - - if(has_wearable && !is_modifiable) - { - // *TODO:Translate - childSetVisible("title_no_modify", TRUE); - childSetTextArg("title_no_modify", "[DESC]", std::string(LLWearableType::getTypeLabel( mType ))); - - hideTextureControls(); - } - else if(has_wearable && !is_complete) - { - // *TODO:Translate - childSetVisible("title_loading", TRUE); - childSetTextArg("title_loading", "[DESC]", std::string(LLWearableType::getTypeLabel( mType ))); - - std::string path; - const LLUUID& item_id = gAgentWearables.getWearableItemID( wearable->getType(), 0 ); // TODO: MULTI-WEARABLE - append_path(item_id, path); - childSetVisible("path", TRUE); - childSetTextArg("path", "[PATH]", path); - - hideTextureControls(); - } - else if(has_wearable && is_modifiable) - { - childSetVisible("title", TRUE); - childSetTextArg("title", "[DESC]", wearable->getName() ); - - std::string path; - const LLUUID& item_id = gAgentWearables.getWearableItemID( wearable->getType(), 0 ); // TODO: MULTI-WEARABLE - append_path(item_id, path); - childSetVisible("path", TRUE); - childSetTextArg("path", "[PATH]", path); - - for( std::map::iterator iter = mTextureList.begin(); - iter != mTextureList.end(); ++iter ) - { - std::string name = iter->first; - LLTextureCtrl* texture_ctrl = getChild(name); - S32 te_index = iter->second; - childSetVisible(name, is_copyable && is_modifiable && is_complete ); - if (texture_ctrl) - { - - const LLLocalTextureObject* lto = wearable->getLocalTextureObject(te_index); - - LLUUID new_id; - - if( lto && (lto->getID() != IMG_DEFAULT_AVATAR) ) - { - new_id = lto->getID(); - } - else - { - new_id = LLUUID::null; - } - - LLUUID old_id = texture_ctrl->getImageAssetID(); - - if (old_id != new_id) - { - // texture has changed, close the floater to avoid DEV-22461 - texture_ctrl->closeFloater(); - } - - texture_ctrl->setImageAssetID(new_id); - } - } - - LLWearable* wearable = gAgentWearables.getWearable(mType, 0); // TODO: MULTI-WEARABLE - - if(wearable) - { - for( std::map::iterator iter = mColorList.begin(); - iter != mColorList.end(); ++iter ) - { - std::string name = iter->first; - S32 te_index = iter->second; - childSetVisible(name, is_modifiable && is_complete ); - childSetEnabled(name, is_modifiable && is_complete ); - LLColorSwatchCtrl* ctrl = getChild(name); - if (ctrl) - { - ctrl->set( wearable->getClothesColor(te_index ) ); - } - } - } - - for (std::map::iterator iter = mInvisibilityList.begin(); - iter != mInvisibilityList.end(); ++iter) - { - std::string name = iter->first; - ETextureIndex te = (ETextureIndex)iter->second; - childSetVisible(name, is_copyable && is_modifiable && is_complete); - childSetEnabled(name, is_copyable && is_modifiable && is_complete); - LLCheckBoxCtrl* ctrl = getChild(name); - if (ctrl) - { - ctrl->set(textureIsInvisible(te)); - } - } - } - else - { - // *TODO:Translate - childSetVisible("title_not_worn", TRUE); - childSetTextArg("title_not_worn", "[DESC]", std::string(LLWearableType::getTypeLabel( mType ))); - - hideTextureControls(); - } - - childSetVisible("icon", has_wearable && is_modifiable); - - LLPanel::draw(); -} - -void LLPanelEditWearable::hideTextureControls() -{ - for (std::map::iterator iter = mTextureList.begin(); - iter != mTextureList.end(); ++iter) - { - childSetVisible(iter->first, FALSE); - } - for (std::map::iterator iter = mColorList.begin(); - iter != mColorList.end(); ++iter) - { - childSetVisible(iter->first, FALSE); - } - for (std::map::iterator iter = mInvisibilityList.begin(); - iter != mInvisibilityList.end(); ++iter) - { - childSetVisible(iter->first, FALSE); - } -} - -void LLPanelEditWearable::setWearable(LLWearable* wearable, U32 perm_mask, BOOL is_complete) -{ - if( wearable ) - { - setUIPermissions(perm_mask, is_complete); - if (mType == LLWearableType::WT_ALPHA) - { - initPreviousTextureList(); - } - } -} - -void LLPanelEditWearable::switchToDefaultSubpart() -{ - setSubpart( getDefaultSubpart() ); -} - -void LLPanelEditWearable::setVisible(BOOL visible) -{ - LLPanel::setVisible( visible ); - if( !visible ) - { - for( std::map::iterator iter = mColorList.begin(); - iter != mColorList.end(); ++iter ) - { - // this forces any open color pickers to cancel their selection - childSetEnabled(iter->first, FALSE ); - } - } -} - -BOOL LLPanelEditWearable::isDirty() const -{ - LLWearable* wearable = gAgentWearables.getWearable( mType, 0 ); // TODO: MULTI-WEARABLE - if( !wearable ) - { - return FALSE; - } - - if( wearable->isDirty() ) - { - return TRUE; - } - - return FALSE; -} - -// static -void LLPanelEditWearable::onCommitSexChange( LLUICtrl*, void* userdata ) -{ - LLPanelEditWearable* self = (LLPanelEditWearable*) userdata; - - LLVOAvatar* avatar = gAgentAvatarp; - if (!avatar) - { - return; - } - - if( !gAgentWearables.isWearableModifiable(self->mType, 0)) // TODO: MULTI-WEARABLE - { - return; - } - - LLWearable* wearable = gAgentWearables.getWearable(self->mType,0); // TODO: MULTI-WEARABLE - if(!wearable) - { - return; - } - - ESex new_sex = gSavedSettings.getU32("AvatarSex") ? SEX_MALE : SEX_FEMALE; - - LLVisualParam* param = avatar->getVisualParam( "male" ); - if( !param ) - { - return; - } - - wearable->setVisualParamWeight(param->getID(), (new_sex == SEX_MALE), TRUE); - wearable->writeToAvatar(); - avatar->updateVisualParams(); - - /*param->setWeight( (new_sex == SEX_MALE), TRUE ); - - avatar->updateSexDependentLayerSets( TRUE ); - - avatar->updateVisualParams();*/ - - gFloaterCustomize->clearScrollingPanelList(); - - // Assumes that we're in the "Shape" Panel. - self->setSubpart( SUBPART_SHAPE_WHOLE ); -} - -void LLPanelEditWearable::setUIPermissions(U32 perm_mask, BOOL is_complete) -{ - BOOL is_copyable = (perm_mask & PERM_COPY) ? TRUE : FALSE; - BOOL is_modifiable = (perm_mask & PERM_MODIFY) ? TRUE : FALSE; - - childSetEnabled("Save", is_modifiable && is_complete); - childSetEnabled("Save As", is_copyable && is_complete); - childSetEnabled("sex radio", is_modifiable && is_complete); - for( std::map::iterator iter = mTextureList.begin(); - iter != mTextureList.end(); ++iter ) - { - childSetVisible(iter->first, is_copyable && is_modifiable && is_complete ); - } - for( std::map::iterator iter = mColorList.begin(); - iter != mColorList.end(); ++iter ) - { - childSetVisible(iter->first, is_modifiable && is_complete ); - } - for (std::map::iterator iter = mInvisibilityList.begin(); - iter != mInvisibilityList.end(); ++iter) - { - childSetVisible(iter->first, is_copyable && is_modifiable && is_complete); - } -} - -///////////////////////////////////////////////////////////////////// -// LLScrollingPanelParam - -class LLScrollingPanelParam : public LLScrollingPanel -{ -public: - LLScrollingPanelParam( const std::string& name, LLViewerJointMesh* mesh, LLViewerVisualParam* param, BOOL allow_modify, bool bVisualHint ); - virtual ~LLScrollingPanelParam(); - - virtual void draw(); - virtual void setVisible( BOOL visible ); - virtual void updatePanel(BOOL allow_modify); - - static void onSliderMouseDown(LLUICtrl* ctrl, void* userdata); - static void onSliderMoved(LLUICtrl* ctrl, void* userdata); - static void onSliderMouseUp(LLUICtrl* ctrl, void* userdata); - - void onHintMouseUp( bool max ); - void onHintMouseDown( bool max ); - void onHintHeldDown( bool max ); - - F32 weightToPercent( F32 weight ); - F32 percentToWeight( F32 percent ); - -public: - LLViewerVisualParam* mParam; - LLPointer mHintMin; - LLPointer mHintMax; - LLButton* mLess; - LLButton* mMore; - - static S32 sUpdateDelayFrames; - -protected: - LLTimer mMouseDownTimer; // timer for how long mouse has been held down on a hint. - F32 mLastHeldTime; - - BOOL mAllowModify; -}; - -//static -S32 LLScrollingPanelParam::sUpdateDelayFrames = 0; - -const S32 BTN_BORDER = 2; -const S32 PARAM_HINT_WIDTH = 128; -const S32 PARAM_HINT_HEIGHT = 128; -const S32 PARAM_HINT_LABEL_HEIGHT = 16; -const S32 PARAM_PANEL_WIDTH = 2 * (3* BTN_BORDER + PARAM_HINT_WIDTH + LLPANEL_BORDER_WIDTH); -const S32 PARAM_PANEL_HEIGHT = 2 * BTN_BORDER + PARAM_HINT_HEIGHT + PARAM_HINT_LABEL_HEIGHT + 4 * LLPANEL_BORDER_WIDTH; - -LLScrollingPanelParam::LLScrollingPanelParam( const std::string& name, - LLViewerJointMesh* mesh, LLViewerVisualParam* param, BOOL allow_modify, bool bVisualHint ) - : LLScrollingPanel( name, LLRect( 0, PARAM_PANEL_HEIGHT, PARAM_PANEL_WIDTH, 0 ) ), - mParam(param), - mAllowModify(allow_modify), - mLess(NULL), - mMore(NULL) -{ - LLUICtrlFactory::getInstance()->buildPanel(this, "panel_scrolling_param.xml"); - - //Set up the slider - LLSliderCtrl *slider = getChild("param slider"); - slider->setValue(weightToPercent(param->getWeight())); - slider->setLabelArg("[DESC]", param->getDisplayName()); - slider->setEnabled(mAllowModify); - slider->setCommitCallback(LLScrollingPanelParam::onSliderMoved); - slider->setCallbackUserData(this); - - if(bVisualHint) - { - S32 pos_x = 2 * LLPANEL_BORDER_WIDTH; - S32 pos_y = 3 * LLPANEL_BORDER_WIDTH + SLIDERCTRL_HEIGHT; - F32 min_weight = param->getMinWeight(); - F32 max_weight = param->getMaxWeight(); - - mHintMin = new LLVisualParamHint( pos_x, pos_y, PARAM_HINT_WIDTH, PARAM_HINT_HEIGHT, mesh, param, min_weight); - pos_x += PARAM_HINT_WIDTH + 3 * BTN_BORDER; - mHintMax = new LLVisualParamHint( pos_x, pos_y, PARAM_HINT_WIDTH, PARAM_HINT_HEIGHT, mesh, param, max_weight ); - - mHintMin->setAllowsUpdates( FALSE ); - mHintMax->setAllowsUpdates( FALSE ); - - // *TODO::translate - std::string min_name = param->getMinDisplayName(); - std::string max_name = param->getMaxDisplayName(); - childSetValue("min param text", min_name); - childSetValue("max param text", max_name); - mLess = getChild("less"); - mLess->setMouseDownCallback( boost::bind(&LLScrollingPanelParam::onHintMouseDown, this, false) ); - mLess->setMouseUpCallback( boost::bind(&LLScrollingPanelParam::onHintMouseUp, this, false) ); - mLess->setHeldDownCallback( boost::bind(&LLScrollingPanelParam::onHintHeldDown, this, false) ); - mLess->setHeldDownDelay( PARAM_STEP_TIME_THRESHOLD ); - - mMore = getChild("more"); - mMore->setMouseDownCallback( boost::bind(&LLScrollingPanelParam::onHintMouseDown, this, true) ); - mMore->setMouseUpCallback( boost::bind(&LLScrollingPanelParam::onHintMouseUp, this, true) ); - mMore->setHeldDownCallback( boost::bind(&LLScrollingPanelParam::onHintHeldDown, this, true) ); - mMore->setHeldDownDelay( PARAM_STEP_TIME_THRESHOLD ); - } - else - { - //Kill everything that isn't the slider... - child_list_t to_remove; - child_list_t::const_iterator it; - for (it = getChildList()->begin(); it != getChildList()->end(); it++) - { - if ((*it) != slider && (*it)->getName() != "panel border") - { - to_remove.push_back(*it); - } - } - for (it = to_remove.begin(); it != to_remove.end(); it++) - { - removeChild(*it); - delete (*it); - } - slider->translate(0,PARAM_HINT_HEIGHT); - reshape(getRect().getWidth(),getRect().getHeight()-PARAM_HINT_HEIGHT); - } - - setVisible(FALSE); - setBorderVisible( FALSE ); -} - -LLScrollingPanelParam::~LLScrollingPanelParam() -{ - mHintMin = NULL; - mHintMax = NULL; -} - -void LLScrollingPanelParam::updatePanel(BOOL allow_modify) -{ - childSetValue("param slider", weightToPercent( mParam->getWeight() ) ); - if(mHintMin) - mHintMin->requestUpdate( sUpdateDelayFrames++ ); - if(mHintMax) - mHintMax->requestUpdate( sUpdateDelayFrames++ ); - - mAllowModify = allow_modify; - childSetEnabled("param slider", mAllowModify); - - if(mLess) - mLess->setEnabled(mAllowModify); - if(mMore) - mMore->setEnabled(mAllowModify); -} - -void LLScrollingPanelParam::setVisible( BOOL visible ) -{ - if( getVisible() != visible ) - { - LLPanel::setVisible( visible ); - if(mHintMin) - mHintMin->setAllowsUpdates( visible ); - if(mHintMax) - mHintMax->setAllowsUpdates( visible ); - - if( visible ) - { - if(mHintMin) - mHintMin->setUpdateDelayFrames( sUpdateDelayFrames++ ); - if(mHintMax) - mHintMax->setUpdateDelayFrames( sUpdateDelayFrames++ ); - } - } -} - -void LLScrollingPanelParam::draw() -{ - if( gFloaterCustomize->isMinimized() ) - { - return; - } - - if(mLess) - mLess->setVisible(mHintMin ? mHintMin->getVisible() : false); - if(mMore) - mMore->setVisible(mHintMax ? mHintMax->getVisible() : false); - - // Draw all the children except for the labels - childSetVisible( "min param text", FALSE ); - childSetVisible( "max param text", FALSE ); - LLPanel::draw(); - - // Draw the hints over the "less" and "more" buttons. - if(mHintMin) - { - gGL.pushMatrix(); - { - const LLRect& r = mHintMin->getRect(); - F32 left = (F32)(r.mLeft + BTN_BORDER); - F32 bot = (F32)(r.mBottom + BTN_BORDER); - gGL.translatef(left, bot, 0.f); - mHintMin->draw(); - } - gGL.popMatrix(); - } - - if(mHintMax) - { - gGL.pushMatrix(); - { - const LLRect& r = mHintMax->getRect(); - F32 left = (F32)(r.mLeft + BTN_BORDER); - F32 bot = (F32)(r.mBottom + BTN_BORDER); - gGL.translatef(left, bot, 0.f); - mHintMax->draw(); - } - gGL.popMatrix(); - } - - - // Draw labels on top of the buttons - childSetVisible( "min param text", TRUE ); - drawChild(getChild("min param text"), BTN_BORDER, BTN_BORDER); - - childSetVisible( "max param text", TRUE ); - drawChild(getChild("max param text"), BTN_BORDER, BTN_BORDER); -} - void updateAvatarHeightDisplay() { - if (gFloaterCustomize) - { - LLVOAvatar* avatar = gAgentAvatarp; - F32 avatar_size = (avatar->mBodySize.mV[VZ]) + (F32)0.17; //mBodySize is actually quite a bit off. - gFloaterCustomize->getChild("HeightTextM")->setValue(llformat("%.2f", avatar_size) + "m"); - F32 feet = avatar_size / 0.3048; - F32 inches = (feet - (F32)((U32)feet)) * 12.0; - gFloaterCustomize->getChild("HeightTextI")->setValue(llformat("%d'%d\"", (U32)feet, (U32)inches)); - } + if (gFloaterCustomize && isAgentAvatarValid()) + { + F32 avatar_size = (gAgentAvatarp->mBodySize.mV[VZ]) + (F32)0.17; //mBodySize is actually quite a bit off. + gFloaterCustomize->getChild("HeightTextM")->setValue(llformat("%.2f", avatar_size) + "m"); + F32 feet = avatar_size / 0.3048; + F32 inches = (feet - (F32)((U32)feet)) * 12.0; + gFloaterCustomize->getChild("HeightTextI")->setValue(llformat("%d'%d\"", (U32)feet, (U32)inches)); + } } -// static -void LLScrollingPanelParam::onSliderMoved(LLUICtrl* ctrl, void* userdata) -{ - LLSliderCtrl* slider = (LLSliderCtrl*) ctrl; - LLScrollingPanelParam* self = (LLScrollingPanelParam*) userdata; - LLViewerVisualParam* param = self->mParam; - - if(!param) - return; - - LLWearable* wearable = gAgentWearables.getWearable( (LLWearableType::EType)param->getWearableType(), 0 ); // TODO: MULTI-WEARABLE - - if(!wearable) - return; - - F32 current_weight = wearable->getVisualParamWeight(param->getID()); - F32 new_weight = self->percentToWeight( (F32)slider->getValue().asReal() ); - if (current_weight != new_weight ) - { - updateAvatarHeightDisplay(); - wearable->setVisualParamWeight( param->getID(), new_weight, FALSE); - wearable->writeToAvatar(); - gAgentAvatarp->updateVisualParams(); - } -} - -// static -void LLScrollingPanelParam::onSliderMouseDown(LLUICtrl* ctrl, void* userdata) -{ -} - -// static -void LLScrollingPanelParam::onSliderMouseUp(LLUICtrl* ctrl, void* userdata) -{ - LLScrollingPanelParam* self = (LLScrollingPanelParam*) userdata; - - LLVisualParamHint::requestHintUpdates( self->mHintMin, self->mHintMax ); -} - -void LLScrollingPanelParam::onHintMouseDown( bool max ) -{ - LLVisualParamHint* hint = max ? mHintMax : mHintMin; - // morph towards this result - F32 current_weight = gAgentAvatarp->getVisualParamWeight( hint->getVisualParam() ); - - // if we have maxed out on this morph, we shouldn't be able to click it - if( hint->getVisualParamWeight() != current_weight ) - { - mMouseDownTimer.reset(); - mLastHeldTime = 0.f; - } -} - -void LLScrollingPanelParam::onHintHeldDown( bool max ) -{ - LLVisualParamHint* hint = max ? mHintMax : mHintMin; - LLViewerVisualParam* param = hint->getVisualParam(); - - LLWearable* wearable = gAgentWearables.getWearable((LLWearableType::EType)param->getWearableType(),0); // TODO: MULTI-WEARABLE - - if(!wearable) - return; - - F32 current_weight = wearable->getVisualParamWeight( param->getID() ); - - if (current_weight != hint->getVisualParamWeight() ) - { - const F32 FULL_BLEND_TIME = 2.f; - F32 elapsed_time = mMouseDownTimer.getElapsedTimeF32() - mLastHeldTime; - mLastHeldTime += elapsed_time; - - F32 new_weight; - if (current_weight > hint->getVisualParamWeight() ) - { - new_weight = current_weight - (elapsed_time / FULL_BLEND_TIME); - } - else - { - new_weight = current_weight + (elapsed_time / FULL_BLEND_TIME); - } - - // Make sure we're not taking the slider out of bounds - // (this is where some simple UI limits are stored) - F32 new_percent = weightToPercent(new_weight); - LLSliderCtrl* slider = getChild("param slider"); - if (slider) - { - if (slider->getMinValue() < new_percent - && new_percent < slider->getMaxValue()) - { - wearable->setVisualParamWeight(param->getID(), new_weight, TRUE); - wearable->writeToAvatar(); - gAgentAvatarp->updateVisualParams(); - - slider->setValue( weightToPercent( new_weight ) ); - } - } - } -} - -void LLScrollingPanelParam::onHintMouseUp( bool max ) -{ - F32 elapsed_time = mMouseDownTimer.getElapsedTimeF32(); - - LLVOAvatar* avatar = gAgentAvatarp; - if (avatar) - { - LLVisualParamHint* hint = max ? mHintMax : mHintMin; - - if (elapsed_time < PARAM_STEP_TIME_THRESHOLD) - { - LLViewerVisualParam* param = hint->getVisualParam(); - - LLWearable* wearable = gAgentWearables.getWearable((LLWearableType::EType)param->getWearableType(),0); - if(wearable) - { - // step in direction - F32 current_weight = wearable->getVisualParamWeight( param->getID() ); - F32 range = mHintMax->getVisualParamWeight() - mHintMin->getVisualParamWeight(); - //if min, range should be negative. - if(!max) - range *= -1.f; - // step a fraction in the negative direction - F32 new_weight = current_weight + (range / 10.f); - F32 new_percent = weightToPercent(new_weight); - LLSliderCtrl* slider = getChild("param slider"); - if (slider) - { - if (slider->getMinValue() < new_percent - && new_percent < slider->getMaxValue()) - { - wearable->setVisualParamWeight(param->getID(), new_weight, TRUE); - wearable->writeToAvatar(); - slider->setValue( weightToPercent( new_weight ) ); - } - } - } - } - } - - LLVisualParamHint::requestHintUpdates( mHintMin, mHintMax ); -} - - -F32 LLScrollingPanelParam::weightToPercent( F32 weight ) -{ - LLViewerVisualParam* param = mParam; - return (weight - param->getMinWeight()) / (param->getMaxWeight() - param->getMinWeight()) * 100.f; -} - -F32 LLScrollingPanelParam::percentToWeight( F32 percent ) -{ - LLViewerVisualParam* param = mParam; - return percent / 100.f * (param->getMaxWeight() - param->getMinWeight()) + param->getMinWeight(); -} - -const std::string& LLFloaterCustomize::getEditGroup() -{ - return getCurrentWearablePanel()->getCurrentSubpart()->mEditGroup; -} - - ///////////////////////////////////////////////////////////////////// // LLFloaterCustomize @@ -2055,325 +687,6 @@ void* LLFloaterCustomize::createWearablePanel(void* userdata) void LLFloaterCustomize::initWearablePanels() { - ///////////////////////////////////////// - // Shape - LLPanelEditWearable* panel = mWearablePanelList[ LLWearableType::WT_SHAPE ]; - - // body - LLSubpart* part = new LLSubpart("mPelvis", "shape_body", LLVector3d(0.f,0.f,0.1f), LLVector3d(-2.5f, 0.5f, 0.8f)); - panel->addSubpart( "Body", SUBPART_SHAPE_WHOLE, part ); - - // head supparts - const LLVector3d head_target(0.f, 0.f, 0.05f); - const LLVector3d head_camera(-0.5f, 0.05f, 0.07f); - - part = new LLSubpart("mHead", "shape_head", head_target, head_camera); - panel->addSubpart( "Head", SUBPART_SHAPE_HEAD, part ); - - part = new LLSubpart("mHead", "shape_eyes", head_target, head_camera); - panel->addSubpart( "Eyes", SUBPART_SHAPE_EYES, part ); - - part = new LLSubpart("mHead", "shape_ears", head_target, head_camera); - panel->addSubpart( "Ears", SUBPART_SHAPE_EARS, part ); - - part = new LLSubpart("mHead", "shape_nose", head_target, head_camera); - panel->addSubpart( "Nose", SUBPART_SHAPE_NOSE, part ); - - part = new LLSubpart("mHead", "shape_mouth", head_target, head_camera); - panel->addSubpart( "Mouth", SUBPART_SHAPE_MOUTH, part ); - - part = new LLSubpart("mHead", "shape_chin", head_target, head_camera); - panel->addSubpart( "Chin", SUBPART_SHAPE_CHIN, part ); - - // torso - part = new LLSubpart("mTorso", "shape_torso", LLVector3d(0.f, 0.f, 0.3f), LLVector3d(-1.f, 0.15f, 0.3f)); - panel->addSubpart( "Torso", SUBPART_SHAPE_TORSO, part ); - - // legs - part = new LLSubpart("mPelvis", "shape_legs", LLVector3d(0.f, 0.f, -0.5f), LLVector3d(-1.6f, 0.15f, -0.5f)); - panel->addSubpart( "Legs", SUBPART_SHAPE_LEGS, part ); - - panel->childSetCommitCallback("sex radio", LLPanelEditWearable::onCommitSexChange, panel); - - ///////////////////////////////////////// - // Skin - panel = mWearablePanelList[ LLWearableType::WT_SKIN ]; - - part = new LLSubpart("mHead", "skin_color", head_target, head_camera); - panel->addSubpart( "Skin Color", SUBPART_SKIN_COLOR, part ); - - part = new LLSubpart("mHead", "skin_facedetail", head_target, head_camera); - panel->addSubpart( "Face Detail", SUBPART_SKIN_FACEDETAIL, part ); - - part = new LLSubpart("mHead", "skin_makeup", head_target, head_camera); - panel->addSubpart( "Makeup", SUBPART_SKIN_MAKEUP, part ); - - part = new LLSubpart("mPelvis", "skin_bodydetail", LLVector3d(0.f, 0.f, -0.2f), LLVector3d(-2.5f, 0.5f, 0.5f)); - panel->addSubpart( "Body Detail", SUBPART_SKIN_BODYDETAIL, part ); - - panel->addTextureDropTarget( TEX_HEAD_BODYPAINT, "Head Tattoos", LLUUID::null, TRUE ); - panel->addTextureDropTarget( TEX_UPPER_BODYPAINT, "Upper Tattoos", LLUUID::null, TRUE ); - panel->addTextureDropTarget( TEX_LOWER_BODYPAINT, "Lower Tattoos", LLUUID::null, TRUE ); - - ///////////////////////////////////////// - // Hair - panel = mWearablePanelList[ LLWearableType::WT_HAIR ]; - - part = new LLSubpart("mHead", "hair_color", LLVector3d(0.f, 0.f, 0.10f), LLVector3d(-0.4f, 0.05f, 0.10f)); - panel->addSubpart( "Color", SUBPART_HAIR_COLOR, part ); - - part = new LLSubpart("mHead", "hair_style", head_target, head_camera); - panel->addSubpart( "Style", SUBPART_HAIR_STYLE, part ); - - part = new LLSubpart("mHead", "hair_eyebrows", head_target, head_camera); - panel->addSubpart( "Eyebrows", SUBPART_HAIR_EYEBROWS, part ); - - part = new LLSubpart("mHead", "hair_facial", head_target, head_camera, SEX_MALE); - panel->addSubpart( "Facial", SUBPART_HAIR_FACIAL, part ); - - panel->addTextureDropTarget(TEX_HAIR, "Texture", - LLUUID( gSavedSettings.getString( "UIImgDefaultHairUUID" ) ), - FALSE ); - - ///////////////////////////////////////// - // Eyes - panel = mWearablePanelList[ LLWearableType::WT_EYES ]; - - part = new LLSubpart("mHead", "eyes", head_target, head_camera); - panel->addSubpart( LLStringUtil::null, SUBPART_EYES, part ); - - panel->addTextureDropTarget(TEX_EYES_IRIS, "Iris", - LLUUID( gSavedSettings.getString( "UIImgDefaultEyesUUID" ) ), - FALSE ); - - ///////////////////////////////////////// - // Shirt - panel = mWearablePanelList[ LLWearableType::WT_SHIRT ]; - - part = new LLSubpart("mTorso", "shirt", LLVector3d(0.f, 0.f, 0.3f), LLVector3d(-1.f, 0.15f, 0.3f)); - panel->addSubpart( LLStringUtil::null, SUBPART_SHIRT, part ); - - panel->addTextureDropTarget( TEX_UPPER_SHIRT, "Fabric", - LLUUID( gSavedSettings.getString( "UIImgDefaultShirtUUID" ) ), - FALSE ); - - panel->addColorSwatch( TEX_UPPER_SHIRT, "Color/Tint" ); - - - ///////////////////////////////////////// - // Pants - panel = mWearablePanelList[ LLWearableType::WT_PANTS ]; - - part = new LLSubpart("mPelvis", "pants", LLVector3d(0.f, 0.f, -0.5f), LLVector3d(-1.6f, 0.15f, -0.5f)); - panel->addSubpart( LLStringUtil::null, SUBPART_PANTS, part ); - - panel->addTextureDropTarget(TEX_LOWER_PANTS, "Fabric", - LLUUID( gSavedSettings.getString( "UIImgDefaultPantsUUID" ) ), - FALSE ); - - panel->addColorSwatch( TEX_LOWER_PANTS, "Color/Tint" ); - - - ///////////////////////////////////////// - // Shoes - panel = mWearablePanelList[ LLWearableType::WT_SHOES ]; - - if (panel) - { - part = new LLSubpart("mPelvis", "shoes", LLVector3d(0.f, 0.f, -0.5f), LLVector3d(-1.6f, 0.15f, -0.5f)); - panel->addSubpart( LLStringUtil::null, SUBPART_SHOES, part ); - - panel->addTextureDropTarget( TEX_LOWER_SHOES, "Fabric", - LLUUID( gSavedSettings.getString( "UIImgDefaultShoesUUID" ) ), - FALSE ); - - panel->addColorSwatch( TEX_LOWER_SHOES, "Color/Tint" ); - } - - - ///////////////////////////////////////// - // Socks - panel = mWearablePanelList[ LLWearableType::WT_SOCKS ]; - - if (panel) - { - part = new LLSubpart("mPelvis", "socks", LLVector3d(0.f, 0.f, -0.5f), LLVector3d(-1.6f, 0.15f, -0.5f)); - panel->addSubpart( LLStringUtil::null, SUBPART_SOCKS, part ); - - panel->addTextureDropTarget( TEX_LOWER_SOCKS, "Fabric", - LLUUID( gSavedSettings.getString( "UIImgDefaultSocksUUID" ) ), - FALSE ); - - panel->addColorSwatch( TEX_LOWER_SOCKS, "Color/Tint" ); - } - - ///////////////////////////////////////// - // Jacket - panel = mWearablePanelList[ LLWearableType::WT_JACKET ]; - - if (panel) - { - part = new LLSubpart("mTorso", "jacket", LLVector3d(), LLVector3d(-2.f, 0.1f, 0.3f)); - panel->addSubpart( LLStringUtil::null, SUBPART_JACKET, part ); - - panel->addTextureDropTarget( TEX_UPPER_JACKET, "Upper Fabric", - LLUUID( gSavedSettings.getString( "UIImgDefaultJacketUUID" ) ), - FALSE ); - panel->addTextureDropTarget( TEX_LOWER_JACKET, "Lower Fabric", - LLUUID( gSavedSettings.getString( "UIImgDefaultJacketUUID" ) ), - FALSE ); - - panel->addColorSwatch( TEX_UPPER_JACKET, "Color/Tint" ); - } - - ///////////////////////////////////////// - // Skirt - panel = mWearablePanelList[ LLWearableType::WT_SKIRT ]; - - if (panel) - { - part = new LLSubpart("mPelvis", "skirt", LLVector3d(0.f, 0.f, -0.5f), LLVector3d(-1.6f, 0.15f, -0.5f)); - panel->addSubpart( LLStringUtil::null, SUBPART_SKIRT, part ); - - panel->addTextureDropTarget( TEX_SKIRT, "Fabric", - LLUUID( gSavedSettings.getString( "UIImgDefaultSkirtUUID" ) ), - FALSE ); - - panel->addColorSwatch( TEX_SKIRT, "Color/Tint" ); - } - - - ///////////////////////////////////////// - // Gloves - panel = mWearablePanelList[ LLWearableType::WT_GLOVES ]; - - if (panel) - { - part = new LLSubpart("mTorso", "gloves", LLVector3d(), LLVector3d(-1.f, 0.15f, 0.f)); - panel->addSubpart( LLStringUtil::null, SUBPART_GLOVES, part ); - - panel->addTextureDropTarget( TEX_UPPER_GLOVES, "Fabric", - LLUUID( gSavedSettings.getString( "UIImgDefaultGlovesUUID" ) ), - FALSE ); - - panel->addColorSwatch( TEX_UPPER_GLOVES, "Color/Tint" ); - } - - - ///////////////////////////////////////// - // Undershirt - panel = mWearablePanelList[ LLWearableType::WT_UNDERSHIRT ]; - - if (panel) - { - part = new LLSubpart("mTorso", "undershirt", LLVector3d(0.f, 0.f, 0.3f), LLVector3d(-1.f, 0.15f, 0.3f)); - panel->addSubpart( LLStringUtil::null, SUBPART_UNDERSHIRT, part ); - - panel->addTextureDropTarget( TEX_UPPER_UNDERSHIRT, "Fabric", - LLUUID( gSavedSettings.getString( "UIImgDefaultUnderwearUUID" ) ), - FALSE ); - - panel->addColorSwatch( TEX_UPPER_UNDERSHIRT, "Color/Tint" ); - } - - ///////////////////////////////////////// - // Underpants - panel = mWearablePanelList[ LLWearableType::WT_UNDERPANTS ]; - - if (panel) - { - part = new LLSubpart("mPelvis", "underpants", LLVector3d(0.f, 0.f, -0.5f), LLVector3d(-1.6f, 0.15f, -0.5f)); - panel->addSubpart( LLStringUtil::null, SUBPART_UNDERPANTS, part ); - - panel->addTextureDropTarget( TEX_LOWER_UNDERPANTS, "Fabric", - LLUUID( gSavedSettings.getString( "UIImgDefaultUnderwearUUID" ) ), - FALSE ); - - panel->addColorSwatch( TEX_LOWER_UNDERPANTS, "Color/Tint" ); - } - - ///////////////////////////////////////// - // Alpha - panel = mWearablePanelList[LLWearableType::WT_ALPHA]; - - if (panel) - { - part = new LLSubpart("mPelvis", "alpha", LLVector3d(0.f, 0.f, 0.1f), LLVector3d(-2.5f, 0.5f, 0.8f)); - panel->addSubpart(LLStringUtil::null, SUBPART_ALPHA, part); - - panel->addTextureDropTarget(TEX_LOWER_ALPHA, "Lower Alpha", - LLUUID(gSavedSettings.getString("UIImgDefaultAlphaUUID")), - TRUE); - panel->addTextureDropTarget(TEX_UPPER_ALPHA, "Upper Alpha", - LLUUID(gSavedSettings.getString("UIImgDefaultAlphaUUID")), - TRUE); - panel->addTextureDropTarget(TEX_HEAD_ALPHA, "Head Alpha", - LLUUID(gSavedSettings.getString("UIImgDefaultAlphaUUID")), - TRUE); - panel->addTextureDropTarget(TEX_EYES_ALPHA, "Eye Alpha", - LLUUID(gSavedSettings.getString("UIImgDefaultAlphaUUID")), - TRUE); - panel->addTextureDropTarget(TEX_HAIR_ALPHA, "Hair Alpha", - LLUUID(gSavedSettings.getString("UIImgDefaultAlphaUUID")), - TRUE); - - panel->addInvisibilityCheckbox(TEX_LOWER_ALPHA, "lower alpha texture invisible"); - panel->addInvisibilityCheckbox(TEX_UPPER_ALPHA, "upper alpha texture invisible"); - panel->addInvisibilityCheckbox(TEX_HEAD_ALPHA, "head alpha texture invisible"); - panel->addInvisibilityCheckbox(TEX_EYES_ALPHA, "eye alpha texture invisible"); - panel->addInvisibilityCheckbox(TEX_HAIR_ALPHA, "hair alpha texture invisible"); - } - - ///////////////////////////////////////// - // Tattoo - panel = mWearablePanelList[LLWearableType::WT_TATTOO]; - - if (panel) - { - part = new LLSubpart("mPelvis", "tattoo", LLVector3d(0.f, 0.f, 0.1f), LLVector3d(-2.5f, 0.5f, 0.8f)); - panel->addSubpart(LLStringUtil::null, SUBPART_TATTOO, part); - - panel->addTextureDropTarget(TEX_LOWER_TATTOO, "Lower Tattoo", - LLUUID::null, - TRUE); - panel->addTextureDropTarget(TEX_UPPER_TATTOO, "Upper Tattoo", - LLUUID::null, - TRUE); - panel->addTextureDropTarget(TEX_HEAD_TATTOO, "Head Tattoo", - LLUUID::null, - TRUE); - panel->addColorSwatch(TEX_LOWER_TATTOO, "Color/Tint"); //-ASC-TTRFE - } - - ///////////////////////////////////////// - // Physics - - panel = mWearablePanelList[LLWearableType::WT_PHYSICS]; - - if(panel) - { - part = new LLSubpart("mTorso", "physics_breasts_updown", LLVector3d(0.f, 0.f, 0.1f), LLVector3d(-0.8f, 0.15f, 0.38f), SEX_FEMALE, false); - panel->addSubpart("Breast Bounce", SUBPART_PHYSICS_BREASTS_UPDOWN, part); - - part = new LLSubpart("mTorso", "physics_breasts_inout", LLVector3d(0.f, 0.f, 0.1f), LLVector3d(-0.8f, 0.15f, 0.38f), SEX_FEMALE, false); - panel->addSubpart("Breast Cleavage", SUBPART_PHYSICS_BREASTS_INOUT, part); - - part = new LLSubpart("mTorso", "physics_breasts_leftright", LLVector3d(0.f, 0.f, 0.1f), LLVector3d(-0.8f, 0.15f, 0.38f), SEX_FEMALE, false); - panel->addSubpart("Breast Sway", SUBPART_PHYSICS_BREASTS_LEFTRIGHT, part); - - part = new LLSubpart("mTorso", "physics_belly_updown", LLVector3d(0.f, 0.f, -.05f), LLVector3d(-0.8f, 0.15f, 0.38f), false); - panel->addSubpart("Belly Bounce", SUBPART_PHYSICS_BELLY_UPDOWN, part); - - part = new LLSubpart("mPelvis", "physics_butt_updown", LLVector3d(0.f, 0.f,-.1f), LLVector3d(0.3f, 0.8f, -0.1f), false); - panel->addSubpart("Butt Bounce", SUBPART_PHYSICS_BUTT_UPDOWN, part); - - part = new LLSubpart("mPelvis", "physics_butt_leftright", LLVector3d(0.f, 0.f,-.1f), LLVector3d(0.3f, 0.8f, -0.1f), false); - panel->addSubpart("Butt Sway", SUBPART_PHYSICS_BUTT_LEFTRIGHT, part); - - part = new LLSubpart("mTorso", "physics_advanced", LLVector3d(0.f, 0.f, 0.1f), LLVector3d(-2.5f, 0.5f, 0.8f), false); - panel->addSubpart("Advanced Parameters", SUBPART_PHYSICS_ADVANCED, part); - - } } //////////////////////////////////////////////////////////////////////////// diff --git a/indra/newview/llfloatercustomize.h b/indra/newview/llfloatercustomize.h index c19a570ad..d4e7e1ad5 100644 --- a/indra/newview/llfloatercustomize.h +++ b/indra/newview/llfloatercustomize.h @@ -91,7 +91,6 @@ public: void generateVisualParamHints(LLViewerJointMesh* joint_mesh, param_map& params, bool bVisualHint); - const std::string& getEditGroup(); void updateScrollingPanelList(BOOL allow_modify); void setWearable(LLWearableType::EType type, LLWearable* wearable, U32 perm_mask, BOOL is_complete); diff --git a/indra/newview/llpaneleditwearable.cpp b/indra/newview/llpaneleditwearable.cpp new file mode 100644 index 000000000..80780594d --- /dev/null +++ b/indra/newview/llpaneleditwearable.cpp @@ -0,0 +1,1405 @@ +/** + * @file llpaneleditwearable.cpp + * @brief UI panel for editing of a particular wearable item. + * + * $LicenseInfo:firstyear=2009&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llpaneleditwearable.h" +#include "llpanel.h" +#include "llwearable.h" +#include "lluictrl.h" +#include "llscrollingpanellist.h" +#include "llvisualparam.h" +#include "lltoolmorph.h" +#include "llviewerjointmesh.h" +#include "lltrans.h" +#include "llbutton.h" +#include "llsliderctrl.h" +#include "llagent.h" +#include "llvoavatarself.h" +#include "lltexteditor.h" +#include "lltextbox.h" +#include "llagentwearables.h" +#include "llscrollingpanelparam.h" +#include "llradiogroup.h" +#include "llnotificationsutil.h" + +#include "llcolorswatch.h" +#include "lltexturectrl.h" +#include "lltextureentry.h" +#include "llviewercontrol.h" // gSavedSettings +#include "llviewertexturelist.h" +#include "llagentcamera.h" +#include "llmorphview.h" + +#include "llcommandhandler.h" +#include "llappearancemgr.h" +#include "llinventoryfunctions.h" +#include "llfloatercustomize.h" + +#include "llwearablelist.h" + +// subparts of the UI for focus, camera position, etc. +enum ESubpart { + SUBPART_SHAPE_HEAD = 1, // avoid 0 + SUBPART_SHAPE_EYES, + SUBPART_SHAPE_EARS, + SUBPART_SHAPE_NOSE, + SUBPART_SHAPE_MOUTH, + SUBPART_SHAPE_CHIN, + SUBPART_SHAPE_TORSO, + SUBPART_SHAPE_LEGS, + SUBPART_SHAPE_WHOLE, + SUBPART_SHAPE_DETAIL, + SUBPART_SKIN_COLOR, + SUBPART_SKIN_FACEDETAIL, + SUBPART_SKIN_MAKEUP, + SUBPART_SKIN_BODYDETAIL, + SUBPART_HAIR_COLOR, + SUBPART_HAIR_STYLE, + SUBPART_HAIR_EYEBROWS, + SUBPART_HAIR_FACIAL, + SUBPART_EYES, + SUBPART_SHIRT, + SUBPART_PANTS, + SUBPART_SHOES, + SUBPART_SOCKS, + SUBPART_JACKET, + SUBPART_GLOVES, + SUBPART_UNDERSHIRT, + SUBPART_UNDERPANTS, + SUBPART_SKIRT, + SUBPART_ALPHA, + SUBPART_TATTOO, + SUBPART_PHYSICS_BREASTS_UPDOWN, + SUBPART_PHYSICS_BREASTS_INOUT, + SUBPART_PHYSICS_BREASTS_LEFTRIGHT, + SUBPART_PHYSICS_BELLY_UPDOWN, + SUBPART_PHYSICS_BUTT_UPDOWN, + SUBPART_PHYSICS_BUTT_LEFTRIGHT, + SUBPART_PHYSICS_ADVANCED, + }; + +using namespace LLVOAvatarDefines; + +typedef std::vector subpart_vec_t; + +// Locally defined classes + +class LLEditWearableDictionary : public LLSingleton +{ + //-------------------------------------------------------------------- + // Constructors and Destructors + //-------------------------------------------------------------------- +public: + LLEditWearableDictionary(); + virtual ~LLEditWearableDictionary(); + + //-------------------------------------------------------------------- + // Wearable Types + //-------------------------------------------------------------------- +public: + struct WearableEntry : public LLDictionaryEntry + { + WearableEntry(LLWearableType::EType type, + const std::string &title, + U8 num_color_swatches, // number of 'color_swatches' + U8 num_texture_pickers, // number of 'texture_pickers' + U8 num_subparts, ... ); // number of subparts followed by a list of ETextureIndex and ESubparts + + + const LLWearableType::EType mWearableType; + subpart_vec_t mSubparts; + texture_vec_t mColorSwatchCtrls; + texture_vec_t mTextureCtrls; + }; + + struct Wearables : public LLDictionary + { + Wearables(); + } mWearables; + + const WearableEntry* getWearable(LLWearableType::EType type) const { return mWearables.lookup(type); } + + //-------------------------------------------------------------------- + // Subparts + //-------------------------------------------------------------------- +public: + struct SubpartEntry : public LLDictionaryEntry + { + SubpartEntry(ESubpart part, + const std::string &joint, + const std::string &edit_group, + const std::string &button_name, + const LLVector3d &target_offset, + const LLVector3d &camera_offset, + const ESex &sex); + + + ESubpart mSubpart; + std::string mTargetJoint; + std::string mEditGroup; + std::string mButtonName; + LLVector3d mTargetOffset; + LLVector3d mCameraOffset; + ESex mSex; + }; + + struct Subparts : public LLDictionary + { + Subparts(); + } mSubparts; + + const SubpartEntry* getSubpart(ESubpart subpart) const { return mSubparts.lookup(subpart); } + + //-------------------------------------------------------------------- + // Picker Control Entries + //-------------------------------------------------------------------- +public: + struct PickerControlEntry : public LLDictionaryEntry + { + PickerControlEntry(ETextureIndex tex_index, + const std::string name, + const LLUUID default_image_id = LLUUID::null, + const bool allow_no_texture = false, + const std::string checkbox_name = LLStringUtil::null); + ETextureIndex mTextureIndex; + const std::string mControlName; + const LLUUID mDefaultImageId; + const bool mAllowNoTexture; + std::string mCheckboxName; + }; + + struct ColorSwatchCtrls : public LLDictionary + { + ColorSwatchCtrls(); + } mColorSwatchCtrls; + + struct TextureCtrls : public LLDictionary + { + TextureCtrls(); + } mTextureCtrls; + + const PickerControlEntry* getTexturePicker(ETextureIndex index) const { return mTextureCtrls.lookup(index); } + const PickerControlEntry* getColorSwatch(ETextureIndex index) const { return mColorSwatchCtrls.lookup(index); } +}; + +LLEditWearableDictionary::LLEditWearableDictionary() +{ + +} + +//virtual +LLEditWearableDictionary::~LLEditWearableDictionary() +{ +} + +LLEditWearableDictionary::Wearables::Wearables() +{ + // note the subpart that is listed first is treated as "default", regardless of what order is in enum. + // Please match the order presented in XUI. -Nyx + // this will affect what camera angle is shown when first editing a wearable + addEntry(LLWearableType::WT_SHAPE, new WearableEntry(LLWearableType::WT_SHAPE,"edit_shape_title",0,0,9, SUBPART_SHAPE_WHOLE, SUBPART_SHAPE_HEAD, SUBPART_SHAPE_EYES, SUBPART_SHAPE_EARS, SUBPART_SHAPE_NOSE, SUBPART_SHAPE_MOUTH, SUBPART_SHAPE_CHIN, SUBPART_SHAPE_TORSO, SUBPART_SHAPE_LEGS)); + addEntry(LLWearableType::WT_SKIN, new WearableEntry(LLWearableType::WT_SKIN,"edit_skin_title",0,3,4, TEX_HEAD_BODYPAINT, TEX_UPPER_BODYPAINT, TEX_LOWER_BODYPAINT, SUBPART_SKIN_COLOR, SUBPART_SKIN_FACEDETAIL, SUBPART_SKIN_MAKEUP, SUBPART_SKIN_BODYDETAIL)); + addEntry(LLWearableType::WT_HAIR, new WearableEntry(LLWearableType::WT_HAIR,"edit_hair_title",0,1,4, TEX_HAIR, SUBPART_HAIR_COLOR, SUBPART_HAIR_STYLE, SUBPART_HAIR_EYEBROWS, SUBPART_HAIR_FACIAL)); + addEntry(LLWearableType::WT_EYES, new WearableEntry(LLWearableType::WT_EYES,"edit_eyes_title",0,1,1, TEX_EYES_IRIS, SUBPART_EYES)); + addEntry(LLWearableType::WT_SHIRT, new WearableEntry(LLWearableType::WT_SHIRT,"edit_shirt_title",1,1,1, TEX_UPPER_SHIRT, TEX_UPPER_SHIRT, SUBPART_SHIRT)); + addEntry(LLWearableType::WT_PANTS, new WearableEntry(LLWearableType::WT_PANTS,"edit_pants_title",1,1,1, TEX_LOWER_PANTS, TEX_LOWER_PANTS, SUBPART_PANTS)); + addEntry(LLWearableType::WT_SHOES, new WearableEntry(LLWearableType::WT_SHOES,"edit_shoes_title",1,1,1, TEX_LOWER_SHOES, TEX_LOWER_SHOES, SUBPART_SHOES)); + addEntry(LLWearableType::WT_SOCKS, new WearableEntry(LLWearableType::WT_SOCKS,"edit_socks_title",1,1,1, TEX_LOWER_SOCKS, TEX_LOWER_SOCKS, SUBPART_SOCKS)); + addEntry(LLWearableType::WT_JACKET, new WearableEntry(LLWearableType::WT_JACKET,"edit_jacket_title",1,2,1, TEX_UPPER_JACKET, TEX_UPPER_JACKET, TEX_LOWER_JACKET, SUBPART_JACKET)); + addEntry(LLWearableType::WT_GLOVES, new WearableEntry(LLWearableType::WT_GLOVES,"edit_gloves_title",1,1,1, TEX_UPPER_GLOVES, TEX_UPPER_GLOVES, SUBPART_GLOVES)); + addEntry(LLWearableType::WT_UNDERSHIRT, new WearableEntry(LLWearableType::WT_UNDERSHIRT,"edit_undershirt_title",1,1,1, TEX_UPPER_UNDERSHIRT, TEX_UPPER_UNDERSHIRT, SUBPART_UNDERSHIRT)); + addEntry(LLWearableType::WT_UNDERPANTS, new WearableEntry(LLWearableType::WT_UNDERPANTS,"edit_underpants_title",1,1,1, TEX_LOWER_UNDERPANTS, TEX_LOWER_UNDERPANTS, SUBPART_UNDERPANTS)); + addEntry(LLWearableType::WT_SKIRT, new WearableEntry(LLWearableType::WT_SKIRT,"edit_skirt_title",1,1,1, TEX_SKIRT, TEX_SKIRT, SUBPART_SKIRT)); + addEntry(LLWearableType::WT_ALPHA, new WearableEntry(LLWearableType::WT_ALPHA,"edit_alpha_title",0,5,1, TEX_LOWER_ALPHA, TEX_UPPER_ALPHA, TEX_HEAD_ALPHA, TEX_EYES_ALPHA, TEX_HAIR_ALPHA, SUBPART_ALPHA)); + addEntry(LLWearableType::WT_TATTOO, new WearableEntry(LLWearableType::WT_TATTOO,"edit_tattoo_title",1,3,1, TEX_HEAD_TATTOO, TEX_LOWER_TATTOO, TEX_UPPER_TATTOO, TEX_HEAD_TATTOO, SUBPART_TATTOO)); + addEntry(LLWearableType::WT_PHYSICS, new WearableEntry(LLWearableType::WT_PHYSICS,"edit_physics_title",0,0,7, SUBPART_PHYSICS_BREASTS_UPDOWN, SUBPART_PHYSICS_BREASTS_INOUT, SUBPART_PHYSICS_BREASTS_LEFTRIGHT, SUBPART_PHYSICS_BELLY_UPDOWN, SUBPART_PHYSICS_BUTT_UPDOWN, SUBPART_PHYSICS_BUTT_LEFTRIGHT, SUBPART_PHYSICS_ADVANCED)); +} + +LLEditWearableDictionary::WearableEntry::WearableEntry(LLWearableType::EType type, + const std::string &title, + U8 num_color_swatches, + U8 num_texture_pickers, + U8 num_subparts, ... ) : + LLDictionaryEntry(title), + mWearableType(type) +{ + va_list argp; + va_start(argp, num_subparts); + + for (U8 i = 0; i < num_color_swatches; ++i) + { + ETextureIndex index = (ETextureIndex)va_arg(argp,int); + mColorSwatchCtrls.push_back(index); + } + + for (U8 i = 0; i < num_texture_pickers; ++i) + { + ETextureIndex index = (ETextureIndex)va_arg(argp,int); + mTextureCtrls.push_back(index); + } + + for (U8 i = 0; i < num_subparts; ++i) + { + ESubpart part = (ESubpart)va_arg(argp,int); + mSubparts.push_back(part); + } +} + +LLEditWearableDictionary::Subparts::Subparts() +{ + addEntry(SUBPART_SHAPE_WHOLE, new SubpartEntry(SUBPART_SHAPE_WHOLE, "mPelvis", "shape_body","Body", LLVector3d(0.f, 0.f, 0.1f), LLVector3d(-2.5f, 0.5f, 0.8f),SEX_BOTH)); + const LLVector3d head_target(0.f, 0.f, 0.05f); + const LLVector3d head_camera(-0.5f, 0.05f, 0.07f); + addEntry(SUBPART_SHAPE_HEAD, new SubpartEntry(SUBPART_SHAPE_HEAD, "mHead", "shape_head","Head", head_target, head_camera,SEX_BOTH)); + addEntry(SUBPART_SHAPE_EYES, new SubpartEntry(SUBPART_SHAPE_EYES, "mHead", "shape_eyes","Eyes", head_target, head_camera,SEX_BOTH)); + addEntry(SUBPART_SHAPE_EARS, new SubpartEntry(SUBPART_SHAPE_EARS, "mHead", "shape_ears","Ears", head_target, head_camera,SEX_BOTH)); + addEntry(SUBPART_SHAPE_NOSE, new SubpartEntry(SUBPART_SHAPE_NOSE, "mHead", "shape_nose","Nose", head_target, head_camera,SEX_BOTH)); + addEntry(SUBPART_SHAPE_MOUTH, new SubpartEntry(SUBPART_SHAPE_MOUTH, "mHead", "shape_mouth","Mouth", head_target, head_camera,SEX_BOTH)); + addEntry(SUBPART_SHAPE_CHIN, new SubpartEntry(SUBPART_SHAPE_CHIN, "mHead", "shape_chin","Chin", head_target, head_camera,SEX_BOTH)); + addEntry(SUBPART_SHAPE_TORSO, new SubpartEntry(SUBPART_SHAPE_TORSO, "mTorso", "shape_torso","Torso", LLVector3d(0.f, 0.f, 0.3f), LLVector3d(-1.f, 0.15f, 0.3f), SEX_BOTH)); + addEntry(SUBPART_SHAPE_LEGS, new SubpartEntry(SUBPART_SHAPE_LEGS, "mPelvis", "shape_legs","Legs", LLVector3d(0.f, 0.f, -0.5f), LLVector3d(-1.6f, 0.15f, -0.5f), SEX_BOTH)); + + addEntry(SUBPART_SKIN_COLOR, new SubpartEntry(SUBPART_SKIN_COLOR, "mHead", "skin_color","Skin Color", head_target, head_camera,SEX_BOTH)); + addEntry(SUBPART_SKIN_FACEDETAIL, new SubpartEntry(SUBPART_SKIN_FACEDETAIL, "mHead", "skin_facedetail","Face Detail", head_target, head_camera,SEX_BOTH)); + addEntry(SUBPART_SKIN_MAKEUP, new SubpartEntry(SUBPART_SKIN_MAKEUP, "mHead", "skin_makeup","Makeup", head_target, head_camera,SEX_BOTH)); + addEntry(SUBPART_SKIN_BODYDETAIL, new SubpartEntry(SUBPART_SKIN_BODYDETAIL, "mPelvis", "skin_bodydetail","Body Detail", LLVector3d(0.f, 0.f, -0.2f), LLVector3d(-2.5f, 0.5f, 0.5f), SEX_BOTH)); + + addEntry(SUBPART_HAIR_COLOR, new SubpartEntry(SUBPART_HAIR_COLOR, "mHead", "hair_color","Color", LLVector3d(0.f, 0.f, 0.10f), LLVector3d(-0.4f, 0.05f, 0.10f),SEX_BOTH)); + addEntry(SUBPART_HAIR_STYLE, new SubpartEntry(SUBPART_HAIR_STYLE, "mHead", "hair_style","Style", LLVector3d(0.f, 0.f, 0.10f), LLVector3d(-0.4f, 0.05f, 0.10f),SEX_BOTH)); + addEntry(SUBPART_HAIR_EYEBROWS, new SubpartEntry(SUBPART_HAIR_EYEBROWS, "mHead", "hair_eyebrows","Eyebrows", head_target, head_camera,SEX_BOTH)); + addEntry(SUBPART_HAIR_FACIAL, new SubpartEntry(SUBPART_HAIR_FACIAL, "mHead", "hair_facial","Facial", head_target, head_camera,SEX_MALE)); + + addEntry(SUBPART_EYES, new SubpartEntry(SUBPART_EYES, "mHead", "eyes",LLStringUtil::null, head_target, head_camera,SEX_BOTH)); + + addEntry(SUBPART_SHIRT, new SubpartEntry(SUBPART_SHIRT, "mTorso", "shirt",LLStringUtil::null, LLVector3d(0.f, 0.f, 0.3f), LLVector3d(-1.f, 0.15f, 0.3f), SEX_BOTH)); + addEntry(SUBPART_PANTS, new SubpartEntry(SUBPART_PANTS, "mPelvis", "pants",LLStringUtil::null, LLVector3d(0.f, 0.f, -0.5f), LLVector3d(-1.6f, 0.15f, -0.5f), SEX_BOTH)); + addEntry(SUBPART_SHOES, new SubpartEntry(SUBPART_SHOES, "mPelvis", "shoes",LLStringUtil::null, LLVector3d(0.f, 0.f, -0.5f), LLVector3d(-1.6f, 0.15f, -0.5f), SEX_BOTH)); + addEntry(SUBPART_SOCKS, new SubpartEntry(SUBPART_SOCKS, "mPelvis", "socks",LLStringUtil::null, LLVector3d(0.f, 0.f, -0.5f), LLVector3d(-1.6f, 0.15f, -0.5f), SEX_BOTH)); + addEntry(SUBPART_JACKET, new SubpartEntry(SUBPART_JACKET, "mTorso", "jacket",LLStringUtil::null, LLVector3d(0.f, 0.f, 0.f), LLVector3d(-2.f, 0.1f, 0.3f), SEX_BOTH)); + addEntry(SUBPART_SKIRT, new SubpartEntry(SUBPART_SKIRT, "mPelvis", "skirt",LLStringUtil::null, LLVector3d(0.f, 0.f, -0.5f), LLVector3d(-1.6f, 0.15f, -0.5f), SEX_BOTH)); + addEntry(SUBPART_GLOVES, new SubpartEntry(SUBPART_GLOVES, "mTorso", "gloves",LLStringUtil::null, LLVector3d(0.f, 0.f, 0.f), LLVector3d(-1.f, 0.15f, 0.f), SEX_BOTH)); + addEntry(SUBPART_UNDERSHIRT, new SubpartEntry(SUBPART_UNDERSHIRT, "mTorso", "undershirt",LLStringUtil::null, LLVector3d(0.f, 0.f, 0.3f), LLVector3d(-1.f, 0.15f, 0.3f), SEX_BOTH)); + addEntry(SUBPART_UNDERPANTS, new SubpartEntry(SUBPART_UNDERPANTS, "mPelvis", "underpants",LLStringUtil::null, LLVector3d(0.f, 0.f, -0.5f), LLVector3d(-1.6f, 0.15f, -0.5f), SEX_BOTH)); + addEntry(SUBPART_ALPHA, new SubpartEntry(SUBPART_ALPHA, "mPelvis", "alpha",LLStringUtil::null, LLVector3d(0.f, 0.f, 0.1f), LLVector3d(-2.5f, 0.5f, 0.8f), SEX_BOTH)); + addEntry(SUBPART_TATTOO, new SubpartEntry(SUBPART_TATTOO, "mPelvis", "tattoo", LLStringUtil::null, LLVector3d(0.f, 0.f, 0.1f), LLVector3d(-2.5f, 0.5f, 0.8f),SEX_BOTH)); + addEntry(SUBPART_PHYSICS_BREASTS_UPDOWN, new SubpartEntry(SUBPART_PHYSICS_BREASTS_UPDOWN, "mTorso", "physics_breasts_updown", "Breast Bounce", LLVector3d(0.f, 0.f, 0.1f), LLVector3d(-0.8f, 0.15f, 0.38),SEX_FEMALE)); + addEntry(SUBPART_PHYSICS_BREASTS_INOUT, new SubpartEntry(SUBPART_PHYSICS_BREASTS_INOUT, "mTorso", "physics_breasts_inout", "Breast Cleavage", LLVector3d(0.f, 0.f, 0.1f), LLVector3d(-0.8f, 0.15f, 0.38f),SEX_FEMALE)); + addEntry(SUBPART_PHYSICS_BREASTS_LEFTRIGHT, new SubpartEntry(SUBPART_PHYSICS_BREASTS_LEFTRIGHT, "mTorso", "physics_breasts_leftright", "Breast Sway", LLVector3d(0.f, 0.f, 0.1f), LLVector3d(-0.8f, 0.15f, 0.38f),SEX_FEMALE)); + addEntry(SUBPART_PHYSICS_BELLY_UPDOWN, new SubpartEntry(SUBPART_PHYSICS_BELLY_UPDOWN, "mTorso", "physics_belly_updown", "Belly Bounce", LLVector3d(0.f, 0.f, -.05f), LLVector3d(-0.8f, 0.15f, 0.38f),SEX_BOTH)); + addEntry(SUBPART_PHYSICS_BUTT_UPDOWN, new SubpartEntry(SUBPART_PHYSICS_BUTT_UPDOWN, "mTorso", "physics_butt_updown", "Butt Bounce", LLVector3d(0.f, 0.f,-.1f), LLVector3d(0.3f, 0.8f, -0.1f),SEX_BOTH)); + addEntry(SUBPART_PHYSICS_BUTT_LEFTRIGHT, new SubpartEntry(SUBPART_PHYSICS_BUTT_LEFTRIGHT, "mTorso", "physics_butt_leftright", "Butt Sway", LLVector3d(0.f, 0.f,-.1f), LLVector3d(0.3f, 0.8f, -0.1f),SEX_BOTH)); + addEntry(SUBPART_PHYSICS_ADVANCED, new SubpartEntry(SUBPART_PHYSICS_ADVANCED, "mTorso", "physics_advanced", "Advanced Parameters", LLVector3d(0.f, 0.f, 0.1f), LLVector3d(-2.5f, 0.5f, 0.8f),SEX_BOTH)); +} + +LLEditWearableDictionary::SubpartEntry::SubpartEntry(ESubpart part, + const std::string &joint, + const std::string &edit_group, + const std::string &button_name, + const LLVector3d &target_offset, + const LLVector3d &camera_offset, + const ESex &sex) : + LLDictionaryEntry(edit_group), + mSubpart(part), + mTargetJoint(joint), + mEditGroup(edit_group), + mButtonName(button_name), + mTargetOffset(target_offset), + mCameraOffset(camera_offset), + mSex(sex) +{ +} + +LLEditWearableDictionary::ColorSwatchCtrls::ColorSwatchCtrls() +{ + addEntry ( TEX_UPPER_SHIRT, new PickerControlEntry (TEX_UPPER_SHIRT, "Color/Tint" )); + addEntry ( TEX_LOWER_PANTS, new PickerControlEntry (TEX_LOWER_PANTS, "Color/Tint" )); + addEntry ( TEX_LOWER_SHOES, new PickerControlEntry (TEX_LOWER_SHOES, "Color/Tint" )); + addEntry ( TEX_LOWER_SOCKS, new PickerControlEntry (TEX_LOWER_SOCKS, "Color/Tint" )); + addEntry ( TEX_UPPER_JACKET, new PickerControlEntry (TEX_UPPER_JACKET, "Color/Tint" )); + addEntry ( TEX_SKIRT, new PickerControlEntry (TEX_SKIRT, "Color/Tint" )); + addEntry ( TEX_UPPER_GLOVES, new PickerControlEntry (TEX_UPPER_GLOVES, "Color/Tint" )); + addEntry ( TEX_UPPER_UNDERSHIRT, new PickerControlEntry (TEX_UPPER_UNDERSHIRT, "Color/Tint" )); + addEntry ( TEX_LOWER_UNDERPANTS, new PickerControlEntry (TEX_LOWER_UNDERPANTS, "Color/Tint" )); + addEntry ( TEX_HEAD_TATTOO, new PickerControlEntry(TEX_HEAD_TATTOO, "Color/Tint" )); +} + +LLEditWearableDictionary::TextureCtrls::TextureCtrls() +{ + addEntry ( TEX_HEAD_BODYPAINT, new PickerControlEntry (TEX_HEAD_BODYPAINT, "Head Tattoos", LLUUID::null, TRUE )); + addEntry ( TEX_UPPER_BODYPAINT, new PickerControlEntry (TEX_UPPER_BODYPAINT, "Upper Tattoos", LLUUID::null, TRUE )); + addEntry ( TEX_LOWER_BODYPAINT, new PickerControlEntry (TEX_LOWER_BODYPAINT, "Lower Tattoos", LLUUID::null, TRUE )); + addEntry ( TEX_HAIR, new PickerControlEntry (TEX_HAIR, "Texture", LLUUID( gSavedSettings.getString( "UIImgDefaultHairUUID" ) ), FALSE )); + addEntry ( TEX_EYES_IRIS, new PickerControlEntry (TEX_EYES_IRIS, "Iris", LLUUID( gSavedSettings.getString( "UIImgDefaultEyesUUID" ) ), FALSE )); + addEntry ( TEX_UPPER_SHIRT, new PickerControlEntry (TEX_UPPER_SHIRT, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultShirtUUID" ) ), FALSE )); + addEntry ( TEX_LOWER_PANTS, new PickerControlEntry (TEX_LOWER_PANTS, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultPantsUUID" ) ), FALSE )); + addEntry ( TEX_LOWER_SHOES, new PickerControlEntry (TEX_LOWER_SHOES, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultShoesUUID" ) ), FALSE )); + addEntry ( TEX_LOWER_SOCKS, new PickerControlEntry (TEX_LOWER_SOCKS, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultSocksUUID" ) ), FALSE )); + addEntry ( TEX_UPPER_JACKET, new PickerControlEntry (TEX_UPPER_JACKET, "Upper Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultJacketUUID" ) ), FALSE )); + addEntry ( TEX_LOWER_JACKET, new PickerControlEntry (TEX_LOWER_JACKET, "Lower Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultJacketUUID" ) ), FALSE )); + addEntry ( TEX_SKIRT, new PickerControlEntry (TEX_SKIRT, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultSkirtUUID" ) ), FALSE )); + addEntry ( TEX_UPPER_GLOVES, new PickerControlEntry (TEX_UPPER_GLOVES, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultGlovesUUID" ) ), FALSE )); + addEntry ( TEX_UPPER_UNDERSHIRT, new PickerControlEntry (TEX_UPPER_UNDERSHIRT, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultUnderwearUUID" ) ), FALSE )); + addEntry ( TEX_LOWER_UNDERPANTS, new PickerControlEntry (TEX_LOWER_UNDERPANTS, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultUnderwearUUID" ) ), FALSE )); + addEntry ( TEX_LOWER_ALPHA, new PickerControlEntry (TEX_LOWER_ALPHA, "Lower Alpha", LLUUID( gSavedSettings.getString( "UIImgDefaultAlphaUUID" ) ), TRUE, "lower alpha texture invisible" )); + addEntry ( TEX_UPPER_ALPHA, new PickerControlEntry (TEX_UPPER_ALPHA, "Upper Alpha", LLUUID( gSavedSettings.getString( "UIImgDefaultAlphaUUID" ) ), TRUE, "upper alpha texture invisible" )); + addEntry ( TEX_HEAD_ALPHA, new PickerControlEntry (TEX_HEAD_ALPHA, "Head Alpha", LLUUID( gSavedSettings.getString( "UIImgDefaultAlphaUUID" ) ), TRUE, "head alpha texture invisible" )); + addEntry ( TEX_EYES_ALPHA, new PickerControlEntry (TEX_EYES_ALPHA, "Eye Alpha", LLUUID( gSavedSettings.getString( "UIImgDefaultAlphaUUID" ) ), TRUE, "eye alpha texture invisible" )); + addEntry ( TEX_HAIR_ALPHA, new PickerControlEntry (TEX_HAIR_ALPHA, "Hair Alpha", LLUUID( gSavedSettings.getString( "UIImgDefaultAlphaUUID" ) ), TRUE, "hair alpha texture invisible" )); + addEntry ( TEX_LOWER_TATTOO, new PickerControlEntry (TEX_LOWER_TATTOO, "Lower Tattoo", LLUUID::null, TRUE )); + addEntry ( TEX_UPPER_TATTOO, new PickerControlEntry (TEX_UPPER_TATTOO, "Upper Tattoo", LLUUID::null, TRUE )); + addEntry ( TEX_HEAD_TATTOO, new PickerControlEntry (TEX_HEAD_TATTOO, "Head Tattoo", LLUUID::null, TRUE )); +} + +LLEditWearableDictionary::PickerControlEntry::PickerControlEntry(ETextureIndex tex_index, + const std::string name, + const LLUUID default_image_id, + const bool allow_no_texture, + const std::string checkbox_name) : + LLDictionaryEntry(name), + mTextureIndex(tex_index), + mControlName(name), + mDefaultImageId(default_image_id), + mAllowNoTexture(allow_no_texture), + mCheckboxName(checkbox_name) +{ +} + +// Helper functions. +static const texture_vec_t null_texture_vec; + +// Specializations of this template function return a vector of texture indexes of particular control type +// (i.e. LLColorSwatchCtrl or LLTextureCtrl) which are contained in given WearableEntry. +template +const texture_vec_t& +get_pickers_indexes(const LLEditWearableDictionary::WearableEntry *wearable_entry) { return null_texture_vec; } + +// Specializations of this template function return picker control entry for particular control type. +template +const LLEditWearableDictionary::PickerControlEntry* +get_picker_entry (const ETextureIndex index) { return NULL; } + +typedef boost::function function_t; + +typedef struct PickerControlEntryNamePredicate +{ + PickerControlEntryNamePredicate(const std::string name) : mName (name) {}; + bool operator()(const LLEditWearableDictionary::PickerControlEntry* entry) const + { + return (entry && entry->mName == mName); + } +private: + const std::string mName; +} PickerControlEntryNamePredicate; + +// A full specialization of get_pickers_indexes for LLColorSwatchCtrl +template <> +const texture_vec_t& +get_pickers_indexes (const LLEditWearableDictionary::WearableEntry *wearable_entry) +{ + if (!wearable_entry) + { + llwarns << "could not get LLColorSwatchCtrl indexes for null wearable entry." << llendl; + return null_texture_vec; + } + return wearable_entry->mColorSwatchCtrls; +} + +// A full specialization of get_pickers_indexes for LLTextureCtrl +template <> +const texture_vec_t& +get_pickers_indexes (const LLEditWearableDictionary::WearableEntry *wearable_entry) +{ + if (!wearable_entry) + { + llwarns << "could not get LLTextureCtrl indexes for null wearable entry." << llendl; + return null_texture_vec; + } + return wearable_entry->mTextureCtrls; +} + +// A full specialization of get_picker_entry for LLColorSwatchCtrl +template <> +const LLEditWearableDictionary::PickerControlEntry* +get_picker_entry (const ETextureIndex index) +{ + return LLEditWearableDictionary::getInstance()->getColorSwatch(index); +} + +// A full specialization of get_picker_entry for LLTextureCtrl +template <> +const LLEditWearableDictionary::PickerControlEntry* +get_picker_entry (const ETextureIndex index) +{ + return LLEditWearableDictionary::getInstance()->getTexturePicker(index); +} + +template +const LLEditWearableDictionary::PickerControlEntry* +find_picker_ctrl_entry_if(LLWearableType::EType type, const Predicate pred) +{ + const LLEditWearableDictionary::WearableEntry *wearable_entry + = LLEditWearableDictionary::getInstance()->getWearable(type); + if (!wearable_entry) + { + llwarns << "could not get wearable dictionary entry for wearable of type: " << type << llendl; + return NULL; + } + const texture_vec_t& indexes = get_pickers_indexes(wearable_entry); + for (texture_vec_t::const_iterator + iter = indexes.begin(), + iter_end = indexes.end(); + iter != iter_end; ++iter) + { + const ETextureIndex te = *iter; + const LLEditWearableDictionary::PickerControlEntry* entry + = get_picker_entry(te); + if (!entry) + { + llwarns << "could not get picker dictionary entry (" << te << ") for wearable of type: " << type << llendl; + continue; + } + if (pred(entry)) + { + return entry; + } + } + return NULL; +} + +template +void +for_each_picker_ctrl_entry(LLPanel* panel, LLWearableType::EType type, function_t fun) +{ + if (!panel) + { + llwarns << "the panel wasn't passed for wearable of type: " << type << llendl; + return; + } + const LLEditWearableDictionary::WearableEntry *wearable_entry + = LLEditWearableDictionary::getInstance()->getWearable(type); + if (!wearable_entry) + { + llwarns << "could not get wearable dictionary entry for wearable of type: " << type << llendl; + return; + } + const texture_vec_t& indexes = get_pickers_indexes(wearable_entry); + for (texture_vec_t::const_iterator + iter = indexes.begin(), + iter_end = indexes.end(); + iter != iter_end; ++iter) + { + const ETextureIndex te = *iter; + const LLEditWearableDictionary::PickerControlEntry* entry + = get_picker_entry(te); + if (!entry) + { + llwarns << "could not get picker dictionary entry (" << te << ") for wearable of type: " << type << llendl; + continue; + } + fun (panel, entry); + } +} + +// The helper functions for pickers management +static void init_color_swatch_ctrl(LLPanelEditWearable* self, LLPanel* panel, const LLEditWearableDictionary::PickerControlEntry* entry) +{ + LLColorSwatchCtrl* color_swatch_ctrl = panel->getChild(entry->mControlName); + if (color_swatch_ctrl) + { + color_swatch_ctrl->setCommitCallback(boost::bind(&LLPanelEditWearable::onColorSwatchCommit, self, _1)); + // Can't get the color from the wearable here, since the wearable may not be set when this is called. + color_swatch_ctrl->setOriginal(LLColor4::white); + } +} + +static void init_texture_ctrl(LLPanelEditWearable* self, LLPanel* panel, const LLEditWearableDictionary::PickerControlEntry* entry) +{ + LLTextureCtrl* texture_ctrl = panel->getChild(entry->mControlName); + if (texture_ctrl) + { + texture_ctrl->setCommitCallback(boost::bind(&LLPanelEditWearable::onTexturePickerCommit, self, _1)); + texture_ctrl->setDefaultImageAssetID(entry->mDefaultImageId); + texture_ctrl->setAllowNoTexture(entry->mAllowNoTexture); + // Don't allow (no copy) or (notransfer) textures to be selected. + texture_ctrl->setImmediateFilterPermMask(PERM_NONE);//PERM_COPY | PERM_TRANSFER); + texture_ctrl->setNonImmediateFilterPermMask(PERM_NONE);//PERM_COPY | PERM_TRANSFER); + } + if(!entry->mCheckboxName.empty()) + { + LLCheckBoxCtrl* checkbox_ctrl = panel->getChild(entry->mCheckboxName, true, false); + if(checkbox_ctrl) + { + checkbox_ctrl->setCommitCallback(LLPanelEditWearable::onInvisibilityCommit, self); + self->initPreviousTextureListEntry(entry->mTextureIndex); + } + } +} + +static void update_color_swatch_ctrl(LLPanelEditWearable* self, LLPanel* panel, const LLEditWearableDictionary::PickerControlEntry* entry) +{ + LLColorSwatchCtrl* color_swatch_ctrl = panel->getChild(entry->mControlName); + if (color_swatch_ctrl) + { + color_swatch_ctrl->set(self->getWearable()->getClothesColor(entry->mTextureIndex)); + } +} + +static void update_texture_ctrl(LLPanelEditWearable* self, LLPanel* panel, const LLEditWearableDictionary::PickerControlEntry* entry) +{ + LLTextureCtrl* texture_ctrl = panel->getChild(entry->mControlName); + if (texture_ctrl) + { + LLUUID new_id; + LLLocalTextureObject *lto = self->getWearable()->getLocalTextureObject(entry->mTextureIndex); + if( lto && (lto->getID() != IMG_DEFAULT_AVATAR) ) + { + new_id = lto->getID(); + } + else + { + new_id = LLUUID::null; + } + LLUUID old_id = texture_ctrl->getImageAssetID(); + if (old_id != new_id) + { + // texture has changed, close the floater to avoid DEV-22461 + texture_ctrl->closeFloater(); + } + texture_ctrl->setImageAssetID(new_id); + } +} + +static void set_enabled_color_swatch_ctrl(bool enabled, LLPanel* panel, const LLEditWearableDictionary::PickerControlEntry* entry) +{ + LLColorSwatchCtrl* color_swatch_ctrl = panel->getChild(entry->mControlName); + if (color_swatch_ctrl) + { + color_swatch_ctrl->setEnabled(enabled); + color_swatch_ctrl->setVisible(enabled); + } +} + +static void set_enabled_texture_ctrl(bool enabled, LLPanel* panel, const LLEditWearableDictionary::PickerControlEntry* entry) +{ + LLTextureCtrl* texture_ctrl = panel->getChild(entry->mControlName); + if (texture_ctrl) + { + texture_ctrl->setEnabled(enabled); + texture_ctrl->setVisible(enabled); + } +} + +static void set_enabled_invisibility_ctrl(bool enabled, LLPanelEditWearable* self, LLPanel* panel, const LLEditWearableDictionary::PickerControlEntry* entry) +{ + if(!entry->mCheckboxName.empty()) + { + LLCheckBoxCtrl* checkbox_ctrl = panel->getChild(entry->mCheckboxName, true, false); + if(checkbox_ctrl) + { + checkbox_ctrl->setEnabled(enabled); + checkbox_ctrl->setVisible(enabled); + checkbox_ctrl->set(!gAgentAvatarp->isTextureVisible(entry->mTextureIndex, self->getWearable())); + } + } +} + +class LLWearableSaveAsDialog : public LLModalDialog +{ +private: + std::string mItemName; + void (*mCommitCallback)(LLWearableSaveAsDialog*,void*); + void* mCallbackUserData; + +public: + LLWearableSaveAsDialog( const std::string& desc, void(*commit_cb)(LLWearableSaveAsDialog*,void*), void* userdata ) + : LLModalDialog( LLStringUtil::null, 240, 100 ), + mCommitCallback( commit_cb ), + mCallbackUserData( userdata ) + { + LLUICtrlFactory::getInstance()->buildFloater(this, "floater_wearable_save_as.xml"); + + childSetAction("Save", LLWearableSaveAsDialog::onSave, this ); + childSetAction("Cancel", LLWearableSaveAsDialog::onCancel, this ); + + childSetTextArg("name ed", "[DESC]", desc); + } + + virtual void startModal() + { + LLModalDialog::startModal(); + LLLineEditor* edit = getChild("name ed"); + if (!edit) return; + edit->setFocus(TRUE); + edit->selectAll(); + } + + const std::string& getItemName() { return mItemName; } + + static void onSave( void* userdata ) + { + LLWearableSaveAsDialog* self = (LLWearableSaveAsDialog*) userdata; + self->mItemName = self->childGetValue("name ed").asString(); + LLStringUtil::trim(self->mItemName); + if( !self->mItemName.empty() ) + { + if( self->mCommitCallback ) + { + self->mCommitCallback( self, self->mCallbackUserData ); + } + self->close(); // destroys this object + } + } + + static void onCancel( void* userdata ) + { + LLWearableSaveAsDialog* self = (LLWearableSaveAsDialog*) userdata; + self->close(); // destroys this object + } +}; + +LLPanelEditWearable::LLPanelEditWearable( LLWearableType::EType type ) + + : LLPanel( LLWearableType::getTypeLabel( type ) ), + mType( type ) +{ +} +LLPanelEditWearable::~LLPanelEditWearable() +{ +} + +BOOL LLPanelEditWearable::postBuild() +{ + std::string icon_name = LLInventoryIcon::getIconName(LLWearableType::getAssetType( mType ),LLInventoryType::IT_WEARABLE,mType,FALSE); + + childSetValue("icon", icon_name); + + childSetAction("Create New", LLPanelEditWearable::onBtnCreateNew, this ); + + // If PG, can't take off underclothing or shirt + mCanTakeOff = + LLWearableType::getAssetType( mType ) == LLAssetType::AT_CLOTHING && + !( gAgent.isTeen() && (mType == LLWearableType::WT_UNDERSHIRT || mType == LLWearableType::WT_UNDERPANTS) ); + childSetVisible("Take Off", mCanTakeOff); + childSetAction("Take Off", LLPanelEditWearable::onBtnTakeOff, this ); + + LLUICtrl* sex_radio = getChild("sex radio", true, false); + if(sex_radio) + { + sex_radio->setCommitCallback(boost::bind(&LLPanelEditWearable::onCommitSexChange,this)); + } + + childSetAction("Save", &LLPanelEditWearable::onBtnSave, (void*)this ); + + childSetAction("Save As", &LLPanelEditWearable::onBtnSaveAs, (void*)this ); + + childSetAction("Revert", &LLPanelEditWearable::onRevertButtonClicked, (void*)this ); + + { + const LLEditWearableDictionary::WearableEntry *wearable_entry = LLEditWearableDictionary::getInstance()->getWearable(mType); + if (!wearable_entry) + { + llwarns << "could not get wearable dictionary entry for wearable of type: " << mType << llendl; + } + U8 num_subparts = wearable_entry->mSubparts.size(); + + for (U8 index = 0; index < num_subparts; ++index) + { + // dive into data structures to get the panel we need + ESubpart subpart_e = wearable_entry->mSubparts[index]; + const LLEditWearableDictionary::SubpartEntry *subpart_entry = LLEditWearableDictionary::getInstance()->getSubpart(subpart_e); + + if (!subpart_entry) + { + llwarns << "could not get wearable subpart dictionary entry for subpart: " << subpart_e << llendl; + continue; + } + + if(!subpart_entry->mButtonName.empty()) + { + llinfos << "Finding button " << subpart_entry->mButtonName << llendl; + llassert_always(getChild(subpart_entry->mButtonName,true,false)); + childSetAction(subpart_entry->mButtonName, &LLPanelEditWearable::onBtnSubpart, (void*)subpart_e); + } + } + // initialize texture and color picker controls + for_each_picker_ctrl_entry (this, mType, boost::bind(init_color_swatch_ctrl, this, _1, _2)); + for_each_picker_ctrl_entry (this, mType, boost::bind(init_texture_ctrl, this, _1, _2)); + } + return TRUE; +} + +BOOL LLPanelEditWearable::isDirty() const +{ + LLWearable* wearable = getWearable(); + return wearable && wearable->isDirty(); +} + +void LLPanelEditWearable::draw() +{ + if( gFloaterCustomize->isMinimized() ) + { + return; + } + + LLVOAvatar* avatar = gAgentAvatarp; + if( !avatar ) + { + return; + } + + LLWearable* wearable = gAgentWearables.getWearable( mType, 0 ); // TODO: MULTI-WEARABLE + BOOL has_wearable = (wearable != NULL ); + BOOL is_dirty = isDirty(); + BOOL is_modifiable = FALSE; + BOOL is_copyable = FALSE; + BOOL is_complete = FALSE; + LLViewerInventoryItem* item; + item = (LLViewerInventoryItem*)gAgentWearables.getWearableInventoryItem(mType, 0); // TODO: MULTI-WEARABLE + if(item) + { + const LLPermissions& perm = item->getPermissions(); + is_modifiable = perm.allowModifyBy(gAgent.getID(), gAgent.getGroupID()); + is_copyable = perm.allowCopyBy(gAgent.getID(), gAgent.getGroupID()); + is_complete = item->isComplete(); + } + + childSetEnabled("Save", is_modifiable && is_complete && has_wearable && is_dirty); + childSetEnabled("Save As", is_copyable && is_complete && has_wearable); + childSetEnabled("Revert", has_wearable && is_dirty ); + childSetEnabled("Take Off", has_wearable ); + childSetVisible("Take Off", mCanTakeOff && has_wearable ); + childSetVisible("Create New", !has_wearable ); + + childSetVisible("not worn instructions", !has_wearable ); + childSetVisible("no modify instructions", has_wearable && !is_modifiable); + + + const LLEditWearableDictionary::WearableEntry *wearable_entry = LLEditWearableDictionary::getInstance()->getWearable(mType); + if (wearable_entry) + { + U8 num_subparts = wearable_entry->mSubparts.size(); + + for (U8 index = 0; index < num_subparts; ++index) + { + // dive into data structures to get the panel we need + ESubpart subpart_e = wearable_entry->mSubparts[index]; + const LLEditWearableDictionary::SubpartEntry *subpart_entry = LLEditWearableDictionary::getInstance()->getSubpart(subpart_e); + + if (!subpart_entry) + { + llwarns << "could not get wearable subpart dictionary entry for subpart: " << subpart_e << llendl; + continue; + } + + childSetVisible(subpart_entry->mButtonName,has_wearable); + if( has_wearable && is_complete && is_modifiable ) + { + childSetEnabled(subpart_entry->mButtonName, subpart_entry->mSex & avatar->getSex() ); + } + else + { + childSetEnabled(subpart_entry->mButtonName, FALSE ); + } + } + } + + childSetVisible("square", !is_modifiable); + + childSetVisible("title", FALSE); + childSetVisible("title_no_modify", FALSE); + childSetVisible("title_not_worn", FALSE); + childSetVisible("title_loading", FALSE); + + childSetVisible("path", FALSE); + + LLTextBox *av_height = getChild("avheight",FALSE,FALSE); + if(av_height) //Only display this if the element exists + { + // Display the shape's nominal height. + // + // The value for avsize is the best available estimate from + // measuring against prims. + float avsize = avatar->mBodySize.mV[VZ] + .195; + int inches = (int)(avsize / .0254f); + int feet = inches / 12; + inches %= 12; + + std::ostringstream avheight(std::ostringstream::trunc); + avheight << std::fixed << std::setprecision(2) << avsize << " m (" + << feet << "' " << inches << "\")"; + av_height->setVisible(TRUE); + av_height->setTextArg("[AVHEIGHT]",avheight.str()); + } + + if(has_wearable && !is_modifiable) + { + // *TODO:Translate + childSetVisible("title_no_modify", TRUE); + childSetTextArg("title_no_modify", "[DESC]", std::string(LLWearableType::getTypeLabel( mType ))); + + hideTextureControls(); + } + else if(has_wearable && !is_complete) + { + // *TODO:Translate + childSetVisible("title_loading", TRUE); + childSetTextArg("title_loading", "[DESC]", std::string(LLWearableType::getTypeLabel( mType ))); + + std::string path; + const LLUUID& item_id = gAgentWearables.getWearableItemID( wearable->getType(), 0 ); // TODO: MULTI-WEARABLE + append_path(item_id, path); + childSetVisible("path", TRUE); + childSetTextArg("path", "[PATH]", path); + + hideTextureControls(); + } + else if(has_wearable && is_modifiable) + { + childSetVisible("title", TRUE); + childSetTextArg("title", "[DESC]", wearable->getName() ); + + std::string path; + const LLUUID& item_id = gAgentWearables.getWearableItemID( wearable->getType(), 0 ); // TODO: MULTI-WEARABLE + append_path(item_id, path); + childSetVisible("path", TRUE); + childSetTextArg("path", "[PATH]", path); + + for_each_picker_ctrl_entry (this, mType, boost::bind(update_color_swatch_ctrl, this, _1, _2)); + for_each_picker_ctrl_entry (this, mType, boost::bind(update_texture_ctrl, this, _1, _2)); + for_each_picker_ctrl_entry (this, mType, boost::bind(set_enabled_color_swatch_ctrl, is_complete, _1, _2)); + for_each_picker_ctrl_entry (this, mType, boost::bind(set_enabled_texture_ctrl, is_complete, _1, _2)); + for_each_picker_ctrl_entry (this, mType, boost::bind(set_enabled_invisibility_ctrl, is_copyable && is_complete, this, _1, _2)); + } + else + { + // *TODO:Translate + childSetVisible("title_not_worn", TRUE); + childSetTextArg("title_not_worn", "[DESC]", std::string(LLWearableType::getTypeLabel( mType ))); + + hideTextureControls(); + } + + childSetVisible("icon", has_wearable && is_modifiable); + + LLPanel::draw(); +} + +void LLPanelEditWearable::setVisible(BOOL visible) +{ + LLPanel::setVisible( visible ); + if( !visible ) + { + for_each_picker_ctrl_entry (this, mType, boost::bind(set_enabled_color_swatch_ctrl, FALSE, _1, _2)); + } +} + +// static +void LLPanelEditWearable::setWearable(LLWearable* wearable, U32 perm_mask, BOOL is_complete) +{ + if( wearable ) + { + setUIPermissions(perm_mask, is_complete); + if (mType == LLWearableType::WT_ALPHA) + { + initPreviousTextureList(); + } + } +} + +// static +void LLPanelEditWearable::onRevertButtonClicked( void* userdata ) +{ + LLPanelEditWearable* self = (LLPanelEditWearable*) userdata; + gAgentWearables.revertWearable( self->mType, 0 ); // TODO: MULTI-WEARABLE +} + +void LLPanelEditWearable::onBtnSave( void* userdata ) +{ + LLPanelEditWearable* self = (LLPanelEditWearable*) userdata; + gAgentWearables.saveWearable( self->mType, 0 ); // TODO: MULTI-WEARABLE +} + +// static +void LLPanelEditWearable::onBtnSaveAs( void* userdata ) +{ + LLPanelEditWearable* self = (LLPanelEditWearable*) userdata; + LLWearable* wearable = gAgentWearables.getWearable( self->getType(), 0 ); // TODO: MULTI-WEARABLE + if( wearable ) + { + LLWearableSaveAsDialog* save_as_dialog = new LLWearableSaveAsDialog( wearable->getName(), onSaveAsCommit, self ); + save_as_dialog->startModal(); + // LLWearableSaveAsDialog deletes itself. + } +} + +// static +void LLPanelEditWearable::onSaveAsCommit( LLWearableSaveAsDialog* save_as_dialog, void* userdata ) +{ + LLPanelEditWearable* self = (LLPanelEditWearable*) userdata; + LLVOAvatar* avatar = gAgentAvatarp; + if( avatar ) + { + gAgentWearables.saveWearableAs( self->getType(), 0, save_as_dialog->getItemName(), FALSE ); // TODO: MULTI-WEARABLE + } +} + +// static +void LLPanelEditWearable::onCommitSexChange() +{ + if (!isAgentAvatarValid()) return; + + LLWearableType::EType type = mType; // TODO: MULTI-WEARABLE + U32 index = 0; // TODO: MULTI-WEARABLE + + if( !gAgentWearables.isWearableModifiable(type, index)) + { + return; + } + + LLViewerVisualParam* param = static_cast(gAgentAvatarp->getVisualParam( "male" )); + if( !param ) + { + return; + } + + bool is_new_sex_male = (gSavedSettings.getU32("AvatarSex") ? SEX_MALE : SEX_FEMALE) == SEX_MALE; + LLWearable* wearable = gAgentWearables.getWearable(type, index); + if (wearable) + { + wearable->setVisualParamWeight(param->getID(), is_new_sex_male, FALSE); + } + param->setWeight( is_new_sex_male, FALSE ); + + gAgentAvatarp->updateSexDependentLayerSets( FALSE ); + + gAgentAvatarp->updateVisualParams(); + + + //if(!wearable) + //{ + // return; + //} + + + + //wearable->setVisualParamWeight(param->getID(), (new_sex == SEX_MALE), TRUE); + //wearable->writeToAvatar(); + //avatar->updateVisualParams(); + + gFloaterCustomize->clearScrollingPanelList(); + + // Assumes that we're in the "Shape" Panel. + //self->setSubpart( SUBPART_SHAPE_WHOLE ); +} + + +// static +void LLPanelEditWearable::onBtnCreateNew( void* userdata ) +{ + LLPanelEditWearable* self = (LLPanelEditWearable*) userdata; + LLSD payload; + payload["wearable_type"] = (S32)self->getType(); + LLNotificationsUtil::add("AutoWearNewClothing", LLSD(), payload, &onSelectAutoWearOption); +} + +bool LLPanelEditWearable::onSelectAutoWearOption(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotification::getSelectedOption(notification, response); + LLVOAvatar* avatar = gAgentAvatarp; + if(avatar) + { + // Create a new wearable in the default folder for the wearable's asset type. + LLWearable* wearable = LLWearableList::instance().createNewWearable( (LLWearableType::EType)notification["payload"]["wearable_type"].asInteger() ); + LLAssetType::EType asset_type = wearable->getAssetType(); + + LLUUID folder_id; + // regular UI, items get created in normal folder + folder_id = gInventory.findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(asset_type)); + + // Only auto wear the new item if the AutoWearNewClothing checkbox is selected. + LLPointer cb = option == 0 ? + new WearOnAvatarCallback : NULL; + create_inventory_item(gAgent.getID(), gAgent.getSessionID(), + folder_id, wearable->getTransactionID(), wearable->getName(), wearable->getDescription(), + asset_type, LLInventoryType::IT_WEARABLE, wearable->getType(), + wearable->getPermissions().getMaskNextOwner(), cb); + } + return false; +} + + +bool LLPanelEditWearable::textureIsInvisible(ETextureIndex te) +{ + const LLWearable* wearable = gAgentWearables.getWearable(mType, 0); // TODO: MULTI-WEARABLE + if(wearable) + { + const LLLocalTextureObject* lto = wearable->getLocalTextureObject(te); + return (lto && lto->getID() == IMG_INVISIBLE); + } + return false; +} + +LLWearable* LLPanelEditWearable::getWearable() const +{ + return gAgentWearables.getWearable(mType, 0); // TODO: MULTI-WEARABLE +} + + +void LLPanelEditWearable::onTexturePickerCommit(const LLUICtrl* ctrl) +{ + const LLTextureCtrl* texture_ctrl = dynamic_cast(ctrl); + if (!texture_ctrl) + { + llwarns << "got commit signal from not LLTextureCtrl." << llendl; + return; + } + + if (getWearable()) + { + LLWearableType::EType type = getWearable()->getType(); + const PickerControlEntryNamePredicate name_pred(texture_ctrl->getName()); + const LLEditWearableDictionary::PickerControlEntry* entry + = find_picker_ctrl_entry_if(type, name_pred); + if (entry) + { + // Set the new version + LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTexture(texture_ctrl->getImageAssetID()); + if( image->getID() == IMG_DEFAULT ) + { + image = LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT_AVATAR); + } + if (getWearable()) + { + U32 index = gAgentWearables.getWearableIndex(getWearable()); + gAgentAvatarp->setLocalTexture(entry->mTextureIndex, image, FALSE, index); + LLVisualParamHint::requestHintUpdates(); + gAgentAvatarp->wearableUpdated(type, FALSE); + } + if (mType == LLWearableType::WT_ALPHA && image->getID() != IMG_INVISIBLE) + { + mPreviousTextureList[entry->mTextureIndex] = image->getID(); + } + } + else + { + llwarns << "could not get texture picker dictionary entry for wearable of type: " << type << llendl; + } + } +} + +void LLPanelEditWearable::onColorSwatchCommit(const LLUICtrl* base_ctrl ) +{ + LLColorSwatchCtrl* ctrl = (LLColorSwatchCtrl*) base_ctrl; + + if (getWearable()) + { + LLWearableType::EType type = getWearable()->getType(); + const PickerControlEntryNamePredicate name_pred(ctrl->getName()); + const LLEditWearableDictionary::PickerControlEntry* entry + = find_picker_ctrl_entry_if(type, name_pred); + if (entry) + { + const LLColor4& old_color = getWearable()->getClothesColor(entry->mTextureIndex); + const LLColor4& new_color = LLColor4(ctrl->getValue()); + if( old_color != new_color ) + { + getWearable()->setClothesColor(entry->mTextureIndex, new_color, TRUE); + LLVisualParamHint::requestHintUpdates(); + gAgentAvatarp->wearableUpdated(getWearable()->getType(), FALSE); + } + } + else + { + llwarns << "could not get color swatch dictionary entry for wearable of type: " << type << llendl; + } + } +} + +ESubpart LLPanelEditWearable::getDefaultSubpart() +{ + switch( mType ) + { + case LLWearableType::WT_SHAPE: return SUBPART_SHAPE_WHOLE; + case LLWearableType::WT_SKIN: return SUBPART_SKIN_COLOR; + case LLWearableType::WT_HAIR: return SUBPART_HAIR_COLOR; + case LLWearableType::WT_EYES: return SUBPART_EYES; + case LLWearableType::WT_SHIRT: return SUBPART_SHIRT; + case LLWearableType::WT_PANTS: return SUBPART_PANTS; + case LLWearableType::WT_SHOES: return SUBPART_SHOES; + case LLWearableType::WT_SOCKS: return SUBPART_SOCKS; + case LLWearableType::WT_JACKET: return SUBPART_JACKET; + case LLWearableType::WT_GLOVES: return SUBPART_GLOVES; + case LLWearableType::WT_UNDERSHIRT: return SUBPART_UNDERSHIRT; + case LLWearableType::WT_UNDERPANTS: return SUBPART_UNDERPANTS; + case LLWearableType::WT_SKIRT: return SUBPART_SKIRT; + case LLWearableType::WT_ALPHA: return SUBPART_ALPHA; + case LLWearableType::WT_TATTOO: return SUBPART_TATTOO; + case LLWearableType::WT_PHYSICS: return SUBPART_PHYSICS_BELLY_UPDOWN; + + default: llassert(0); return SUBPART_SHAPE_WHOLE; + } +} + + + + +void LLPanelEditWearable::hideTextureControls() +{ + for_each_picker_ctrl_entry (this, mType, boost::bind(set_enabled_texture_ctrl, FALSE, _1, _2)); + for_each_picker_ctrl_entry (this, mType, boost::bind(set_enabled_color_swatch_ctrl, FALSE, _1, _2)); + for_each_picker_ctrl_entry (this, mType, boost::bind(set_enabled_invisibility_ctrl, FALSE, this, _1, _2)); +} + + +void LLPanelEditWearable::switchToDefaultSubpart() +{ + setSubpart( getDefaultSubpart() ); +} + + + +void LLPanelEditWearable::setUIPermissions(U32 perm_mask, BOOL is_complete) +{ + BOOL is_copyable = (perm_mask & PERM_COPY) ? TRUE : FALSE; + BOOL is_modifiable = (perm_mask & PERM_MODIFY) ? TRUE : FALSE; + + childSetEnabled("Save", is_modifiable && is_complete); + childSetEnabled("Save As", is_copyable && is_complete); + childSetEnabled("sex radio", is_modifiable && is_complete); + for_each_picker_ctrl_entry (this, mType, boost::bind(set_enabled_texture_ctrl, is_copyable && is_modifiable && is_complete, _1, _2)); + for_each_picker_ctrl_entry (this, mType, boost::bind(set_enabled_color_swatch_ctrl, is_modifiable && is_complete, _1, _2)); + for_each_picker_ctrl_entry (this, mType, boost::bind(set_enabled_invisibility_ctrl, is_copyable && is_modifiable && is_complete, this, _1, _2)); +} + +// static +void LLPanelEditWearable::onBtnSubpart(void* userdata) +{ + LLFloaterCustomize* floater_customize = gFloaterCustomize; + if (!floater_customize) return; + LLPanelEditWearable* self = floater_customize->getCurrentWearablePanel(); + if (!self) return; + ESubpart subpart = (ESubpart) (intptr_t)userdata; + self->setSubpart( subpart ); +} + +void LLPanelEditWearable::setSubpart( ESubpart subpart ) +{ + mCurrentSubpart = subpart; + + const LLEditWearableDictionary::WearableEntry *wearable_entry = LLEditWearableDictionary::getInstance()->getWearable(mType); + if (wearable_entry) + { + U8 num_subparts = wearable_entry->mSubparts.size(); + + for (U8 index = 0; index < num_subparts; ++index) + { + // dive into data structures to get the panel we need + ESubpart subpart_e = wearable_entry->mSubparts[index]; + const LLEditWearableDictionary::SubpartEntry *subpart_entry = LLEditWearableDictionary::getInstance()->getSubpart(subpart_e); + + if (subpart_entry) + { + LLButton* btn = getChild(subpart_entry->mButtonName); + { + btn->setToggleState( subpart == subpart_e ); + } + } + } + } + + const LLEditWearableDictionary::SubpartEntry *subpart_entry = LLEditWearableDictionary::getInstance()->getSubpart(subpart); + if( subpart_entry ) + { + // Update the thumbnails we display + LLFloaterCustomize::param_map sorted_params; + LLVOAvatar* avatar = gAgentAvatarp; + ESex avatar_sex = avatar->getSex(); + LLViewerInventoryItem* item; + item = (LLViewerInventoryItem*)gAgentWearables.getWearableInventoryItem(mType,0); // TODO: MULTI-WEARABLE + U32 perm_mask = 0x0; + BOOL is_complete = FALSE; + bool can_export = false; + bool can_import = false; + if(item) + { + perm_mask = item->getPermissions().getMaskOwner(); + is_complete = item->isComplete(); + + if (subpart <= 18) // body parts only + { + can_import = true; + + if (is_complete && + gAgent.getID() == item->getPermissions().getOwner() && + gAgent.getID() == item->getPermissions().getCreator() && + (PERM_ITEM_UNRESTRICTED & + perm_mask) == PERM_ITEM_UNRESTRICTED) + { + can_export = true; + } + } + } + setUIPermissions(perm_mask, is_complete); + BOOL editable = ((perm_mask & PERM_MODIFY) && is_complete) ? TRUE : FALSE; + + for(LLViewerVisualParam* param = (LLViewerVisualParam *)avatar->getFirstVisualParam(); + param; + param = (LLViewerVisualParam *)avatar->getNextVisualParam()) + { + if (param->getID() == -1 + || !param->isTweakable() + || param->getEditGroup() != subpart_entry->mEditGroup + || !(param->getSex() & avatar_sex)) + { + continue; + } + + // negative getDisplayOrder() to make lowest order the highest priority + LLFloaterCustomize::param_map::value_type vt(-param->getDisplayOrder(), LLFloaterCustomize::editable_param(editable, param)); + llassert( sorted_params.find(-param->getDisplayOrder()) == sorted_params.end() ); // Check for duplicates + sorted_params.insert(vt); + } + gFloaterCustomize->generateVisualParamHints(NULL, sorted_params, mType != LLWearableType::WT_PHYSICS); + gFloaterCustomize->updateScrollingPanelUI(); + gFloaterCustomize->childSetEnabled("Export", can_export); + gFloaterCustomize->childSetEnabled("Import", can_import); + + // Update the camera + gMorphView->setCameraTargetJoint( gAgentAvatarp->getJoint( subpart_entry->mTargetJoint ) ); + gMorphView->setCameraTargetOffset( subpart_entry->mTargetOffset ); + gMorphView->setCameraOffset( subpart_entry->mCameraOffset ); + gMorphView->setCameraDistToDefault(); + if (gSavedSettings.getBOOL("AppearanceCameraMovement")) + { + gMorphView->updateCamera(); + } + } +} + +// static +void LLPanelEditWearable::onBtnTakeOff( void* userdata ) +{ + LLPanelEditWearable* self = (LLPanelEditWearable*) userdata; + + LLWearable* wearable = gAgentWearables.getWearable( self->mType, 0 ); // TODO: MULTI-WEARABLE + if( !wearable ) + { + return; + } + + gAgentWearables.removeWearable( self->mType, false, 0 ); // TODO: MULTI-WEARABLE +} + +// static +void LLPanelEditWearable::onInvisibilityCommit(LLUICtrl* ctrl, void* userdata) +{ + LLPanelEditWearable* self = (LLPanelEditWearable*) userdata; + LLCheckBoxCtrl* checkbox_ctrl = (LLCheckBoxCtrl*) ctrl; + if (!gAgentAvatarp) + { + return; + } + + const LLEditWearableDictionary::WearableEntry *wearable_entry = LLEditWearableDictionary::getInstance()->getWearable(self->mType); + if (wearable_entry) + { + U8 num_textures = wearable_entry->mTextureCtrls.size(); + + for (U8 index = 0; index < num_textures; ++index) + { + // dive into data structures to get the panel we need + ETextureIndex texindex = wearable_entry->mTextureCtrls[index]; + + const LLEditWearableDictionary::PickerControlEntry *tex_ctrl = LLEditWearableDictionary::getInstance()->getTexturePicker(texindex); + + if (tex_ctrl && tex_ctrl->mCheckboxName == checkbox_ctrl->getName()) + { + bool new_invis_state = checkbox_ctrl->get(); + if (new_invis_state) + { + LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTexture(IMG_INVISIBLE); + + LLWearable* wearable = gAgentWearables.getWearable(self->mType,0); // TODO: MULTI-WEARABLE + const LLLocalTextureObject* lto = wearable ? wearable->getLocalTextureObject(texindex) : NULL; + + if(lto) + { + self->mPreviousTextureList[(S32)texindex] = lto->getID(); + } + if(wearable) + { + LLLocalTextureObject new_lto(image, IMG_INVISIBLE); + wearable->setLocalTextureObject(texindex, new_lto); + wearable->writeToAvatar(); + gAgentAvatarp->wearableUpdated(self->mType, FALSE); + } + + } + else + { + // Try to restore previous texture, if any. + LLUUID prev_id = self->mPreviousTextureList[(S32)texindex]; + if (prev_id.isNull() || (prev_id == IMG_INVISIBLE)) + { + prev_id = LLUUID(gSavedSettings.getString("UIImgDefaultAlphaUUID")); + } + if (prev_id.notNull()) + { + LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTexture(prev_id); + LLWearable* wearable = gAgentWearables.getWearable(self->mType,0); // TODO: MULTI-WEARABLE + if(wearable) + { + LLLocalTextureObject new_lto(image, prev_id); + wearable->setLocalTextureObject(texindex, new_lto); + wearable->writeToAvatar(); + gAgentAvatarp->wearableUpdated(self->mType, FALSE); + } + } + } + } + } + } +} + +void LLPanelEditWearable::initPreviousTextureList() +{ + initPreviousTextureListEntry(TEX_LOWER_ALPHA); + initPreviousTextureListEntry(TEX_UPPER_ALPHA); + initPreviousTextureListEntry(TEX_HEAD_ALPHA); + initPreviousTextureListEntry(TEX_EYES_ALPHA); + initPreviousTextureListEntry(TEX_LOWER_ALPHA); +} +void LLPanelEditWearable::initPreviousTextureListEntry(ETextureIndex te) +{ + if(!getWearable()) + return; + LLLocalTextureObject *lto = getWearable()->getLocalTextureObject(te); + if (lto) + { + mPreviousTextureList[te] = lto->getID(); + } +} diff --git a/indra/newview/llpaneleditwearable.h b/indra/newview/llpaneleditwearable.h new file mode 100644 index 000000000..808296211 --- /dev/null +++ b/indra/newview/llpaneleditwearable.h @@ -0,0 +1,114 @@ +/** + * @file llpaneleditwearable.h + * @brief A LLPanel dedicated to the editing of wearables. + * + * $LicenseInfo:firstyear=2009&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$ + */ + +#ifndef LL_LLPANELEDITWEARABLE_H +#define LL_LLPANELEDITWEARABLE_H + +#include "llpanel.h" +#include "llscrollingpanellist.h" +#include "llmodaldialog.h" +#include "llvoavatardefines.h" +#include "llwearabletype.h" + +class LLAccordionCtrl; +class LLCheckBoxCtrl; +class LLWearable; +class LLTextBox; +class LLViewerInventoryItem; +class LLViewerVisualParam; +class LLVisualParamHint; +class LLViewerJointMesh; +class LLAccordionCtrlTab; +class LLJoint; +class LLLineEditor; +class LLSubpart; +class LLWearableSaveAsDialog; + +enum ESubpart; +using namespace LLVOAvatarDefines; + +class LLPanelEditWearable : public LLPanel +{ +public: + LLPanelEditWearable( LLWearableType::EType type ); + virtual ~LLPanelEditWearable(); + + virtual BOOL postBuild(); + virtual void draw(); + virtual BOOL isDirty() const; // LLUICtrl + + void addTextureDropTarget( ETextureIndex te, const std::string& name, const LLUUID& default_image_id, BOOL allow_no_texture ); + void addInvisibilityCheckbox(ETextureIndex te, const std::string& name); + + const std::string& getLabel() { return LLWearableType::getTypeLabel( mType ); } + LLWearableType::EType getType() const{ return mType; } + LLWearable* getWearable() const; + + ESubpart getDefaultSubpart(); + void setSubpart( ESubpart subpart ); + void switchToDefaultSubpart(); + + void setWearable(LLWearable* wearable, U32 perm_mask, BOOL is_complete); + + void setUIPermissions(U32 perm_mask, BOOL is_complete); + + void hideTextureControls(); + bool textureIsInvisible(ETextureIndex te); + void initPreviousTextureList(); + void initPreviousTextureListEntry(ETextureIndex te); + + static void onRevertButtonClicked( void* userdata ); + void onCommitSexChange(); + + virtual void setVisible( BOOL visible ); + + // Callbacks + static void onBtnSubpart( void* userdata ); + static void onBtnTakeOff( void* userdata ); + static void onBtnSave( void* userdata ); + + static void onBtnSaveAs( void* userdata ); + static void onSaveAsCommit( LLWearableSaveAsDialog* save_as_dialog, void* userdata ); + + static void onBtnTakeOffDialog( S32 option, void* userdata ); + static void onBtnCreateNew( void* userdata ); + static void onInvisibilityCommit( LLUICtrl* ctrl, void* userdata ); + static bool onSelectAutoWearOption(const LLSD& notification, const LLSD& response); + + + + void onColorSwatchCommit(const LLUICtrl*); + void onTexturePickerCommit(const LLUICtrl*); +private: + + LLWearableType::EType mType; + BOOL mCanTakeOff; + std::map mInvisibilityList; + std::map mPreviousTextureList; + ESubpart mCurrentSubpart; +}; + +#endif diff --git a/indra/newview/llscrollingpanelparam.cpp b/indra/newview/llscrollingpanelparam.cpp new file mode 100644 index 000000000..5b142c571 --- /dev/null +++ b/indra/newview/llscrollingpanelparam.cpp @@ -0,0 +1,329 @@ +/** + * @file llscrollingpanelparam.cpp + * @brief UI panel for a list of visual param panels + * + * $LicenseInfo:firstyear=2009&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llscrollingpanelparam.h" +#include "llviewerjointmesh.h" +#include "llviewervisualparam.h" +#include "llwearable.h" +#include "llviewervisualparam.h" +#include "lltoolmorph.h" +#include "lltrans.h" +#include "llbutton.h" +#include "llsliderctrl.h" +#include "llagent.h" +#include "llviewborder.h" +#include "llvoavatarself.h" +#include "llagentwearables.h" +#include "llfloatercustomize.h" + +// Constants for LLPanelVisualParam +const F32 LLScrollingPanelParam::PARAM_STEP_TIME_THRESHOLD = 0.25f; + +const S32 LLScrollingPanelParam::PARAM_HINT_WIDTH = 128; +const S32 LLScrollingPanelParam::PARAM_HINT_HEIGHT = 128; + +const S32 BTN_BORDER = 2; +const S32 PARAM_HINT_LABEL_HEIGHT = 16; +const S32 PARAM_PANEL_WIDTH = 2 * (3* BTN_BORDER + LLScrollingPanelParam::PARAM_HINT_WIDTH + LLPANEL_BORDER_WIDTH); +const S32 PARAM_PANEL_HEIGHT = 2 * BTN_BORDER + LLScrollingPanelParam::PARAM_HINT_HEIGHT + PARAM_HINT_LABEL_HEIGHT + 4 * LLPANEL_BORDER_WIDTH; + +// LLScrollingPanelParam +//static +S32 LLScrollingPanelParam::sUpdateDelayFrames = 0; + +LLScrollingPanelParam::LLScrollingPanelParam( const std::string& name, + LLViewerJointMesh* mesh, LLViewerVisualParam* param, BOOL allow_modify, bool bVisualHint ) + : LLScrollingPanelParamBase( name, mesh, param, allow_modify, bVisualHint, LLRect( 0, PARAM_PANEL_HEIGHT, PARAM_PANEL_WIDTH, 0 )), + mLess(NULL), + mMore(NULL) +{ + + if(bVisualHint) + { + S32 pos_x = 2 * LLPANEL_BORDER_WIDTH; + S32 pos_y = 3 * LLPANEL_BORDER_WIDTH + SLIDERCTRL_HEIGHT; + F32 min_weight = param->getMinWeight(); + F32 max_weight = param->getMaxWeight(); + + mHintMin = new LLVisualParamHint( pos_x, pos_y, PARAM_HINT_WIDTH, PARAM_HINT_HEIGHT, mesh, param, min_weight); + pos_x += PARAM_HINT_WIDTH + 3 * BTN_BORDER; + mHintMax = new LLVisualParamHint( pos_x, pos_y, PARAM_HINT_WIDTH, PARAM_HINT_HEIGHT, mesh, param, max_weight ); + + mHintMin->setAllowsUpdates( FALSE ); + mHintMax->setAllowsUpdates( FALSE ); + + // *TODO::translate + std::string min_name = param->getMinDisplayName(); + std::string max_name = param->getMaxDisplayName(); + childSetValue("min param text", min_name); + childSetValue("max param text", max_name); + mLess = getChild("less"); + mLess->setMouseDownCallback( boost::bind(&LLScrollingPanelParam::onHintMouseDown, this, false) ); + mLess->setMouseUpCallback( boost::bind(&LLScrollingPanelParam::onHintMouseUp, this, false) ); + mLess->setHeldDownCallback( boost::bind(&LLScrollingPanelParam::onHintHeldDown, this, false) ); + mLess->setHeldDownDelay( PARAM_STEP_TIME_THRESHOLD ); + + mMore = getChild("more"); + mMore->setMouseDownCallback( boost::bind(&LLScrollingPanelParam::onHintMouseDown, this, true) ); + mMore->setMouseUpCallback( boost::bind(&LLScrollingPanelParam::onHintMouseUp, this, true) ); + mMore->setHeldDownCallback( boost::bind(&LLScrollingPanelParam::onHintHeldDown, this, true) ); + mMore->setHeldDownDelay( PARAM_STEP_TIME_THRESHOLD ); + } + + setVisible(FALSE); + setBorderVisible( FALSE ); +} + +LLScrollingPanelParam::~LLScrollingPanelParam() +{ + mHintMin = NULL; + mHintMax = NULL; +} + +void LLScrollingPanelParam::updatePanel(BOOL allow_modify) +{ + LLWearable* wearable = gAgentWearables.getWearable((LLWearableType::EType)mParam->getWearableType(),0); // TODO: MULTI-WEARABLE + + if(!wearable) + { + // not editing a wearable just now, no update necessary + return; + } + + LLScrollingPanelParamBase::updatePanel(allow_modify); + + if(mHintMin) + mHintMin->requestUpdate( sUpdateDelayFrames++ ); + if(mHintMax) + mHintMax->requestUpdate( sUpdateDelayFrames++ ); + + if(mLess) + mLess->setEnabled(mAllowModify); + if(mMore) + mMore->setEnabled(mAllowModify); +} + +void LLScrollingPanelParam::setVisible( BOOL visible ) +{ + if( getVisible() != visible ) + { + LLPanel::setVisible( visible ); + if(mHintMin) + mHintMin->setAllowsUpdates( visible ); + if(mHintMax) + mHintMax->setAllowsUpdates( visible ); + + if( visible ) + { + if(mHintMin) + mHintMin->setUpdateDelayFrames( sUpdateDelayFrames++ ); + if(mHintMax) + mHintMax->setUpdateDelayFrames( sUpdateDelayFrames++ ); + } + } +} + +void LLScrollingPanelParam::draw() +{ + LLWearable* wearable = gAgentWearables.getWearable((LLWearableType::EType)mParam->getWearableType(),0); // TODO: MULTI-WEARABLE + + if( !wearable || gFloaterCustomize->isMinimized() ) + { + return; + } + + if(mLess) + mLess->setVisible(mHintMin && mHintMin->getVisible()); + if(mMore) + mMore->setVisible(mHintMax && mHintMax->getVisible()); + + // Draw all the children except for the labels + childSetVisible( "min param text", FALSE ); + childSetVisible( "max param text", FALSE ); + LLPanel::draw(); + + // Draw the hints over the "less" and "more" buttons. + if(mHintMin) + { + gGL.pushMatrix(); + { + const LLRect& r = mHintMin->getRect(); + F32 left = (F32)(r.mLeft + BTN_BORDER); + F32 bot = (F32)(r.mBottom + BTN_BORDER); + gGL.translatef(left, bot, 0.f); + mHintMin->draw(); + } + gGL.popMatrix(); + } + + if(mHintMax) + { + gGL.pushMatrix(); + { + const LLRect& r = mHintMax->getRect(); + F32 left = (F32)(r.mLeft + BTN_BORDER); + F32 bot = (F32)(r.mBottom + BTN_BORDER); + gGL.translatef(left, bot, 0.f); + mHintMax->draw(); + } + gGL.popMatrix(); + } + + + // Draw labels on top of the buttons + childSetVisible( "min param text", TRUE ); + drawChild(getChild("min param text"), BTN_BORDER, BTN_BORDER); + + childSetVisible( "max param text", TRUE ); + drawChild(getChild("max param text"), BTN_BORDER, BTN_BORDER); +} + +// static +void LLScrollingPanelParam::onSliderMouseDown(LLUICtrl* ctrl, void* userdata) +{ +} + +// static +void LLScrollingPanelParam::onSliderMouseUp(LLUICtrl* ctrl, void* userdata) +{ + LLScrollingPanelParam* self = (LLScrollingPanelParam*) userdata; + LLVisualParamHint::requestHintUpdates( self->mHintMin, self->mHintMax ); +} + +void LLScrollingPanelParam::onHintMouseDown( bool max ) +{ + LLVisualParamHint* hint = max ? mHintMax : mHintMin; + LLViewerVisualParam* param = hint->getVisualParam(); + LLWearable* wearable = gAgentWearables.getWearable((LLWearableType::EType)mParam->getWearableType(),0); // TODO: MULTI-WEARABLE + + if(!wearable || !param) + { + return; + } + + // morph towards this result + F32 current_weight = wearable->getVisualParamWeight( hint->getVisualParam()->getID() ); + + // if we have maxed out on this morph, we shouldn't be able to click it + if( hint->getVisualParamWeight() != current_weight ) + { + mMouseDownTimer.reset(); + mLastHeldTime = 0.f; + } +} + +void LLScrollingPanelParam::onHintHeldDown( bool max ) +{ + LLVisualParamHint* hint = max ? mHintMax : mHintMin; + LLViewerVisualParam* param = hint->getVisualParam(); + LLWearable* wearable = gAgentWearables.getWearable((LLWearableType::EType)param->getWearableType(),0); // TODO: MULTI-WEARABLE + + if(!wearable || !param) + { + return; + } + + F32 current_weight = wearable->getVisualParamWeight( param->getID() ); + + if (current_weight != hint->getVisualParamWeight() ) + { + const F32 FULL_BLEND_TIME = 2.f; + F32 elapsed_time = mMouseDownTimer.getElapsedTimeF32() - mLastHeldTime; + mLastHeldTime += elapsed_time; + + F32 new_weight; + if (current_weight > hint->getVisualParamWeight() ) + { + new_weight = current_weight - (elapsed_time / FULL_BLEND_TIME); + } + else + { + new_weight = current_weight + (elapsed_time / FULL_BLEND_TIME); + } + + // Make sure we're not taking the slider out of bounds + // (this is where some simple UI limits are stored) + F32 new_percent = weightToPercent(new_weight); + LLSliderCtrl* slider = getChild("param slider"); + if (slider) + { + if (slider->getMinValue() < new_percent + && new_percent < slider->getMaxValue()) + { + wearable->setVisualParamWeight(param->getID(), new_weight, FALSE); + wearable->writeToAvatar(); + gAgentAvatarp->updateVisualParams(); + + slider->setValue( weightToPercent( new_weight ) ); + } + } + } +} + +void LLScrollingPanelParam::onHintMouseUp( bool max ) +{ + F32 elapsed_time = mMouseDownTimer.getElapsedTimeF32(); + + if (isAgentAvatarValid()) + { + LLVisualParamHint* hint = max ? mHintMax : mHintMin; + + if (elapsed_time < PARAM_STEP_TIME_THRESHOLD) + { + LLViewerVisualParam* param = hint->getVisualParam(); + + LLWearable* wearable = gAgentWearables.getWearable((LLWearableType::EType)param->getWearableType(),0); // TODO: MULTI-WEARABLE + if(wearable) + { + // step in direction + F32 current_weight = wearable->getVisualParamWeight( param->getID() ); + F32 range = mHintMax->getVisualParamWeight() - mHintMin->getVisualParamWeight(); + //if min, range should be negative. + if(!max) + range *= -1.f; + // step a fraction in the negative direction + F32 new_weight = current_weight + (range / 10.f); + F32 new_percent = weightToPercent(new_weight); + LLSliderCtrl* slider = getChild("param slider"); + if (slider) + { + if (slider->getMinValue() < new_percent + && new_percent < slider->getMaxValue()) + { + wearable->setVisualParamWeight(param->getID(), new_weight, FALSE); + wearable->writeToAvatar(); + slider->setValue( weightToPercent( new_weight ) ); + } + } + } + } + } + + LLVisualParamHint::requestHintUpdates( mHintMin, mHintMax ); +} + diff --git a/indra/newview/llscrollingpanelparam.h b/indra/newview/llscrollingpanelparam.h new file mode 100644 index 000000000..4b2069574 --- /dev/null +++ b/indra/newview/llscrollingpanelparam.h @@ -0,0 +1,76 @@ +/** + * @file llscrollingpanelparam.h + * @brief the scrolling panel containing a list of visual param + * panels + * + * $LicenseInfo:firstyear=2009&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$ + */ + +#ifndef LL_SCROLLINGPANELPARAM_H +#define LL_SCROLLINGPANELPARAM_H + +#include "llscrollingpanelparambase.h" + +class LLViewerJointMesh; +class LLViewerVisualParam; +class LLWearable; +class LLVisualParamHint; +class LLViewerVisualParam; +class LLJoint; + +class LLScrollingPanelParam : public LLScrollingPanelParamBase +{ +public: + LLScrollingPanelParam( const std::string& name, LLViewerJointMesh* mesh, LLViewerVisualParam* param, BOOL allow_modify, bool bVisualHint ); + virtual ~LLScrollingPanelParam(); + + virtual void draw(); + virtual void setVisible( BOOL visible ); + virtual void updatePanel(BOOL allow_modify); + + static void onSliderMouseDown(LLUICtrl* ctrl, void* userdata); + static void onSliderMouseUp(LLUICtrl* ctrl, void* userdata); + + void onHintMouseUp( bool max ); + void onHintMouseDown( bool max ); + void onHintHeldDown( bool max ); + +public: + // Constants for LLPanelVisualParam + const static F32 PARAM_STEP_TIME_THRESHOLD; + + const static S32 PARAM_HINT_WIDTH; + const static S32 PARAM_HINT_HEIGHT; + LLPointer mHintMin; + LLPointer mHintMax; + LLButton* mLess; + LLButton* mMore; + static S32 sUpdateDelayFrames; + +protected: + LLTimer mMouseDownTimer; // timer for how long mouse has been held down on a hint. + F32 mLastHeldTime; + BOOL mAllowModify; +}; + + +#endif diff --git a/indra/newview/llscrollingpanelparambase.cpp b/indra/newview/llscrollingpanelparambase.cpp new file mode 100644 index 000000000..bd8561cf6 --- /dev/null +++ b/indra/newview/llscrollingpanelparambase.cpp @@ -0,0 +1,139 @@ +/** + * @file llscrollingpanelparam.cpp + * @brief UI panel for a list of visual param panels + * + * $LicenseInfo:firstyear=2009&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llscrollingpanelparambase.h" +#include "llviewerjointmesh.h" +#include "llviewervisualparam.h" +#include "llwearable.h" +#include "llviewervisualparam.h" +#include "lltoolmorph.h" +#include "lltrans.h" +#include "llbutton.h" +#include "llsliderctrl.h" +#include "llagent.h" +#include "llviewborder.h" +#include "llvoavatarself.h" +#include "llagentwearables.h" + +LLScrollingPanelParamBase::LLScrollingPanelParamBase( const std::string& name, + LLViewerJointMesh* mesh, LLViewerVisualParam* param, BOOL allow_modify, bool bVisualHint, LLRect rect ) + : LLScrollingPanel( name, rect ), + mParam(param), + mAllowModify(allow_modify) +{ + LLUICtrlFactory::getInstance()->buildPanel(this, "panel_scrolling_param.xml"); + //Set up the slider + LLSliderCtrl *slider = getChild("param slider"); + + //Kill everything that isn't the slider... + if(!bVisualHint) + { + child_list_t to_remove; + child_list_t::const_iterator it; + for (it = getChildList()->begin(); it != getChildList()->end(); it++) + { + if ((*it) != slider && (*it)->getName() != "panel border") + { + to_remove.push_back(*it); + } + } + for (it = to_remove.begin(); it != to_remove.end(); it++) + { + removeChild(*it); + delete (*it); + } + slider->translate(0,/*PARAM_HINT_HEIGHT*/128); + reshape(getRect().getWidth(),getRect().getHeight()-128); + } + + slider->setValue(weightToPercent(param->getWeight())); + slider->setLabelArg("[DESC]", param->getDisplayName()); + slider->setEnabled(mAllowModify); + slider->setCommitCallback(boost::bind(&LLScrollingPanelParamBase::onSliderMoved, this, _1)); + + setVisible(FALSE); + setBorderVisible( FALSE ); +} + +LLScrollingPanelParamBase::~LLScrollingPanelParamBase() +{ +} + +void LLScrollingPanelParamBase::updatePanel(BOOL allow_modify) +{ + LLViewerVisualParam* param = mParam; + LLWearable* wearable = gAgentWearables.getWearable( (LLWearableType::EType)param->getWearableType(), 0 ); // TODO: MULTI-WEARABLE + if(!wearable) + { + // not editing a wearable just now, no update necessary + return; + } + + F32 current_weight = wearable->getVisualParamWeight( param->getID() ); + childSetValue("param slider", weightToPercent( current_weight ) ); + mAllowModify = allow_modify; + childSetEnabled("param slider", mAllowModify); +} + +void LLScrollingPanelParamBase::onSliderMoved(LLUICtrl* ctrl) +{ + if(!mParam) + { + return; + } + + LLWearable* wearable = gAgentWearables.getWearable( (LLWearableType::EType)mParam->getWearableType(), 0 ); // TODO: MULTI-WEARABLE + + if(!wearable) + { + return; + } + + LLSliderCtrl* slider = (LLSliderCtrl*) ctrl; + + F32 current_weight = wearable->getVisualParamWeight(mParam->getID()); + F32 new_weight = percentToWeight( (F32)slider->getValue().asReal() ); + if (current_weight != new_weight ) + { + wearable->setVisualParamWeight( mParam->getID(), new_weight, FALSE); + wearable->writeToAvatar(); + gAgentAvatarp->updateVisualParams(); + } +} + +F32 LLScrollingPanelParamBase::weightToPercent( F32 weight ) +{ + LLViewerVisualParam* param = mParam; + return (weight - param->getMinWeight()) / (param->getMaxWeight() - param->getMinWeight()) * 100.f; +} + +F32 LLScrollingPanelParamBase::percentToWeight( F32 percent ) +{ + LLViewerVisualParam* param = mParam; + return percent / 100.f * (param->getMaxWeight() - param->getMinWeight()) + param->getMinWeight(); +} diff --git a/indra/newview/llscrollingpanelparambase.h b/indra/newview/llscrollingpanelparambase.h new file mode 100644 index 000000000..9f41882c6 --- /dev/null +++ b/indra/newview/llscrollingpanelparambase.h @@ -0,0 +1,61 @@ +/** + * @file llscrollingpanelparam.h + * @brief the scrolling panel containing a list of visual param + * panels + * + * $LicenseInfo:firstyear=2009&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$ + */ + +#ifndef LL_SCROLLINGPANELPARAMBASE_H +#define LL_SCROLLINGPANELPARAMBASE_H + +#include "llpanel.h" +#include "llscrollingpanellist.h" + +class LLViewerJointMesh; +class LLViewerVisualParam; +class LLWearable; +class LLVisualParamHint; +class LLViewerVisualParam; +class LLJoint; + +class LLScrollingPanelParamBase : public LLScrollingPanel +{ +public: + LLScrollingPanelParamBase( const std::string& name, + LLViewerJointMesh* mesh, LLViewerVisualParam* param, BOOL allow_modify, bool bVisualHint, LLRect rect ); + virtual ~LLScrollingPanelParamBase(); + + virtual void updatePanel(BOOL allow_modify); + + void onSliderMoved(LLUICtrl* ctrl); + + F32 weightToPercent( F32 weight ); + F32 percentToWeight( F32 percent ); + +public: + LLViewerVisualParam* mParam; +protected: + BOOL mAllowModify; +}; + +#endif diff --git a/indra/newview/lltoolmorph.cpp b/indra/newview/lltoolmorph.cpp index f95a8f085..30d716134 100644 --- a/indra/newview/lltoolmorph.cpp +++ b/indra/newview/lltoolmorph.cpp @@ -64,6 +64,7 @@ #include "llviewerwindow.h" #include "llvoavatarself.h" #include "pipeline.h" +#include "llagentwearables.h" //static @@ -152,7 +153,8 @@ BOOL LLVisualParamHint::needsRender() void LLVisualParamHint::preRender(BOOL clear_depth) { mLastParamWeight = mVisualParam->getWeight(); - //mWearablePtr->setVisualParamWeight(mVisualParam->getID(), mVisualParamWeight, FALSE); + LLWearable* wearable = gAgentWearables.getWearable((LLWearableType::EType)mVisualParam->getWearableType(),0); // TODO: MULTI-WEARABLE + if(wearable)wearable->setVisualParamWeight(mVisualParam->getID(), mVisualParamWeight, FALSE); gAgentAvatarp->setVisualParamWeight(mVisualParam->getID(), mVisualParamWeight, FALSE); gAgentAvatarp->setVisualParamWeight("Blink_Left", 0.f); gAgentAvatarp->setVisualParamWeight("Blink_Right", 0.f); @@ -252,7 +254,10 @@ BOOL LLVisualParamHint::render() gGL.setSceneBlendType(LLRender::BT_ALPHA); gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); } - gAgentAvatarp->setVisualParamWeight(mVisualParam, mLastParamWeight); + gAgentAvatarp->setVisualParamWeight(mVisualParam->getID(), mLastParamWeight); + LLWearable* wearable = gAgentWearables.getWearable((LLWearableType::EType)mVisualParam->getWearableType(),0); // TODO: MULTI-WEARABLE + if(wearable)wearable->setVisualParamWeight(mVisualParam->getID(), mLastParamWeight, FALSE); + gAgentAvatarp->updateVisualParams(); gGL.color4f(1,1,1,1); mGLTexturep->setGLTextureCreated(true); return TRUE; diff --git a/indra/newview/llwearable.cpp b/indra/newview/llwearable.cpp index 1e12feb84..f44ac395a 100644 --- a/indra/newview/llwearable.cpp +++ b/indra/newview/llwearable.cpp @@ -1077,6 +1077,27 @@ void LLWearable::revertValues() { panel->updateScrollingPanelList(); }*/ + if( gFloaterCustomize ) + { + if(gAgentWearables.getWearableIndex(this) != 0) // TODO: MULTI-WEARABLE + return; + + LLViewerInventoryItem* item; + item = (LLViewerInventoryItem*)gInventory.getItem(getItemID()); // TODO: MULTI-WEARABLE + U32 perm_mask = PERM_NONE; + BOOL is_complete = FALSE; + if(item) + { + perm_mask = item->getPermissions().getMaskOwner(); + is_complete = item->isComplete(); + if(!is_complete) + { + item->fetchFromServer(); + } + } + gFloaterCustomize->setWearable(mType, this, perm_mask, is_complete); + LLFloaterCustomize::setCurrentWearableType( mType ); + } } BOOL LLWearable::isOnTop() const @@ -1118,6 +1139,28 @@ void LLWearable::saveValues() { panel->updateScrollingPanelList(); }*/ + if( gFloaterCustomize ) + { + if(gAgentWearables.getWearableIndex(this) != 0) // TODO: MULTI-WEARABLE + return; + + LLViewerInventoryItem* item; + item = (LLViewerInventoryItem*)gInventory.getItem(getItemID()); // TODO: MULTI-WEARABLE + U32 perm_mask = PERM_NONE; + BOOL is_complete = FALSE; + if(item) + { + perm_mask = item->getPermissions().getMaskOwner(); + is_complete = item->isComplete(); + if(!is_complete) + { + item->fetchFromServer(); + } + } + gFloaterCustomize->setWearable(mType, this, perm_mask, is_complete); + LLFloaterCustomize::setCurrentWearableType( mType ); + } + } void LLWearable::syncImages(te_map_t &src, te_map_t &dst) From 5228aa7029a4c538f352dee57b018f1e8ce47ea8 Mon Sep 17 00:00:00 2001 From: Shyotl Date: Sat, 9 Jun 2012 01:48:01 -0500 Subject: [PATCH 02/28] Updated LLMeshRepoThread. Hopefully a little more reliable. --- indra/newview/llmeshrepository.cpp | 191 ++++++++++------------------- indra/newview/llmeshrepository.h | 4 +- 2 files changed, 69 insertions(+), 126 deletions(-) diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index ab64f5228..caf2ce7da 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -521,9 +521,11 @@ void LLMeshRepoThread::run() mLODReqQ.pop(); LLMeshRepository::sLODProcessing--; mMutex->unlock(); - if (fetchMeshLOD(req.mMeshParams, req.mLOD)) + if (!fetchMeshLOD(req.mMeshParams, req.mLOD, count))//failed, resubmit { - count++; + mMutex->lock(); + mLODReqQ.push(req) ; + mMutex->unlock(); } } } @@ -536,9 +538,11 @@ void LLMeshRepoThread::run() HeaderRequest req = mHeaderReqQ.front(); mHeaderReqQ.pop(); mMutex->unlock(); - if (fetchMeshHeader(req.mMeshParams)) + if (!fetchMeshHeader(req.mMeshParams, count))//failed, resubmit { - count++; + mMutex->lock(); + mHeaderReqQ.push(req) ; + mMutex->unlock(); } } } @@ -691,8 +695,9 @@ bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id) return false; } + bool ret = true ; U32 header_size = mMeshHeaderSize[mesh_id]; - + if (header_size > 0) { S32 version = mMeshHeader[mesh_id]["version"].asInteger(); @@ -737,10 +742,13 @@ bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id) std::string http_url = constructUrl(mesh_id); if (!http_url.empty()) - { - LLMeshRepository::sHTTPRequestCount++; - mCurlRequest->getByteRange(constructUrl(mesh_id), headers, offset, size, - new LLMeshSkinInfoResponder(mesh_id, offset, size)); + { + ret = mCurlRequest->getByteRange(http_url, headers, offset, size, + new LLMeshSkinInfoResponder(mesh_id, offset, size)); + if(ret) + { + LLMeshRepository::sHTTPRequestCount++; + } } } } @@ -750,7 +758,7 @@ bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id) } //early out was not hit, effectively fetched - return true; + return ret; } bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id) @@ -769,7 +777,8 @@ bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id) } U32 header_size = mMeshHeaderSize[mesh_id]; - + bool ret = true ; + if (header_size > 0) { S32 version = mMeshHeader[mesh_id]["version"].asInteger(); @@ -814,10 +823,13 @@ bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id) std::string http_url = constructUrl(mesh_id); if (!http_url.empty()) - { - LLMeshRepository::sHTTPRequestCount++; - mCurlRequest->getByteRange(http_url, headers, offset, size, - new LLMeshDecompositionResponder(mesh_id, offset, size)); + { + ret = mCurlRequest->getByteRange(http_url, headers, offset, size, + new LLMeshDecompositionResponder(mesh_id, offset, size)); + if(ret) + { + LLMeshRepository::sHTTPRequestCount++; + } } } } @@ -827,7 +839,7 @@ bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id) } //early out was not hit, effectively fetched - return true; + return ret; } bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id) @@ -840,12 +852,13 @@ bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id) mHeaderMutex->lock(); if (mMeshHeader.find(mesh_id) == mMeshHeader.end()) - { //we have no header info for this mesh, do nothing + { //we have no header info for this mesh, do nothing mHeaderMutex->unlock(); return false; } U32 header_size = mMeshHeaderSize[mesh_id]; + bool ret = true ; if (header_size > 0) { @@ -891,14 +904,18 @@ bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id) std::string http_url = constructUrl(mesh_id); if (!http_url.empty()) - { - LLMeshRepository::sHTTPRequestCount++; - mCurlRequest->getByteRange(http_url, headers, offset, size, - new LLMeshPhysicsShapeResponder(mesh_id, offset, size)); + { + ret = mCurlRequest->getByteRange(http_url, headers, offset, size, + new LLMeshPhysicsShapeResponder(mesh_id, offset, size)); + + if(ret) + { + LLMeshRepository::sHTTPRequestCount++; + } } } else - { //no physics shape whatsoever, report back NULL + { //no physics shape whatsoever, report back NULL physicsShapeReceived(mesh_id, NULL, 0); } } @@ -908,13 +925,12 @@ bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id) } //early out was not hit, effectively fetched - return true; + return ret; } -bool LLMeshRepoThread::fetchMeshHeader(const LLVolumeParams& mesh_params) +//return false if failed to get header +bool LLMeshRepoThread::fetchMeshHeader(const LLVolumeParams& mesh_params, U32& count) { - bool retval = false; - { //look for mesh in asset in vfs LLVFile file(gVFS, mesh_params.getSculptID(), LLAssetType::AT_MESH); @@ -928,32 +944,37 @@ bool LLMeshRepoThread::fetchMeshHeader(const LLVolumeParams& mesh_params) LLMeshRepository::sCacheBytesRead += bytes; file.read(buffer, bytes); if (headerReceived(mesh_params, buffer, bytes)) - { //did not do an HTTP request, return false - return false; + { //did not do an HTTP request, return false + return true; } } } - //either cache entry doesn't exist or is corrupt, request header from simulator - + //either cache entry doesn't exist or is corrupt, request header from simulator + bool retval = true ; std::vector headers; headers.push_back("Accept: application/octet-stream"); std::string http_url = constructUrl(mesh_params.getSculptID()); if (!http_url.empty()) { - retval = true; //grab first 4KB if we're going to bother with a fetch. Cache will prevent future fetches if a full mesh fits //within the first 4KB - LLMeshRepository::sHTTPRequestCount++; - mCurlRequest->getByteRange(http_url, headers, 0, 4096, new LLMeshHeaderResponder(mesh_params)); + //NOTE -- this will break of headers ever exceed 4KB + retval = mCurlRequest->getByteRange(http_url, headers, 0, 4096, new LLMeshHeaderResponder(mesh_params)); + if(retval) + { + LLMeshRepository::sHTTPRequestCount++; + } + count++; } return retval; } -bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod) -{ //protected by mMutex +//return false if failed to get mesh lod. +bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod, U32& count) +{ //protected by mMutex if (!mHeaderMutex) { return false; @@ -961,7 +982,7 @@ bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod) mHeaderMutex->lock(); - bool retval = false; + bool retval = true; LLUUID mesh_id = mesh_params.getSculptID(); @@ -998,7 +1019,7 @@ bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod) if (lodReceived(mesh_params, lod, buffer, size)) { delete[] buffer; - return false; + return true; } } @@ -1011,11 +1032,15 @@ bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod) std::string http_url = constructUrl(mesh_id); if (!http_url.empty()) - { - retval = true; - LLMeshRepository::sHTTPRequestCount++; - mCurlRequest->getByteRange(constructUrl(mesh_id), headers, offset, size, + { + retval = mCurlRequest->getByteRange(constructUrl(mesh_id), headers, offset, size, new LLMeshLODResponder(mesh_params, lod, offset, size)); + + if(retval) + { + LLMeshRepository::sHTTPRequestCount++; + } + count++; } else { @@ -2212,6 +2237,7 @@ S32 LLMeshRepository::loadMesh(LLVOVolume* vobj, const LLVolumeParams& mesh_para //first request for this mesh mLoadingMeshes[detail][mesh_params].insert(vobj->getID()); mPendingRequests.push_back(LLMeshRepoThread::LODRequest(mesh_params, detail)); + LLMeshRepository::sLODPending++; } } @@ -3228,7 +3254,6 @@ void LLPhysicsDecomp::doDecompositionSingleHull() LLCDMeshData mesh; -#if 1 setMeshData(mesh, true); LLCDResult ret = decomp->buildSingleHull() ; @@ -3264,88 +3289,6 @@ void LLPhysicsDecomp::doDecompositionSingleHull() mCurRequest->mHull[0] = p; mMutex->unlock(); } -#else - setMeshData(mesh, false); - - //set all parameters to default - std::map param_map; - - static const LLCDParam* params = NULL; - static S32 param_count = 0; - - if (!params) - { - param_count = decomp->getParameters(¶ms); - } - - for (S32 i = 0; i < param_count; ++i) - { - decomp->setParam(params[i].mName, params[i].mDefault.mIntOrEnumValue); - } - - const S32 STAGE_DECOMPOSE = mStageID["Decompose"]; - const S32 STAGE_SIMPLIFY = mStageID["Simplify"]; - const S32 DECOMP_PREVIEW = 0; - const S32 SIMPLIFY_RETAIN = 0; - - decomp->setParam("Decompose Quality", DECOMP_PREVIEW); - decomp->setParam("Simplify Method", SIMPLIFY_RETAIN); - decomp->setParam("Retain%", 0.f); - - LLCDResult ret = LLCD_OK; - ret = decomp->executeStage(STAGE_DECOMPOSE); - - if (ret) - { - llwarns << "Could not execute decomposition stage when attempting to create single hull." << llendl; - make_box(mCurRequest); - } - else - { - ret = decomp->executeStage(STAGE_SIMPLIFY); - - if (ret) - { - llwarns << "Could not execute simiplification stage when attempting to create single hull." << llendl; - make_box(mCurRequest); - } - else - { - S32 num_hulls =0; - if (LLConvexDecomposition::getInstance() != NULL) - { - num_hulls = LLConvexDecomposition::getInstance()->getNumHullsFromStage(STAGE_SIMPLIFY); - } - - mMutex->lock(); - mCurRequest->mHull.clear(); - mCurRequest->mHull.resize(num_hulls); - mCurRequest->mHullMesh.clear(); - mMutex->unlock(); - - for (S32 i = 0; i < num_hulls; ++i) - { - std::vector p; - LLCDHull hull; - // if LLConvexDecomposition is a stub, num_hulls should have been set to 0 above, and we should not reach this code - LLConvexDecomposition::getInstance()->getHullFromStage(STAGE_SIMPLIFY, i, &hull); - - const F32* v = hull.mVertexBase; - - for (S32 j = 0; j < hull.mNumVertices; ++j) - { - LLVector3 vert(v[0], v[1], v[2]); - p.push_back(vert); - v = (F32*) (((U8*) v) + hull.mVertexStrideBytes); - } - - mMutex->lock(); - mCurRequest->mHull[i] = p; - mMutex->unlock(); - } - } - } -#endif { completeCurrent(); diff --git a/indra/newview/llmeshrepository.h b/indra/newview/llmeshrepository.h index a655b71d0..c106f810f 100644 --- a/indra/newview/llmeshrepository.h +++ b/indra/newview/llmeshrepository.h @@ -350,8 +350,8 @@ public: virtual void run(); void loadMeshLOD(const LLVolumeParams& mesh_params, S32 lod); - bool fetchMeshHeader(const LLVolumeParams& mesh_params); - bool fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod); + bool fetchMeshHeader(const LLVolumeParams& mesh_params, U32& count); + bool fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod, U32& count); bool headerReceived(const LLVolumeParams& mesh_params, U8* data, S32 data_size); bool lodReceived(const LLVolumeParams& mesh_params, S32 lod, U8* data, S32 data_size); bool skinInfoReceived(const LLUUID& mesh_id, U8* data, S32 data_size); From 332c8f997c4e9ebbb1f408743fe6fefab7018972 Mon Sep 17 00:00:00 2001 From: Shyotl Date: Sat, 9 Jun 2012 01:50:14 -0500 Subject: [PATCH 03/28] Applied MAINT-862. Sounds not playing first time. http://hg.secondlife.com/viewer-beta/changeset/24a7281bef42 --- indra/llaudio/llaudiodecodemgr.cpp | 19 +++++++++++++------ indra/llaudio/llaudioengine.cpp | 19 ++++++++++++------- indra/llaudio/llaudioengine.h | 9 ++++++--- 3 files changed, 31 insertions(+), 16 deletions(-) diff --git a/indra/llaudio/llaudiodecodemgr.cpp b/indra/llaudio/llaudiodecodemgr.cpp index 4350152ac..bc4f1c0b5 100644 --- a/indra/llaudio/llaudiodecodemgr.cpp +++ b/indra/llaudio/llaudiodecodemgr.cpp @@ -616,7 +616,8 @@ void LLAudioDecodeMgr::Impl::processQueue(const F32 num_secs) llwarns << mCurrentDecodep->getUUID() << " has invalid vorbis data, aborting decode" << llendl; mCurrentDecodep->flushBadFile(); LLAudioData *adp = gAudiop->getAudioData(mCurrentDecodep->getUUID()); - adp->setHasValidData(FALSE); + adp->setHasValidData(false); + adp->setHasCompletedDecode(true); mCurrentDecodep = NULL; done = TRUE; } @@ -631,11 +632,16 @@ void LLAudioDecodeMgr::Impl::processQueue(const F32 num_secs) if (mCurrentDecodep->finishDecode()) { // We finished! - if (mCurrentDecodep->isValid() && mCurrentDecodep->isDone()) + LLAudioData *adp = gAudiop->getAudioData(mCurrentDecodep->getUUID()); + if (!adp) { - LLAudioData *adp = gAudiop->getAudioData(mCurrentDecodep->getUUID()); - adp->setHasDecodedData(TRUE); - adp->setHasValidData(TRUE); + llwarns << "Missing LLAudioData for decode of " << mCurrentDecodep->getUUID() << llendl; + } + else if (mCurrentDecodep->isValid() && mCurrentDecodep->isDone()) + { + adp->setHasCompletedDecode(true); + adp->setHasDecodedData(true); + adp->setHasValidData(true); // At this point, we could see if anyone needs this sound immediately, but // I'm not sure that there's a reason to - we need to poll all of the playing @@ -644,7 +650,8 @@ void LLAudioDecodeMgr::Impl::processQueue(const F32 num_secs) } else { - llinfos << "Vorbis decode failed!!!" << llendl; + adp->setHasCompletedDecode(true); + llinfos << "Vorbis decode failed for " << mCurrentDecodep->getUUID() << llendl; } mCurrentDecodep = NULL; } diff --git a/indra/llaudio/llaudioengine.cpp b/indra/llaudio/llaudioengine.cpp index d696020bb..fb790dbdb 100644 --- a/indra/llaudio/llaudioengine.cpp +++ b/indra/llaudio/llaudioengine.cpp @@ -1279,6 +1279,7 @@ void LLAudioEngine::assetCallback(LLVFS *vfs, const LLUUID &uuid, LLAssetType::E adp->setHasValidData(false); adp->setHasLocalData(false); adp->setHasDecodedData(false); + adp->setHasCompletedDecode(true); } } else @@ -1380,16 +1381,18 @@ void LLAudioSource::update() if (!getCurrentBuffer()) { - if (getCurrentData()) + LLAudioData *adp = getCurrentData(); + if (adp) { // Hack - try and load the sound. Will do this as a callback // on decode later. - if (getCurrentData()->load() && getCurrentData()->getBuffer()) + if (adp->load() && adp->getBuffer()) { - play(getCurrentData()->getID()); + play(adp->getID()); } - else + else if (adp->hasCompletedDecode()) // Only mark corrupted after decode is done { + llwarns << "Marking LLAudioSource corrupted for " << adp->getID() << llendl; mCorrupted = true ; } } @@ -1812,6 +1815,7 @@ LLAudioData::LLAudioData(const LLUUID &uuid) : mBufferp(NULL), mHasLocalData(false), mHasDecodedData(false), + mHasCompletedDecode(false), mHasValidData(true) { if (uuid.isNull()) @@ -1823,12 +1827,13 @@ LLAudioData::LLAudioData(const LLUUID &uuid) : if (gAudiop && gAudiop->hasDecodedFile(uuid)) { // Already have a decoded version, don't need to decode it. - mHasLocalData = true; - mHasDecodedData = true; + setHasLocalData(true); + setHasDecodedData(true); + setHasCompletedDecode(true); } else if (gAssetStorage && gAssetStorage->hasLocalAsset(uuid, LLAssetType::AT_SOUND)) { - mHasLocalData = true; + setHasLocalData(true); } } diff --git a/indra/llaudio/llaudioengine.h b/indra/llaudio/llaudioengine.h index 254a1ee1f..c80b71688 100644 --- a/indra/llaudio/llaudioengine.h +++ b/indra/llaudio/llaudioengine.h @@ -408,10 +408,12 @@ public: bool hasLocalData() const { return mHasLocalData; } bool hasDecodedData() const { return mHasDecodedData; } + bool hasCompletedDecode() const { return mHasCompletedDecode; } bool hasValidData() const { return mHasValidData; } void setHasLocalData(const bool hld) { mHasLocalData = hld; } void setHasDecodedData(const bool hdd) { mHasDecodedData = hdd; } + void setHasCompletedDecode(const bool hcd) { mHasCompletedDecode = hcd; } void setHasValidData(const bool hvd) { mHasValidData = hvd; } friend class LLAudioEngine; // Severe laziness, bad. @@ -419,9 +421,10 @@ public: protected: LLUUID mID; LLAudioBuffer *mBufferp; // If this data is being used by the audio system, a pointer to the buffer will be set here. - bool mHasLocalData; - bool mHasDecodedData; - bool mHasValidData; + bool mHasLocalData; // Set true if the sound asset file is available locally + bool mHasDecodedData; // Set true if the sound file has been decoded + bool mHasCompletedDecode; // Set true when the sound is decoded + bool mHasValidData; // Set false if decoding failed, meaning the sound asset is bad }; From bb8417d6be6f0ef61697cf85923d15f876738d89 Mon Sep 17 00:00:00 2001 From: Shyotl Date: Sat, 9 Jun 2012 01:50:50 -0500 Subject: [PATCH 04/28] Added some missing settings pertaining to marketplace features. --- indra/newview/app_settings/settings.xml | 66 +++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 3f2c00386..cf09680e1 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -7257,6 +7257,72 @@ Value 1.0 + InventoryDisplayInbox + + Comment + Override received items inventory inbox display + Persist + 0 + Type + Boolean + Value + 0 + + InventoryDisplayOutbox + + Comment + Override merchant inventory outbox display + Persist + 0 + Type + Boolean + Value + 0 + + InventoryOutboxLogging + + Comment + Enable debug output associated with the Merchant Outbox. + Persist + 1 + Type + Boolean + Value + 0 + + InventoryOutboxMaxFolderCount + + Comment + Maximum number of subfolders allowed in a listing in the merchant outbox. + Persist + 0 + Type + U32 + Value + 21 + + InventoryOutboxMaxFolderDepth + + Comment + Maximum number of nested levels of subfolders allowed in a listing in the merchant outbox. + Persist + 0 + Type + U32 + Value + 4 + + InventoryOutboxMaxItemCount + + Comment + Maximum number of items allowed in a listing in the merchant outbox. + Persist + 0 + Type + U32 + Value + 200 + InventorySortOrder Comment From 1a217b23c6e098878284be81a6d1d36cc47adf84 Mon Sep 17 00:00:00 2001 From: Shyotl Date: Sat, 9 Jun 2012 01:57:21 -0500 Subject: [PATCH 05/28] SH-3065 Out-of-order operations on startup. http://hg.secondlife.com/viewer-beta/changeset/ecdfca07cbe3 --- indra/newview/llavatarpropertiesprocessor.cpp | 9 +++++++++ indra/newview/lltexturefetch.cpp | 14 +++++++++++--- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/indra/newview/llavatarpropertiesprocessor.cpp b/indra/newview/llavatarpropertiesprocessor.cpp index aa7d391a1..9ec769f9f 100644 --- a/indra/newview/llavatarpropertiesprocessor.cpp +++ b/indra/newview/llavatarpropertiesprocessor.cpp @@ -31,6 +31,7 @@ // Viewer includes #include "llagent.h" #include "llviewergenericmessage.h" +#include "llstartup.h" // Linden library includes #include "llavatarconstants.h" // AVATAR_TRANSACTED, etc. @@ -111,6 +112,14 @@ void LLAvatarPropertiesProcessor::sendGenericRequest(const LLUUID& avatar_id, EA void LLAvatarPropertiesProcessor::sendAvatarPropertiesRequest(const LLUUID& avatar_id) { + // this is the startup state when send_complete_agent_movement() message is sent. + // Before this, the AvatarPropertiesRequest message + // won't work so don't bother trying + if (LLStartUp::getStartupState() <= STATE_AGENT_SEND) + { + return; + } + if (isPendingRequest(avatar_id, APT_PROPERTIES)) { // waiting for a response, don't re-request diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp index 4862c7db7..cff601fde 100644 --- a/indra/newview/lltexturefetch.cpp +++ b/indra/newview/lltexturefetch.cpp @@ -57,6 +57,7 @@ #include "llviewerregion.h" #include "llviewerstats.h" #include "llworld.h" +#include "llstartup.h" ////////////////////////////////////////////////////////////////////////////// class LLTextureFetchWorker : public LLWorkerClass @@ -2367,6 +2368,7 @@ void LLTextureFetch::commonUpdate() } } + // MAIN THREAD //virtual S32 LLTextureFetch::update(F32 max_time_ms) @@ -2382,14 +2384,20 @@ S32 LLTextureFetch::update(F32 max_time_ms) mNetworkQueueMutex.unlock() ; } - + S32 res = LLWorkerThread::update(max_time_ms); if (!mDebugPause) { - sendRequestListToSimulators(); + // this is the startup state when send_complete_agent_movement() message is sent. + // Before this, the RequestImages message sent by sendRequestListToSimulators + // won't work so don't bother trying + if (LLStartUp::getStartupState() > STATE_AGENT_SEND) + { + sendRequestListToSimulators(); + } } - + if (!mThreaded) { commonUpdate(); From 5ce477c7cc1b6a6a4d3210e5a5fc990bca2fab28 Mon Sep 17 00:00:00 2001 From: Shyotl Date: Sat, 9 Jun 2012 02:28:42 -0500 Subject: [PATCH 06/28] Removed redundant double-click-teleport logic. --- indra/newview/lltoolpie.cpp | 50 +++++----------------------------- indra/newview/llviewermenu.cpp | 50 +++++++++++++--------------------- 2 files changed, 26 insertions(+), 74 deletions(-) diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp index 9b3a87d0e..bacfa4938 100644 --- a/indra/newview/lltoolpie.cpp +++ b/indra/newview/lltoolpie.cpp @@ -779,38 +779,26 @@ BOOL LLToolPie::handleDoubleClick(S32 x, S32 y, MASK mask) llinfos << "LLToolPie handleDoubleClick (becoming mouseDown)" << llendl; } - if (gSavedSettings.getBOOL("DoubleClickAutoPilot") || gSavedSettings.getBOOL("DoubleClickTeleport")) + if (gSavedSettings.getBOOL("DoubleClickAutoPilot")) { - if (mPick.mPickType == LLPickInfo::PICK_LAND - && !mPick.mPosGlobal.isExactlyZero()) + if ((mPick.mPickType == LLPickInfo::PICK_LAND && !mPick.mPosGlobal.isExactlyZero()) || + (mPick.mObjectID.notNull() && !mPick.mPosGlobal.isExactlyZero())) { handle_go_to(); return TRUE; } - else if (mPick.mObjectID.notNull() - && !mPick.mPosGlobal.isExactlyZero()) - { - // Hit an object - // Do not go to attachments... - if (mPick.getObject() && !mPick.getObject()->isHUDAttachment()) - { - // HACK: Call the last hit position the point we hit on the object - //gLastHitPosGlobal += gLastHitObjectOffset; - handle_go_to(); - return TRUE; - } - } - } else - /* code added to support double click teleports */ - if (gSavedSettings.getBOOL("DoubleClickTeleport")) + } + else if (gSavedSettings.getBOOL("DoubleClickTeleport")) { LLViewerObject* objp = mPick.getObject(); LLViewerObject* parentp = objp ? objp->getRootEdit() : NULL; + bool is_in_world = mPick.mObjectID.notNull() && objp && !objp->isHUDAttachment(); bool is_land = mPick.mPickType == LLPickInfo::PICK_LAND; bool pos_non_zero = !mPick.mPosGlobal.isExactlyZero(); bool has_touch_handler = (objp && objp->flagHandleTouch()) || (parentp && parentp->flagHandleTouch()); bool has_click_action = final_click_action(objp); + if (pos_non_zero && (is_land || (is_in_world && !has_touch_handler && !has_click_action))) { LLVector3d pos = mPick.mPosGlobal; @@ -821,30 +809,6 @@ BOOL LLToolPie::handleDoubleClick(S32 x, S32 y, MASK mask) } return FALSE; - - /* JC - don't do go-there, because then double-clicking on physical - objects gets you into trouble. - - // If double-click on object or land, go there. - LLViewerObject *object = gViewerWindow->getLastPick().getObject(); - if (object) - { - if (object->isAvatar()) - { - LLFloaterAvatarInfo::showFromAvatar(object->getID()); - } - else - { - handle_go_to(NULL); - } - } - else if (!gLastHitPosGlobal.isExactlyZero()) - { - handle_go_to(NULL); - } - - return TRUE; - */ } diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index e7867655c..634e70e0b 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -2751,44 +2751,32 @@ bool handle_go_to() */ // [/RLVa:KB] - // JAMESDEBUG try simulator autopilot + // try simulator autopilot std::vector strings; std::string val; LLVector3d pos = LLToolPie::getInstance()->getPick().mPosGlobal; - if (gSavedSettings.getBOOL("DoubleClickTeleport") - ) + val = llformat("%g", pos.mdV[VX]); + strings.push_back(val); + val = llformat("%g", pos.mdV[VY]); + strings.push_back(val); + val = llformat("%g", pos.mdV[VZ]); + strings.push_back(val); + send_generic_message("autopilot", strings); + + LLViewerParcelMgr::getInstance()->deselectLand(); + + if (isAgentAvatarValid() && !gSavedSettings.getBOOL("AutoPilotLocksCamera")) { - LLVector3d hips_offset(0.0f, 0.0f, 1.2f); - gAgent.teleportViaLocation(pos + hips_offset); + gAgentCamera.setFocusGlobal(gAgentCamera.getFocusTargetGlobal(), gAgentAvatarp->getID()); } - else + else { - // JAMESDEBUG try simulator autopilot - std::vector strings; - std::string val; - val = llformat("%g", pos.mdV[VX]); - strings.push_back(val); - val = llformat("%g", pos.mdV[VY]); - strings.push_back(val); - val = llformat("%g", pos.mdV[VZ]); - strings.push_back(val); - send_generic_message("autopilot", strings); - - LLViewerParcelMgr::getInstance()->deselectLand(); - - if (gAgentAvatarp && !gSavedSettings.getBOOL("AutoPilotLocksCamera")) - { - gAgentCamera.setFocusGlobal(gAgentCamera.getFocusTargetGlobal(), gAgentAvatarp->getID()); - } - else - { - // Snap camera back to behind avatar - gAgentCamera.setFocusOnAvatar(TRUE, ANIMATE); - } - - // Could be first use - LLFirstUse::useGoTo(); + // Snap camera back to behind avatar + gAgentCamera.setFocusOnAvatar(TRUE, ANIMATE); } + + // Could be first use + LLFirstUse::useGoTo(); return true; } From 891d6d344851422769da6f2aa119ef697779b5ff Mon Sep 17 00:00:00 2001 From: Shyotl Date: Mon, 11 Jun 2012 04:54:54 -0500 Subject: [PATCH 07/28] Interim work on appearance editor. --- indra/newview/llagentwearables.cpp | 8 + indra/newview/llfloatercustomize.cpp | 70 +--- indra/newview/llfloatercustomize.h | 14 +- indra/newview/llpaneleditwearable.cpp | 509 +++++++++++++++----------- indra/newview/llpaneleditwearable.h | 49 ++- indra/newview/lltoolmorph.cpp | 8 +- indra/newview/llwearable.cpp | 73 +--- 7 files changed, 363 insertions(+), 368 deletions(-) diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp index ccd53a187..ad5333323 100644 --- a/indra/newview/llagentwearables.cpp +++ b/indra/newview/llagentwearables.cpp @@ -831,6 +831,14 @@ void LLAgentWearables::wearableUpdated(LLWearable *wearable) saveWearable(wearable->getType(),index,TRUE); } + //Needed as wearable 'save' process is a mess and fires superfluous updateScrollingPanelList calls + //while the wearable being created has not yet been stuffed into the wearable list. + //This results in the param hints being buggered and screwing up the current wearable during LLVisualParamHint::preRender, + //thus making the wearable 'dirty'. The code below basically 'forces' a refresh of the panel to fix this. + U32 index = gAgentWearables.getWearableIndex(wearable); + if(gFloaterCustomize && index==0) + gFloaterCustomize->setWearable(wearable->getType(), wearable); + } void LLAgentWearables::popWearable(LLWearable *wearable) diff --git a/indra/newview/llfloatercustomize.cpp b/indra/newview/llfloatercustomize.cpp index 03a789c45..dd8a3742c 100644 --- a/indra/newview/llfloatercustomize.cpp +++ b/indra/newview/llfloatercustomize.cpp @@ -98,7 +98,7 @@ class LLFloaterCustomizeObserver : public LLInventoryObserver public: LLFloaterCustomizeObserver(LLFloaterCustomize* fc) : mFC(fc) {} virtual ~LLFloaterCustomizeObserver() {} - virtual void changed(U32 mask) { mFC->updateScrollingPanelUI(); } + virtual void changed(U32 mask) { mFC->getCurrentWearablePanel()->updateScrollingPanelUI(); } protected: LLFloaterCustomize* mFC; }; @@ -701,7 +701,7 @@ LLFloaterCustomize::~LLFloaterCustomize() void LLFloaterCustomize::switchToDefaultSubpart() { - getCurrentWearablePanel()->switchToDefaultSubpart(); + getCurrentWearablePanel()->showDefaultSubpart(); } void LLFloaterCustomize::draw() @@ -812,31 +812,7 @@ void LLFloaterCustomize::initScrollingPanelList() } } -void LLFloaterCustomize::clearScrollingPanelList() -{ - if( mScrollingPanelList ) - { - mScrollingPanelList->clearPanels(); - } -} - -void LLFloaterCustomize::generateVisualParamHints(LLViewerJointMesh* joint_mesh, LLFloaterCustomize::param_map& params, bool bVisualHint) -{ - // sorted_params is sorted according to magnitude of effect from - // least to greatest. Adding to the front of the child list - // reverses that order. - if( mScrollingPanelList ) - { - mScrollingPanelList->clearPanels(); - param_map::iterator end = params.end(); - for(param_map::iterator it = params.begin(); it != end; ++it) - { - mScrollingPanelList->addPanel( new LLScrollingPanelParam( "LLScrollingPanelParam", joint_mesh, (*it).second.second, (*it).second.first, bVisualHint) ); - } - } -} - -void LLFloaterCustomize::setWearable(LLWearableType::EType type, LLWearable* wearable, U32 perm_mask, BOOL is_complete) +void LLFloaterCustomize::setWearable(LLWearableType::EType type, LLWearable* wearable) { llassert( type < LLWearableType::WT_COUNT ); gSavedSettings.setU32("AvatarSex", (gAgentAvatarp->getSex() == SEX_MALE) ); @@ -844,21 +820,30 @@ void LLFloaterCustomize::setWearable(LLWearableType::EType type, LLWearable* wea LLPanelEditWearable* panel = mWearablePanelList[ type ]; if( panel ) { + U32 perm_mask = wearable ? PERM_NONE : PERM_ALL; + BOOL is_complete = wearable ? FALSE : TRUE; + if(wearable) + { + LLViewerInventoryItem* item = (LLViewerInventoryItem*)gInventory.getItem(gAgentWearables.getWearableItemID(type, 0)); // TODO: MULTI-WEARABLE + if(item) + { + perm_mask = item->getPermissions().getMaskOwner(); + is_complete = item->isComplete(); + if(!is_complete) + { + item->fetchFromServer(); + } + } + } panel->setWearable(wearable, perm_mask, is_complete); - updateScrollingPanelList((perm_mask & PERM_MODIFY) ? is_complete : FALSE); } } -void LLFloaterCustomize::updateScrollingPanelList(BOOL allow_modify) +void LLFloaterCustomize::updateScrollingPanelList() { - if( mScrollingPanelList ) - { - LLScrollingPanelParam::sUpdateDelayFrames = 0; - mScrollingPanelList->updatePanels(allow_modify ); - } + getCurrentWearablePanel()->updateScrollingPanelList(); } - void LLFloaterCustomize::askToSaveIfDirty( boost::function cb ) { if( isDirty()) @@ -984,18 +969,3 @@ void LLFloaterCustomize::updateInventoryUI() childSetEnabled("Make Outfit", all_complete); } -void LLFloaterCustomize::updateScrollingPanelUI() -{ - LLPanelEditWearable* panel = mWearablePanelList[sCurrentWearableType]; - if(panel) - { - LLViewerInventoryItem* item = (LLViewerInventoryItem*)gAgentWearables.getWearableInventoryItem(panel->getType(), 0); // TODO: MULTI-WEARABLE - if(item) - { - U32 perm_mask = item->getPermissions().getMaskOwner(); - BOOL is_complete = item->isComplete(); - updateScrollingPanelList((perm_mask & PERM_MODIFY) ? is_complete : FALSE); - } - } -} - diff --git a/indra/newview/llfloatercustomize.h b/indra/newview/llfloatercustomize.h index d4e7e1ad5..31343d199 100644 --- a/indra/newview/llfloatercustomize.h +++ b/indra/newview/llfloatercustomize.h @@ -71,10 +71,6 @@ class AIFilePicker; class LLFloaterCustomize : public LLFloater { -public: - typedef std::pair editable_param; - typedef std::map param_map; - public: LLFloaterCustomize(); virtual ~LLFloaterCustomize(); @@ -87,13 +83,9 @@ public: // New methods - void clearScrollingPanelList(); - void generateVisualParamHints(LLViewerJointMesh* joint_mesh, - param_map& params, bool bVisualHint); - void updateScrollingPanelList(BOOL allow_modify); - - void setWearable(LLWearableType::EType type, LLWearable* wearable, U32 perm_mask, BOOL is_complete); + void setWearable(LLWearableType::EType type, LLWearable* wearable); + void updateScrollingPanelList(); LLPanelEditWearable* getCurrentWearablePanel() { return mWearablePanelList[ sCurrentWearableType ]; } virtual BOOL isDirty() const; @@ -121,8 +113,8 @@ public: void fetchInventory(); void updateInventoryUI(); - void updateScrollingPanelUI(); + LLScrollingPanelList* getScrollingPanelList() const { return mScrollingPanelList; } protected: LLPanelEditWearable* mWearablePanelList[ LLWearableType::WT_COUNT ]; diff --git a/indra/newview/llpaneleditwearable.cpp b/indra/newview/llpaneleditwearable.cpp index 80780594d..99917d91e 100644 --- a/indra/newview/llpaneleditwearable.cpp +++ b/indra/newview/llpaneleditwearable.cpp @@ -183,13 +183,12 @@ public: PickerControlEntry(ETextureIndex tex_index, const std::string name, const LLUUID default_image_id = LLUUID::null, - const bool allow_no_texture = false, - const std::string checkbox_name = LLStringUtil::null); + const bool allow_no_texture = false + ); ETextureIndex mTextureIndex; const std::string mControlName; const LLUUID mDefaultImageId; const bool mAllowNoTexture; - std::string mCheckboxName; }; struct ColorSwatchCtrls : public LLDictionary @@ -364,11 +363,11 @@ LLEditWearableDictionary::TextureCtrls::TextureCtrls() addEntry ( TEX_UPPER_GLOVES, new PickerControlEntry (TEX_UPPER_GLOVES, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultGlovesUUID" ) ), FALSE )); addEntry ( TEX_UPPER_UNDERSHIRT, new PickerControlEntry (TEX_UPPER_UNDERSHIRT, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultUnderwearUUID" ) ), FALSE )); addEntry ( TEX_LOWER_UNDERPANTS, new PickerControlEntry (TEX_LOWER_UNDERPANTS, "Fabric", LLUUID( gSavedSettings.getString( "UIImgDefaultUnderwearUUID" ) ), FALSE )); - addEntry ( TEX_LOWER_ALPHA, new PickerControlEntry (TEX_LOWER_ALPHA, "Lower Alpha", LLUUID( gSavedSettings.getString( "UIImgDefaultAlphaUUID" ) ), TRUE, "lower alpha texture invisible" )); - addEntry ( TEX_UPPER_ALPHA, new PickerControlEntry (TEX_UPPER_ALPHA, "Upper Alpha", LLUUID( gSavedSettings.getString( "UIImgDefaultAlphaUUID" ) ), TRUE, "upper alpha texture invisible" )); - addEntry ( TEX_HEAD_ALPHA, new PickerControlEntry (TEX_HEAD_ALPHA, "Head Alpha", LLUUID( gSavedSettings.getString( "UIImgDefaultAlphaUUID" ) ), TRUE, "head alpha texture invisible" )); - addEntry ( TEX_EYES_ALPHA, new PickerControlEntry (TEX_EYES_ALPHA, "Eye Alpha", LLUUID( gSavedSettings.getString( "UIImgDefaultAlphaUUID" ) ), TRUE, "eye alpha texture invisible" )); - addEntry ( TEX_HAIR_ALPHA, new PickerControlEntry (TEX_HAIR_ALPHA, "Hair Alpha", LLUUID( gSavedSettings.getString( "UIImgDefaultAlphaUUID" ) ), TRUE, "hair alpha texture invisible" )); + addEntry ( TEX_LOWER_ALPHA, new PickerControlEntry (TEX_LOWER_ALPHA, "Lower Alpha", LLUUID( gSavedSettings.getString( "UIImgDefaultAlphaUUID" ) ), TRUE )); + addEntry ( TEX_UPPER_ALPHA, new PickerControlEntry (TEX_UPPER_ALPHA, "Upper Alpha", LLUUID( gSavedSettings.getString( "UIImgDefaultAlphaUUID" ) ), TRUE )); + addEntry ( TEX_HEAD_ALPHA, new PickerControlEntry (TEX_HEAD_ALPHA, "Head Alpha", LLUUID( gSavedSettings.getString( "UIImgDefaultAlphaUUID" ) ), TRUE )); + addEntry ( TEX_EYES_ALPHA, new PickerControlEntry (TEX_EYES_ALPHA, "Eye Alpha", LLUUID( gSavedSettings.getString( "UIImgDefaultAlphaUUID" ) ), TRUE )); + addEntry ( TEX_HAIR_ALPHA, new PickerControlEntry (TEX_HAIR_ALPHA, "Hair Alpha", LLUUID( gSavedSettings.getString( "UIImgDefaultAlphaUUID" ) ), TRUE )); addEntry ( TEX_LOWER_TATTOO, new PickerControlEntry (TEX_LOWER_TATTOO, "Lower Tattoo", LLUUID::null, TRUE )); addEntry ( TEX_UPPER_TATTOO, new PickerControlEntry (TEX_UPPER_TATTOO, "Upper Tattoo", LLUUID::null, TRUE )); addEntry ( TEX_HEAD_TATTOO, new PickerControlEntry (TEX_HEAD_TATTOO, "Head Tattoo", LLUUID::null, TRUE )); @@ -377,14 +376,12 @@ LLEditWearableDictionary::TextureCtrls::TextureCtrls() LLEditWearableDictionary::PickerControlEntry::PickerControlEntry(ETextureIndex tex_index, const std::string name, const LLUUID default_image_id, - const bool allow_no_texture, - const std::string checkbox_name) : + const bool allow_no_texture) : LLDictionaryEntry(name), mTextureIndex(tex_index), mControlName(name), mDefaultImageId(default_image_id), - mAllowNoTexture(allow_no_texture), - mCheckboxName(checkbox_name) + mAllowNoTexture(allow_no_texture) { } @@ -548,15 +545,6 @@ static void init_texture_ctrl(LLPanelEditWearable* self, LLPanel* panel, const L texture_ctrl->setImmediateFilterPermMask(PERM_NONE);//PERM_COPY | PERM_TRANSFER); texture_ctrl->setNonImmediateFilterPermMask(PERM_NONE);//PERM_COPY | PERM_TRANSFER); } - if(!entry->mCheckboxName.empty()) - { - LLCheckBoxCtrl* checkbox_ctrl = panel->getChild(entry->mCheckboxName, true, false); - if(checkbox_ctrl) - { - checkbox_ctrl->setCommitCallback(LLPanelEditWearable::onInvisibilityCommit, self); - self->initPreviousTextureListEntry(entry->mTextureIndex); - } - } } static void update_color_swatch_ctrl(LLPanelEditWearable* self, LLPanel* panel, const LLEditWearableDictionary::PickerControlEntry* entry) @@ -613,20 +601,6 @@ static void set_enabled_texture_ctrl(bool enabled, LLPanel* panel, const LLEditW } } -static void set_enabled_invisibility_ctrl(bool enabled, LLPanelEditWearable* self, LLPanel* panel, const LLEditWearableDictionary::PickerControlEntry* entry) -{ - if(!entry->mCheckboxName.empty()) - { - LLCheckBoxCtrl* checkbox_ctrl = panel->getChild(entry->mCheckboxName, true, false); - if(checkbox_ctrl) - { - checkbox_ctrl->setEnabled(enabled); - checkbox_ctrl->setVisible(enabled); - checkbox_ctrl->set(!gAgentAvatarp->isTextureVisible(entry->mTextureIndex, self->getWearable())); - } - } -} - class LLWearableSaveAsDialog : public LLModalDialog { private: @@ -718,6 +692,12 @@ BOOL LLPanelEditWearable::postBuild() childSetAction("Revert", &LLPanelEditWearable::onRevertButtonClicked, (void*)this ); + configureAlphaCheckbox(LLVOAvatarDefines::TEX_LOWER_ALPHA, "lower alpha texture invisible"); + configureAlphaCheckbox(LLVOAvatarDefines::TEX_UPPER_ALPHA, "upper alpha texture invisible"); + configureAlphaCheckbox(LLVOAvatarDefines::TEX_HEAD_ALPHA, "head alpha texture invisible"); + configureAlphaCheckbox(LLVOAvatarDefines::TEX_EYES_ALPHA, "eye alpha texture invisible"); + configureAlphaCheckbox(LLVOAvatarDefines::TEX_HAIR_ALPHA, "hair alpha texture invisible"); + { const LLEditWearableDictionary::WearableEntry *wearable_entry = LLEditWearableDictionary::getInstance()->getWearable(mType); if (!wearable_entry) @@ -742,7 +722,7 @@ BOOL LLPanelEditWearable::postBuild() { llinfos << "Finding button " << subpart_entry->mButtonName << llendl; llassert_always(getChild(subpart_entry->mButtonName,true,false)); - childSetAction(subpart_entry->mButtonName, &LLPanelEditWearable::onBtnSubpart, (void*)subpart_e); + childSetAction(subpart_entry->mButtonName, &LLPanelEditWearable::onBtnSubpart, (void*)index); } } // initialize texture and color picker controls @@ -760,31 +740,22 @@ BOOL LLPanelEditWearable::isDirty() const void LLPanelEditWearable::draw() { - if( gFloaterCustomize->isMinimized() ) - { + if( gFloaterCustomize->isMinimized() || !isAgentAvatarValid()) return; - } - LLVOAvatar* avatar = gAgentAvatarp; - if( !avatar ) - { - return; - } - - LLWearable* wearable = gAgentWearables.getWearable( mType, 0 ); // TODO: MULTI-WEARABLE + LLWearable* wearable = getWearable(); BOOL has_wearable = (wearable != NULL ); BOOL is_dirty = isDirty(); BOOL is_modifiable = FALSE; BOOL is_copyable = FALSE; BOOL is_complete = FALSE; - LLViewerInventoryItem* item; - item = (LLViewerInventoryItem*)gAgentWearables.getWearableInventoryItem(mType, 0); // TODO: MULTI-WEARABLE - if(item) + LLInventoryItem* item = NULL; + if(wearable && (item = gInventory.getItem(wearable->getItemID()))) { const LLPermissions& perm = item->getPermissions(); is_modifiable = perm.allowModifyBy(gAgent.getID(), gAgent.getGroupID()); is_copyable = perm.allowCopyBy(gAgent.getID(), gAgent.getGroupID()); - is_complete = item->isComplete(); + is_complete = ((LLViewerInventoryItem*)item)->isComplete(); } childSetEnabled("Save", is_modifiable && is_complete && has_wearable && is_dirty); @@ -818,7 +789,7 @@ void LLPanelEditWearable::draw() childSetVisible(subpart_entry->mButtonName,has_wearable); if( has_wearable && is_complete && is_modifiable ) { - childSetEnabled(subpart_entry->mButtonName, subpart_entry->mSex & avatar->getSex() ); + childSetEnabled(subpart_entry->mButtonName, subpart_entry->mSex & gAgentAvatarp->getSex() ); } else { @@ -843,7 +814,7 @@ void LLPanelEditWearable::draw() // // The value for avsize is the best available estimate from // measuring against prims. - float avsize = avatar->mBodySize.mV[VZ] + .195; + float avsize = gAgentAvatarp->mBodySize.mV[VZ] + .195; int inches = (int)(avsize / .0254f); int feet = inches / 12; inches %= 12; @@ -870,7 +841,7 @@ void LLPanelEditWearable::draw() childSetTextArg("title_loading", "[DESC]", std::string(LLWearableType::getTypeLabel( mType ))); std::string path; - const LLUUID& item_id = gAgentWearables.getWearableItemID( wearable->getType(), 0 ); // TODO: MULTI-WEARABLE + const LLUUID& item_id = wearable->getItemID(); append_path(item_id, path); childSetVisible("path", TRUE); childSetTextArg("path", "[PATH]", path); @@ -883,7 +854,7 @@ void LLPanelEditWearable::draw() childSetTextArg("title", "[DESC]", wearable->getName() ); std::string path; - const LLUUID& item_id = gAgentWearables.getWearableItemID( wearable->getType(), 0 ); // TODO: MULTI-WEARABLE + const LLUUID& item_id = wearable->getItemID(); append_path(item_id, path); childSetVisible("path", TRUE); childSetTextArg("path", "[PATH]", path); @@ -892,7 +863,16 @@ void LLPanelEditWearable::draw() for_each_picker_ctrl_entry (this, mType, boost::bind(update_texture_ctrl, this, _1, _2)); for_each_picker_ctrl_entry (this, mType, boost::bind(set_enabled_color_swatch_ctrl, is_complete, _1, _2)); for_each_picker_ctrl_entry (this, mType, boost::bind(set_enabled_texture_ctrl, is_complete, _1, _2)); - for_each_picker_ctrl_entry (this, mType, boost::bind(set_enabled_invisibility_ctrl, is_copyable && is_complete, this, _1, _2)); + for(string_texture_index_map_t::iterator iter = mAlphaCheckbox2Index.begin(); + iter != mAlphaCheckbox2Index.end(); ++iter ) + { + LLCheckBoxCtrl* ctrl = getChild(iter->first, true, false); + if (ctrl) + { + ctrl->setEnabled(is_copyable && is_complete); + ctrl->setVisible(is_copyable && is_complete); + } + } } else { @@ -917,7 +897,6 @@ void LLPanelEditWearable::setVisible(BOOL visible) } } -// static void LLPanelEditWearable::setWearable(LLWearable* wearable, U32 perm_mask, BOOL is_complete) { if( wearable ) @@ -925,22 +904,32 @@ void LLPanelEditWearable::setWearable(LLWearable* wearable, U32 perm_mask, BOOL setUIPermissions(perm_mask, is_complete); if (mType == LLWearableType::WT_ALPHA) { - initPreviousTextureList(); + initPreviousAlphaTextures(); + updateAlphaCheckboxes(); } } + const LLEditWearableDictionary::SubpartEntry *subpart_entry = LLEditWearableDictionary::getInstance()->getSubpart(mCurrentSubpart); + if(subpart_entry) + { + value_map_t sorted_params; + getSortedParams(sorted_params, subpart_entry->mEditGroup, ((perm_mask & PERM_MODIFY) && is_complete) ? TRUE : FALSE); + buildParamList(gFloaterCustomize->getScrollingPanelList(), sorted_params); + } + + updateScrollingPanelList(); } // static void LLPanelEditWearable::onRevertButtonClicked( void* userdata ) { - LLPanelEditWearable* self = (LLPanelEditWearable*) userdata; - gAgentWearables.revertWearable( self->mType, 0 ); // TODO: MULTI-WEARABLE + LLPanelEditWearable *panel = (LLPanelEditWearable*) userdata; + panel->revertChanges(); } void LLPanelEditWearable::onBtnSave( void* userdata ) { LLPanelEditWearable* self = (LLPanelEditWearable*) userdata; - gAgentWearables.saveWearable( self->mType, 0 ); // TODO: MULTI-WEARABLE + self->saveChanges(false); } // static @@ -960,11 +949,7 @@ void LLPanelEditWearable::onBtnSaveAs( void* userdata ) void LLPanelEditWearable::onSaveAsCommit( LLWearableSaveAsDialog* save_as_dialog, void* userdata ) { LLPanelEditWearable* self = (LLPanelEditWearable*) userdata; - LLVOAvatar* avatar = gAgentAvatarp; - if( avatar ) - { - gAgentWearables.saveWearableAs( self->getType(), 0, save_as_dialog->getItemName(), FALSE ); // TODO: MULTI-WEARABLE - } + self->saveChanges(true, save_as_dialog->getItemName()); } // static @@ -997,7 +982,8 @@ void LLPanelEditWearable::onCommitSexChange() gAgentAvatarp->updateSexDependentLayerSets( FALSE ); gAgentAvatarp->updateVisualParams(); - + + updateScrollingPanelUI(); //if(!wearable) //{ @@ -1010,7 +996,7 @@ void LLPanelEditWearable::onCommitSexChange() //wearable->writeToAvatar(); //avatar->updateVisualParams(); - gFloaterCustomize->clearScrollingPanelList(); +// gFloaterCustomize->clearScrollingPanelList(); // Assumes that we're in the "Shape" Panel. //self->setSubpart( SUBPART_SHAPE_WHOLE ); @@ -1051,18 +1037,6 @@ bool LLPanelEditWearable::onSelectAutoWearOption(const LLSD& notification, const return false; } - -bool LLPanelEditWearable::textureIsInvisible(ETextureIndex te) -{ - const LLWearable* wearable = gAgentWearables.getWearable(mType, 0); // TODO: MULTI-WEARABLE - if(wearable) - { - const LLLocalTextureObject* lto = wearable->getLocalTextureObject(te); - return (lto && lto->getID() == IMG_INVISIBLE); - } - return false; -} - LLWearable* LLPanelEditWearable::getWearable() const { return gAgentWearables.getWearable(mType, 0); // TODO: MULTI-WEARABLE @@ -1101,7 +1075,7 @@ void LLPanelEditWearable::onTexturePickerCommit(const LLUICtrl* ctrl) } if (mType == LLWearableType::WT_ALPHA && image->getID() != IMG_INVISIBLE) { - mPreviousTextureList[entry->mTextureIndex] = image->getID(); + mPreviousAlphaTexture[entry->mTextureIndex] = image->getID(); } } else @@ -1139,45 +1113,67 @@ void LLPanelEditWearable::onColorSwatchCommit(const LLUICtrl* base_ctrl ) } } -ESubpart LLPanelEditWearable::getDefaultSubpart() -{ - switch( mType ) - { - case LLWearableType::WT_SHAPE: return SUBPART_SHAPE_WHOLE; - case LLWearableType::WT_SKIN: return SUBPART_SKIN_COLOR; - case LLWearableType::WT_HAIR: return SUBPART_HAIR_COLOR; - case LLWearableType::WT_EYES: return SUBPART_EYES; - case LLWearableType::WT_SHIRT: return SUBPART_SHIRT; - case LLWearableType::WT_PANTS: return SUBPART_PANTS; - case LLWearableType::WT_SHOES: return SUBPART_SHOES; - case LLWearableType::WT_SOCKS: return SUBPART_SOCKS; - case LLWearableType::WT_JACKET: return SUBPART_JACKET; - case LLWearableType::WT_GLOVES: return SUBPART_GLOVES; - case LLWearableType::WT_UNDERSHIRT: return SUBPART_UNDERSHIRT; - case LLWearableType::WT_UNDERPANTS: return SUBPART_UNDERPANTS; - case LLWearableType::WT_SKIRT: return SUBPART_SKIRT; - case LLWearableType::WT_ALPHA: return SUBPART_ALPHA; - case LLWearableType::WT_TATTOO: return SUBPART_TATTOO; - case LLWearableType::WT_PHYSICS: return SUBPART_PHYSICS_BELLY_UPDOWN; - - default: llassert(0); return SUBPART_SHAPE_WHOLE; - } -} - - - void LLPanelEditWearable::hideTextureControls() { for_each_picker_ctrl_entry (this, mType, boost::bind(set_enabled_texture_ctrl, FALSE, _1, _2)); for_each_picker_ctrl_entry (this, mType, boost::bind(set_enabled_color_swatch_ctrl, FALSE, _1, _2)); - for_each_picker_ctrl_entry (this, mType, boost::bind(set_enabled_invisibility_ctrl, FALSE, this, _1, _2)); + for(string_texture_index_map_t::iterator iter = mAlphaCheckbox2Index.begin(); + iter != mAlphaCheckbox2Index.end(); ++iter ) + { + LLCheckBoxCtrl* ctrl = getChild(iter->first, true, false); + if (ctrl) + { + ctrl->setEnabled(FALSE); + ctrl->setVisible(FALSE); + } + } } - -void LLPanelEditWearable::switchToDefaultSubpart() +void LLPanelEditWearable::saveChanges(bool force_save_as, std::string new_name) { - setSubpart( getDefaultSubpart() ); + if (!getWearable() || !isDirty()) + { + // do nothing if no unsaved changes + return; + } + + U32 index = gAgentWearables.getWearableIndex(getWearable()); + + if (force_save_as) + { + // the name of the wearable has changed, re-save wearable with new name + LLAppearanceMgr::instance().removeCOFItemLinks(getWearable()->getItemID(),false); + gAgentWearables.saveWearableAs(mType, index, new_name, FALSE); + childSetTextArg("title", "[DESC]", new_name ); + } + else + { + gAgentWearables.saveWearable(mType, index, TRUE, new_name); + } +} + +void LLPanelEditWearable::revertChanges() +{ + LLWearable* wearable = getWearable(); + if (!wearable || !isDirty()) + { + // no unsaved changes to revert + return; + } + + wearable->revertValues(); + childSetTextArg("title", "[DESC]", wearable->getName() ); + gAgentAvatarp->wearableUpdated(mType, FALSE); + if (mType == LLWearableType::WT_ALPHA) + { + updateAlphaCheckboxes(); + } +} + +void LLPanelEditWearable::showDefaultSubpart() +{ + changeCamera(0); } @@ -1192,7 +1188,16 @@ void LLPanelEditWearable::setUIPermissions(U32 perm_mask, BOOL is_complete) childSetEnabled("sex radio", is_modifiable && is_complete); for_each_picker_ctrl_entry (this, mType, boost::bind(set_enabled_texture_ctrl, is_copyable && is_modifiable && is_complete, _1, _2)); for_each_picker_ctrl_entry (this, mType, boost::bind(set_enabled_color_swatch_ctrl, is_modifiable && is_complete, _1, _2)); - for_each_picker_ctrl_entry (this, mType, boost::bind(set_enabled_invisibility_ctrl, is_copyable && is_modifiable && is_complete, this, _1, _2)); + for(string_texture_index_map_t::iterator iter = mAlphaCheckbox2Index.begin(); + iter != mAlphaCheckbox2Index.end(); ++iter ) + { + LLCheckBoxCtrl* ctrl = getChild(iter->first, true, false); + if (ctrl) + { + ctrl->setEnabled(is_copyable && is_modifiable && is_complete); + ctrl->setVisible(is_copyable && is_modifiable && is_complete); + } + } } // static @@ -1202,20 +1207,37 @@ void LLPanelEditWearable::onBtnSubpart(void* userdata) if (!floater_customize) return; LLPanelEditWearable* self = floater_customize->getCurrentWearablePanel(); if (!self) return; - ESubpart subpart = (ESubpart) (intptr_t)userdata; - self->setSubpart( subpart ); + self->changeCamera( (S32)(intptr_t)userdata ); } -void LLPanelEditWearable::setSubpart( ESubpart subpart ) +void LLPanelEditWearable::changeCamera(U8 subpart) { - mCurrentSubpart = subpart; + + const LLEditWearableDictionary::WearableEntry *wearable_entry = LLEditWearableDictionary::getInstance()->getWearable(mType); + if (!wearable_entry) + { + llinfos << "could not get wearable dictionary entry for wearable type: " << mType << llendl; + return; + } - const LLEditWearableDictionary::WearableEntry *wearable_entry = LLEditWearableDictionary::getInstance()->getWearable(mType); - if (wearable_entry) - { - U8 num_subparts = wearable_entry->mSubparts.size(); + if (subpart >= wearable_entry->mSubparts.size()) + { + llinfos << "accordion tab expanded for invalid subpart. Wearable type: " << mType << " subpart num: " << subpart << llendl; + return; + } - for (U8 index = 0; index < num_subparts; ++index) + ESubpart subpart_e = wearable_entry->mSubparts[subpart]; + const LLEditWearableDictionary::SubpartEntry *subpart_entry = LLEditWearableDictionary::getInstance()->getSubpart(subpart_e); + + if (!subpart_entry) + { + llwarns << "could not get wearable subpart dictionary entry for subpart: " << subpart_e << llendl; + return; + } + + mCurrentSubpart = subpart_e; + //Update the buttons to reflect the current selected subpart. + for (U8 index = 0; index < wearable_entry->mSubparts.size(); ++index) { // dive into data structures to get the panel we need ESubpart subpart_e = wearable_entry->mSubparts[index]; @@ -1229,17 +1251,10 @@ void LLPanelEditWearable::setSubpart( ESubpart subpart ) } } } - } - const LLEditWearableDictionary::SubpartEntry *subpart_entry = LLEditWearableDictionary::getInstance()->getSubpart(subpart); - if( subpart_entry ) - { // Update the thumbnails we display - LLFloaterCustomize::param_map sorted_params; - LLVOAvatar* avatar = gAgentAvatarp; - ESex avatar_sex = avatar->getSex(); - LLViewerInventoryItem* item; - item = (LLViewerInventoryItem*)gAgentWearables.getWearableInventoryItem(mType,0); // TODO: MULTI-WEARABLE + LLWearable* wearable = getWearable(); + LLViewerInventoryItem* item = wearable ? gInventory.getItem(wearable->getItemID()) : NULL; U32 perm_mask = 0x0; BOOL is_complete = FALSE; bool can_export = false; @@ -1249,7 +1264,7 @@ void LLPanelEditWearable::setSubpart( ESubpart subpart ) perm_mask = item->getPermissions().getMaskOwner(); is_complete = item->isComplete(); - if (subpart <= 18) // body parts only + if (subpart_e < SUBPART_EYES) // body parts only { can_import = true; @@ -1264,27 +1279,11 @@ void LLPanelEditWearable::setSubpart( ESubpart subpart ) } } setUIPermissions(perm_mask, is_complete); - BOOL editable = ((perm_mask & PERM_MODIFY) && is_complete) ? TRUE : FALSE; - - for(LLViewerVisualParam* param = (LLViewerVisualParam *)avatar->getFirstVisualParam(); - param; - param = (LLViewerVisualParam *)avatar->getNextVisualParam()) - { - if (param->getID() == -1 - || !param->isTweakable() - || param->getEditGroup() != subpart_entry->mEditGroup - || !(param->getSex() & avatar_sex)) - { - continue; - } - // negative getDisplayOrder() to make lowest order the highest priority - LLFloaterCustomize::param_map::value_type vt(-param->getDisplayOrder(), LLFloaterCustomize::editable_param(editable, param)); - llassert( sorted_params.find(-param->getDisplayOrder()) == sorted_params.end() ); // Check for duplicates - sorted_params.insert(vt); - } - gFloaterCustomize->generateVisualParamHints(NULL, sorted_params, mType != LLWearableType::WT_PHYSICS); - gFloaterCustomize->updateScrollingPanelUI(); + value_map_t sorted_params; + getSortedParams(sorted_params, subpart_entry->mEditGroup, ((perm_mask & PERM_MODIFY) && is_complete) ? TRUE : FALSE); + buildParamList(gFloaterCustomize->getScrollingPanelList(), sorted_params); + updateScrollingPanelUI(); gFloaterCustomize->childSetEnabled("Export", can_export); gFloaterCustomize->childSetEnabled("Import", can_import); @@ -1297,6 +1296,32 @@ void LLPanelEditWearable::setSubpart( ESubpart subpart ) { gMorphView->updateCamera(); } +} + +void LLPanelEditWearable::updateScrollingPanelList() +{ + updateScrollingPanelUI(); +} + +void LLPanelEditWearable::updateScrollingPanelUI() +{ + LLWearable* wearable = getWearable(); + // do nothing if we don't have a valid wearable we're editing + if(!wearable) + { + return; + } + + llinfos << llformat("%#.8lX",wearable) << llendl; + llinfos << "cur_wearable->isDirty()=" << wearable->isDirty() << llendl; + + LLViewerInventoryItem* item = gInventory.getItem(wearable->getItemID()); + if(item) + { + U32 perm_mask = item->getPermissions().getMaskOwner(); + BOOL is_complete = item->isComplete(); + LLScrollingPanelParam::sUpdateDelayFrames = 0; + gFloaterCustomize->getScrollingPanelList()->updatePanels((perm_mask & PERM_MODIFY) && is_complete); } } @@ -1315,91 +1340,133 @@ void LLPanelEditWearable::onBtnTakeOff( void* userdata ) } // static -void LLPanelEditWearable::onInvisibilityCommit(LLUICtrl* ctrl, void* userdata) +void LLPanelEditWearable::getSortedParams(value_map_t &sorted_params, const std::string &edit_group, bool editable) { - LLPanelEditWearable* self = (LLPanelEditWearable*) userdata; - LLCheckBoxCtrl* checkbox_ctrl = (LLCheckBoxCtrl*) ctrl; - if (!gAgentAvatarp) - { - return; - } + if(!getWearable())return; - const LLEditWearableDictionary::WearableEntry *wearable_entry = LLEditWearableDictionary::getInstance()->getWearable(self->mType); - if (wearable_entry) - { - U8 num_textures = wearable_entry->mTextureCtrls.size(); + LLWearable::visual_param_vec_t param_list; + ESex avatar_sex = gAgentAvatarp->getSex(); - for (U8 index = 0; index < num_textures; ++index) + getWearable()->getVisualParams(param_list); + + for (LLWearable::visual_param_vec_t::iterator iter = param_list.begin(); + iter != param_list.end(); + ++iter) { - // dive into data structures to get the panel we need - ETextureIndex texindex = wearable_entry->mTextureCtrls[index]; - - const LLEditWearableDictionary::PickerControlEntry *tex_ctrl = LLEditWearableDictionary::getInstance()->getTexturePicker(texindex); - - if (tex_ctrl && tex_ctrl->mCheckboxName == checkbox_ctrl->getName()) - { - bool new_invis_state = checkbox_ctrl->get(); - if (new_invis_state) - { - LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTexture(IMG_INVISIBLE); - - LLWearable* wearable = gAgentWearables.getWearable(self->mType,0); // TODO: MULTI-WEARABLE - const LLLocalTextureObject* lto = wearable ? wearable->getLocalTextureObject(texindex) : NULL; + LLViewerVisualParam *param = (LLViewerVisualParam*) *iter; - if(lto) - { - self->mPreviousTextureList[(S32)texindex] = lto->getID(); - } - if(wearable) - { - LLLocalTextureObject new_lto(image, IMG_INVISIBLE); - wearable->setLocalTextureObject(texindex, new_lto); - wearable->writeToAvatar(); - gAgentAvatarp->wearableUpdated(self->mType, FALSE); - } - - } - else - { - // Try to restore previous texture, if any. - LLUUID prev_id = self->mPreviousTextureList[(S32)texindex]; - if (prev_id.isNull() || (prev_id == IMG_INVISIBLE)) - { - prev_id = LLUUID(gSavedSettings.getString("UIImgDefaultAlphaUUID")); - } - if (prev_id.notNull()) - { - LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTexture(prev_id); - LLWearable* wearable = gAgentWearables.getWearable(self->mType,0); // TODO: MULTI-WEARABLE - if(wearable) - { - LLLocalTextureObject new_lto(image, prev_id); - wearable->setLocalTextureObject(texindex, new_lto); - wearable->writeToAvatar(); - gAgentAvatarp->wearableUpdated(self->mType, FALSE); - } - } - } - } + if (param->getID() == -1 + || !param->isTweakable() + || param->getEditGroup() != edit_group + || !(param->getSex() & avatar_sex)) + { + continue; + } + + // negative getDisplayOrder() to make lowest order the highest priority + value_map_t::value_type vt(-param->getDisplayOrder(), editable_param(editable, param)); + llassert( sorted_params.find(-param->getDisplayOrder()) == sorted_params.end() ); // Check for duplicates + sorted_params.insert(vt); + } +} + +void LLPanelEditWearable::buildParamList(LLScrollingPanelList *panel_list, value_map_t &sorted_params) +{ + // sorted_params is sorted according to magnitude of effect from + // least to greatest. Adding to the front of the child list + // reverses that order. + if( panel_list ) + { + panel_list->clearPanels(); + value_map_t::iterator end = sorted_params.end(); + for(value_map_t::iterator it = sorted_params.begin(); it != end; ++it) + { + LLScrollingPanelParam *panel_param = NULL; + panel_param = new LLScrollingPanelParam( "LLScrollingPanelParam", NULL, (*it).second.second, (*it).second.first, (mType != LLWearableType::WT_PHYSICS)); + panel_list->addPanel( panel_param ); } } } - -void LLPanelEditWearable::initPreviousTextureList() + +void LLPanelEditWearable::configureAlphaCheckbox(LLVOAvatarDefines::ETextureIndex te, const std::string& name) { - initPreviousTextureListEntry(TEX_LOWER_ALPHA); - initPreviousTextureListEntry(TEX_UPPER_ALPHA); - initPreviousTextureListEntry(TEX_HEAD_ALPHA); - initPreviousTextureListEntry(TEX_EYES_ALPHA); - initPreviousTextureListEntry(TEX_LOWER_ALPHA); + LLCheckBoxCtrl* checkbox = getChild(name, true, false); + if(checkbox) + { + checkbox->setCommitCallback(boost::bind(&LLPanelEditWearable::onInvisibilityCommit, this, checkbox, te)); + initPreviousAlphaTextureEntry(te); + mAlphaCheckbox2Index[name] = te; + } } -void LLPanelEditWearable::initPreviousTextureListEntry(ETextureIndex te) + +void LLPanelEditWearable::onInvisibilityCommit(LLCheckBoxCtrl* checkbox_ctrl, LLVOAvatarDefines::ETextureIndex te) +{ + if (!checkbox_ctrl) return; + if (!getWearable()) return; + + llinfos << "onInvisibilityCommit, self " << this << " checkbox_ctrl " << checkbox_ctrl << llendl; + + bool new_invis_state = checkbox_ctrl->get(); + if (new_invis_state) + { + LLLocalTextureObject *lto = getWearable()->getLocalTextureObject(te); + mPreviousAlphaTexture[te] = lto->getID(); + + LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTexture( IMG_INVISIBLE ); + U32 index = gAgentWearables.getWearableIndex(getWearable()); + gAgentAvatarp->setLocalTexture(te, image, FALSE, index); + gAgentAvatarp->wearableUpdated(getWearable()->getType(), FALSE); + } + else + { + // Try to restore previous texture, if any. + LLUUID prev_id = mPreviousAlphaTexture[te]; + if (prev_id.isNull() || (prev_id == IMG_INVISIBLE)) + { + prev_id = LLUUID( gSavedSettings.getString( "UIImgDefaultAlphaUUID" ) ); + } + if (prev_id.isNull()) return; + + LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTexture(prev_id); + if (!image) return; + + U32 index = gAgentWearables.getWearableIndex(getWearable()); + gAgentAvatarp->setLocalTexture(te, image, FALSE, index); + gAgentAvatarp->wearableUpdated(getWearable()->getType(), FALSE); + } +} + +void LLPanelEditWearable::updateAlphaCheckboxes() +{ + if(!getWearable())return; + for(string_texture_index_map_t::iterator iter = mAlphaCheckbox2Index.begin(); + iter != mAlphaCheckbox2Index.end(); ++iter ) + { + LLVOAvatarDefines::ETextureIndex te = (LLVOAvatarDefines::ETextureIndex)iter->second; + LLCheckBoxCtrl* ctrl = getChild(iter->first, true, false); + if (ctrl) + { + ctrl->set(!gAgentAvatarp->isTextureVisible(te, getWearable())); + } + } +} + +void LLPanelEditWearable::initPreviousAlphaTextures() +{ + initPreviousAlphaTextureEntry(TEX_LOWER_ALPHA); + initPreviousAlphaTextureEntry(TEX_UPPER_ALPHA); + initPreviousAlphaTextureEntry(TEX_HEAD_ALPHA); + initPreviousAlphaTextureEntry(TEX_EYES_ALPHA); + initPreviousAlphaTextureEntry(TEX_LOWER_ALPHA); +} + +void LLPanelEditWearable::initPreviousAlphaTextureEntry(LLVOAvatarDefines::ETextureIndex te) { if(!getWearable()) return; LLLocalTextureObject *lto = getWearable()->getLocalTextureObject(te); if (lto) { - mPreviousTextureList[te] = lto->getID(); + mPreviousAlphaTexture[te] = lto->getID(); } } diff --git a/indra/newview/llpaneleditwearable.h b/indra/newview/llpaneleditwearable.h index 808296211..8f732244a 100644 --- a/indra/newview/llpaneleditwearable.h +++ b/indra/newview/llpaneleditwearable.h @@ -56,35 +56,42 @@ public: LLPanelEditWearable( LLWearableType::EType type ); virtual ~LLPanelEditWearable(); - virtual BOOL postBuild(); - virtual void draw(); - virtual BOOL isDirty() const; // LLUICtrl + /*virtual*/ BOOL postBuild(); + /*virtual*/ BOOL isDirty() const; // LLUICtrl + /*virtual*/ void draw(); - void addTextureDropTarget( ETextureIndex te, const std::string& name, const LLUUID& default_image_id, BOOL allow_no_texture ); - void addInvisibilityCheckbox(ETextureIndex te, const std::string& name); + // changes camera angle to default for selected subpart + void changeCamera(U8 subpart); const std::string& getLabel() { return LLWearableType::getTypeLabel( mType ); } LLWearableType::EType getType() const{ return mType; } LLWearable* getWearable() const; - ESubpart getDefaultSubpart(); - void setSubpart( ESubpart subpart ); - void switchToDefaultSubpart(); - void setWearable(LLWearable* wearable, U32 perm_mask, BOOL is_complete); + void saveChanges(bool force_save_as = false, std::string new_name = std::string()); + void setUIPermissions(U32 perm_mask, BOOL is_complete); void hideTextureControls(); - bool textureIsInvisible(ETextureIndex te); - void initPreviousTextureList(); - void initPreviousTextureListEntry(ETextureIndex te); + void revertChanges(); + + void showDefaultSubpart(); + + void updateScrollingPanelList(); static void onRevertButtonClicked( void* userdata ); void onCommitSexChange(); virtual void setVisible( BOOL visible ); + typedef std::pair editable_param; + typedef std::map value_map_t; + + void updateScrollingPanelUI(); + void getSortedParams(value_map_t &sorted_params, const std::string &edit_group, bool editable); + void buildParamList(LLScrollingPanelList *panel_list, value_map_t &sorted_params); + // Callbacks static void onBtnSubpart( void* userdata ); static void onBtnTakeOff( void* userdata ); @@ -95,19 +102,27 @@ public: static void onBtnTakeOffDialog( S32 option, void* userdata ); static void onBtnCreateNew( void* userdata ); - static void onInvisibilityCommit( LLUICtrl* ctrl, void* userdata ); static bool onSelectAutoWearOption(const LLSD& notification, const LLSD& response); - - void onColorSwatchCommit(const LLUICtrl*); void onTexturePickerCommit(const LLUICtrl*); + + //alpha mask checkboxes + void configureAlphaCheckbox(LLVOAvatarDefines::ETextureIndex te, const std::string& name); + void onInvisibilityCommit(LLCheckBoxCtrl* checkbox_ctrl, LLVOAvatarDefines::ETextureIndex te); + void updateAlphaCheckboxes(); + void initPreviousAlphaTextures(); + void initPreviousAlphaTextureEntry(LLVOAvatarDefines::ETextureIndex te); + private: LLWearableType::EType mType; BOOL mCanTakeOff; - std::map mInvisibilityList; - std::map mPreviousTextureList; + typedef std::map string_texture_index_map_t; + string_texture_index_map_t mAlphaCheckbox2Index; + + typedef std::map s32_uuid_map_t; + s32_uuid_map_t mPreviousAlphaTexture; ESubpart mCurrentSubpart; }; diff --git a/indra/newview/lltoolmorph.cpp b/indra/newview/lltoolmorph.cpp index 30d716134..c3954e8a7 100644 --- a/indra/newview/lltoolmorph.cpp +++ b/indra/newview/lltoolmorph.cpp @@ -154,8 +154,12 @@ void LLVisualParamHint::preRender(BOOL clear_depth) { mLastParamWeight = mVisualParam->getWeight(); LLWearable* wearable = gAgentWearables.getWearable((LLWearableType::EType)mVisualParam->getWearableType(),0); // TODO: MULTI-WEARABLE - if(wearable)wearable->setVisualParamWeight(mVisualParam->getID(), mVisualParamWeight, FALSE); - gAgentAvatarp->setVisualParamWeight(mVisualParam->getID(), mVisualParamWeight, FALSE); + if(wearable) + { + llinfos << llformat("%#.8lX",wearable) << llendl; + wearable->setVisualParamWeight(mVisualParam->getID(), mVisualParamWeight, FALSE); + } + gAgentAvatarp->setVisualParamWeight(mVisualParam->getID(), mVisualParamWeight, FALSE); gAgentAvatarp->setVisualParamWeight("Blink_Left", 0.f); gAgentAvatarp->setVisualParamWeight("Blink_Right", 0.f); gAgentAvatarp->updateComposites(); diff --git a/indra/newview/llwearable.cpp b/indra/newview/llwearable.cpp index f44ac395a..d8e8792bc 100644 --- a/indra/newview/llwearable.cpp +++ b/indra/newview/llwearable.cpp @@ -727,36 +727,12 @@ void LLWearable::writeToAvatar() gAgentAvatarp->setLocalTextureTE(te, image, 0); } } - - /*if( gFloaterCustomize ) - { - LLViewerInventoryItem* item; - item = (LLViewerInventoryItem*)gInventory.getItem(gAgentWearables.getWearableItemID(mType, 0)); // TODO: MULTI-WEARABLE - U32 perm_mask = PERM_NONE; - BOOL is_complete = FALSE; - if(item) - { - perm_mask = item->getPermissions().getMaskOwner(); - is_complete = item->isComplete(); - if(!is_complete) - { - item->fetchFromServer(); - } - } - gFloaterCustomize->setWearable(mType, this, perm_mask, is_complete); - LLFloaterCustomize::setCurrentWearableType( mType ); - }*/ ESex new_sex = gAgentAvatarp->getSex(); if( old_sex != new_sex ) { gAgentAvatarp->updateSexDependentLayerSets( FALSE ); } - -// if( upload_bake ) -// { -// gAgent.sendAgentSetAppearance(); -// } } @@ -787,7 +763,7 @@ void LLWearable::removeFromAvatar( LLWearableType::EType type, BOOL upload_bake if(gAgentCamera.cameraCustomizeAvatar()) { - gFloaterCustomize->setWearable(type, NULL, PERM_ALL, TRUE); + gFloaterCustomize->setWearable(type, NULL); } gAgentAvatarp->updateVisualParams(); @@ -1077,27 +1053,9 @@ void LLWearable::revertValues() { panel->updateScrollingPanelList(); }*/ - if( gFloaterCustomize ) - { - if(gAgentWearables.getWearableIndex(this) != 0) // TODO: MULTI-WEARABLE - return; - - LLViewerInventoryItem* item; - item = (LLViewerInventoryItem*)gInventory.getItem(getItemID()); // TODO: MULTI-WEARABLE - U32 perm_mask = PERM_NONE; - BOOL is_complete = FALSE; - if(item) - { - perm_mask = item->getPermissions().getMaskOwner(); - is_complete = item->isComplete(); - if(!is_complete) - { - item->fetchFromServer(); - } - } - gFloaterCustomize->setWearable(mType, this, perm_mask, is_complete); - LLFloaterCustomize::setCurrentWearableType( mType ); - } + if( gFloaterCustomize && gAgentWearables.getWearableIndex(this)==0 ) + gFloaterCustomize->updateScrollingPanelList(); + } BOOL LLWearable::isOnTop() const @@ -1139,28 +1097,9 @@ void LLWearable::saveValues() { panel->updateScrollingPanelList(); }*/ - if( gFloaterCustomize ) - { - if(gAgentWearables.getWearableIndex(this) != 0) // TODO: MULTI-WEARABLE - return; - - LLViewerInventoryItem* item; - item = (LLViewerInventoryItem*)gInventory.getItem(getItemID()); // TODO: MULTI-WEARABLE - U32 perm_mask = PERM_NONE; - BOOL is_complete = FALSE; - if(item) - { - perm_mask = item->getPermissions().getMaskOwner(); - is_complete = item->isComplete(); - if(!is_complete) - { - item->fetchFromServer(); - } - } - gFloaterCustomize->setWearable(mType, this, perm_mask, is_complete); - LLFloaterCustomize::setCurrentWearableType( mType ); - } + if( gFloaterCustomize && gAgentWearables.getWearableIndex(this)==0) + gFloaterCustomize->updateScrollingPanelList(); } void LLWearable::syncImages(te_map_t &src, te_map_t &dst) From 57641db71bdbcf44b609adbe3177220b7a6c4a7b Mon Sep 17 00:00:00 2001 From: Shyotl Date: Mon, 11 Jun 2012 06:43:05 -0500 Subject: [PATCH 08/28] Added 'Move Forward' and 'Move Back' to multi-worn clothing context menus. --- indra/newview/llinventorybridge.cpp | 45 +++++++++++++++++++ .../default/xui/en-us/menu_inventory.xml | 8 ++++ 2 files changed, 53 insertions(+) diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index c2a870ce1..d0ffee5c9 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -5543,6 +5543,33 @@ LLUIImagePtr LLWearableBridge::getIcon() const return LLInventoryIcon::getIcon(mAssetType, mInvType, mWearableType, FALSE); } +//LLAppearanceMgr::moveWearable unfortunately fails for non-link item, so links in CoF must be found for this to work. +void move_wearable_item(LLViewerInventoryItem* item, bool closer_to_body) +{ + if(!item) + return; + + if(item->getIsLinkType()) + { + if(LLAppearanceMgr::instance().moveWearable(item, closer_to_body)) + gAgentAvatarp->wearableUpdated(item->getWearableType(),TRUE); + } + else + { + LLInventoryModel::item_array_t items; + gInventory.collectDescendentsIf(LLAppearanceMgr::instance().getCOF(), + LLInventoryModel::cat_array_t(), + items, + LLInventoryModel::EXCLUDE_TRASH, + LLLinkedItemIDMatches(item->getUUID())); + if(!items.empty()) + { + if(LLAppearanceMgr::instance().moveWearable(gInventory.getItem(items.front()->getUUID()),closer_to_body)) + gAgentAvatarp->wearableUpdated(item->getWearableType(),TRUE); + } + } +} + // virtual void LLWearableBridge::performAction(LLInventoryModel* model, std::string action) { @@ -5564,6 +5591,15 @@ void LLWearableBridge::performAction(LLInventoryModel* model, std::string action removeFromAvatar(); return; } + //These move + else if("move_forward" == action) + { + move_wearable_item(getItem(),false); + } + else if("move_back" == action) + { + move_wearable_item(getItem(),true); + } else LLItemBridge::performAction(model, action); } @@ -5686,6 +5722,15 @@ void LLWearableBridge::buildContextMenu(LLMenuGL& menu, U32 flags) if (LLWearableType::getAllowMultiwear(mWearableType)) { items.push_back(std::string("Wearable Add")); + items.push_back(std::string("Wearable Move Forward")); + items.push_back(std::string("Wearable Move Back")); + + bool is_worn = get_is_item_worn(item->getUUID()); + if(!is_worn || !gAgentWearables.canMoveWearable(item->getUUID(),false)) + disabled_items.push_back(std::string("Wearable Move Forward")); + if(!is_worn || !gAgentWearables.canMoveWearable(item->getUUID(),true)) + disabled_items.push_back(std::string("Wearable Move Back")); + // if (gAgentWearables.getWearableCount(mWearableType) >= LLAgentWearables::MAX_CLOTHING_PER_TYPE) // [SL:KB] - Patch: Appearance-WearableDuplicateAssets | Checked: 2011-07-24 (Catznip-2.6.0e) | Added: Catznip-2.6.0e if ( (gAgentWearables.getWearableCount(mWearableType) >= LLAgentWearables::MAX_CLOTHING_PER_TYPE) || diff --git a/indra/newview/skins/default/xui/en-us/menu_inventory.xml b/indra/newview/skins/default/xui/en-us/menu_inventory.xml index 854a1cd35..6fe3d3d8f 100644 --- a/indra/newview/skins/default/xui/en-us/menu_inventory.xml +++ b/indra/newview/skins/default/xui/en-us/menu_inventory.xml @@ -284,6 +284,14 @@ name="Wearable Add" width="128"> + + + + + + Date: Mon, 11 Jun 2012 06:54:59 -0500 Subject: [PATCH 09/28] Merged baking process with v3 head. Hopefully alleviates some baking oddities pertaining innitial login. --- indra/newview/app_settings/settings.xml | 33 +++ indra/newview/llagent.cpp | 9 +- indra/newview/llagentwearables.cpp | 19 +- indra/newview/llagentwearables.h | 1 + indra/newview/llappearancemgr.cpp | 143 ++++++----- indra/newview/lltexlayer.cpp | 9 +- indra/newview/lltexlayer.h | 1 - indra/newview/llviewerjointmesh.h | 1 + indra/newview/llvoavatar.cpp | 307 +++++++++++++++++------- indra/newview/llvoavatar.h | 19 +- indra/newview/llvoavatarself.cpp | 66 ++++- indra/newview/llvoavatarself.h | 15 +- indra/newview/llwearable.cpp | 2 +- 13 files changed, 449 insertions(+), 176 deletions(-) diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index cf09680e1..e2db9c442 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -13290,6 +13290,39 @@ Value 20.0 + TexelPixelRatio + + Comment + texel pixel ratio = texel / pixel + Persist + 1 + Type + F32 + Value + 1.0 + + TextureCameraMotionThreshold + + Comment + If the overall motion is lower than this value, textures will be loaded faster + Persist + 1 + Type + F32 + Value + 0.2 + + TextureCameraMotionBoost + + Comment + Progressive discard level decrement when the camera is still + Persist + 1 + Type + S32 + Value + 3 + TextureDecodeDisabled Comment diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index b02fbf71c..8c26e36a5 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -3344,13 +3344,12 @@ void LLAgent::processAgentCachedTextureResponse(LLMessageSystem *mesgsys, void * else { // no cache of this bake. request upload. - gAgentAvatarp->requestLayerSetUpload(baked_index); + gAgentAvatarp->invalidateComposite(gAgentAvatarp->getLayerSet(baked_index),TRUE); } } } } } - llinfos << "Received cached texture response for " << num_results << " textures." << llendl; gAgentAvatarp->outputRezTiming("Fetched agent wearables textures from cache. Will now load them"); @@ -3885,7 +3884,7 @@ void LLAgent::sendAgentSetAppearance() return; } - llinfos << "TAT: Sent AgentSetAppearance: " << gAgentAvatarp->getBakedStatusForPrintout() << llendl; + LL_INFOS("Avatar") << gAgentAvatarp->avString() << "TAT: Sent AgentSetAppearance: " << gAgentAvatarp->getBakedStatusForPrintout() << LL_ENDL; //dumpAvatarTEs( "sendAgentSetAppearance()" ); LLMessageSystem* msg = gMessageSystem; @@ -3943,14 +3942,14 @@ void LLAgent::sendAgentSetAppearance() // only update cache entries if we have all our baked textures if (textures_current) { - llinfos << "TAT: Sending cached texture data" << llendl; + LL_INFOS("Avatar") << gAgentAvatarp->avString() << "TAT: Sending cached texture data" << LL_ENDL; for (U8 baked_index = 0; baked_index < BAKED_NUM_INDICES; baked_index++) { BOOL generate_valid_hash = TRUE; if (isAgentAvatarValid() && !gAgentAvatarp->isBakedTextureFinal((LLVOAvatarDefines::EBakedTextureIndex)baked_index)) { generate_valid_hash = FALSE; - llinfos << "Not caching baked texture upload for " << (U32)baked_index << " due to being uploaded at low resolution." << llendl; + LL_DEBUGS("Avatar") << gAgentAvatarp->avString() << "Not caching baked texture upload for " << (U32)baked_index << " due to being uploaded at low resolution." << LL_ENDL; } const LLUUID hash = gAgentWearables.computeBakedTextureHash((EBakedTextureIndex) baked_index, generate_valid_hash); diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp index ad5333323..c264b73a7 100644 --- a/indra/newview/llagentwearables.cpp +++ b/indra/newview/llagentwearables.cpp @@ -1615,7 +1615,16 @@ void LLAgentWearables::setWearableOutfit(const LLInventoryItem::item_array_t& it { gAgentAvatarp->setCompositeUpdatesEnabled(TRUE); gAgentAvatarp->updateVisualParams(); - gAgentAvatarp->invalidateAll(); + + // If we have not yet declouded, we may want to use + // baked texture UUIDs sent from the first objectUpdate message + // don't overwrite these. If we have already declouded, we've saved + // these ids as the last known good textures and can invalidate without + // re-clouding. + if (!gAgentAvatarp->getIsCloud()) + { + gAgentAvatarp->invalidateAll(); + } } // Start rendering & update the server @@ -1816,7 +1825,8 @@ void LLAgentWearables::queryWearableCache() { gAgentAvatarp->outputRezTiming("Fetching textures from cache"); } - llinfos << "Requesting texture cache entry for " << num_queries << " baked textures" << llendl; + + LL_INFOS("Avatar") << gAgentAvatarp->avString() << "Requesting texture cache entry for " << num_queries << " baked textures" << LL_ENDL; gMessageSystem->sendReliable(gAgent.getRegion()->getHost()); gAgentQueryManager.mNumPendingQueries++; gAgentQueryManager.mWearablesCacheQueryID++; @@ -2345,6 +2355,11 @@ boost::signals2::connection LLAgentWearables::addInitialWearablesLoadedCallback( } // [/SL:KB] +bool LLAgentWearables::changeInProgress() const +{ + return mCOFChangeInProgress; +} + void LLAgentWearables::notifyLoadingStarted() { mCOFChangeInProgress = true; diff --git a/indra/newview/llagentwearables.h b/indra/newview/llagentwearables.h index 36ec572eb..231edc7fb 100644 --- a/indra/newview/llagentwearables.h +++ b/indra/newview/llagentwearables.h @@ -247,6 +247,7 @@ public: boost::signals2::connection addInitialWearablesLoadedCallback(loaded_callback_t cb); // [/SL:KB] + bool changeInProgress() const; void notifyLoadingStarted(); void notifyLoadingFinished(); diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index 1cd4eceb9..7bf71fe36 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -54,6 +54,11 @@ #include "rlvlocks.h" // [/RLVa:KB] +std::string self_av_string() +{ + return gAgentAvatarp->avString(); +} + // RAII thingy to guarantee that a variable gets reset when the Setter // goes out of scope. More general utility would be handy - TODO: // check boost. @@ -160,6 +165,8 @@ public: { mCatID = cat_id; mAppend = append; + + LL_INFOS("Avatar") << self_av_string() << "starting" << LL_ENDL; } void fire(const LLUUID& item_id) { @@ -171,12 +178,13 @@ public: * after the last item has fired the event and dereferenced it -- if all * the events actually fire! */ + LL_DEBUGS("Avatar") << self_av_string() << " fired on copied item, id " << item_id << LL_ENDL; } protected: ~LLWearInventoryCategoryCallback() { - llinfos << "done all inventory callbacks" << llendl; + LL_INFOS("Avatar") << self_av_string() << "done all inventory callbacks" << LL_ENDL; // Is the destructor called by ordinary dereference, or because the app's shutting down? // If the inventory callback manager goes away, we're shutting down, no longer want the callback. @@ -186,7 +194,7 @@ protected: } else { - llwarns << "Dropping unhandled LLWearInventoryCategoryCallback" << llendl; + llwarns << self_av_string() << "Dropping unhandled LLWearInventoryCategoryCallback" << llendl; } } @@ -220,6 +228,7 @@ LLUpdateAppearanceOnDestroy::LLUpdateAppearanceOnDestroy(bool update_base_outfit LLUpdateAppearanceOnDestroy::~LLUpdateAppearanceOnDestroy() { + LL_INFOS("Avatar") << self_av_string() << "done update appearance on destroy" << LL_ENDL; llinfos << "done update appearance on destroy" << llendl; if (!LLApp::isExiting()) @@ -233,7 +242,7 @@ void LLUpdateAppearanceOnDestroy::fire(const LLUUID& inv_item) LLViewerInventoryItem* item = (LLViewerInventoryItem*)gInventory.getItem(inv_item); const std::string item_name = item ? item->getName() : "ITEM NOT FOUND"; #ifndef LL_RELEASE_FOR_DOWNLOAD - llinfos << "callback fired [ name:" << item_name << " UUID:" << inv_item << " count:" << mFireCount << " ] " << llendl; + LL_DEBUGS("Avatar") << self_av_string() << "callback fired [ name:" << item_name << " UUID:" << inv_item << " count:" << mFireCount << " ] " << LL_ENDL; #endif mFireCount++; } @@ -399,7 +408,8 @@ void LLWearableHoldingPattern::checkMissingWearables() { if (!isMostRecent()) { - llwarns << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl; + // runway why don't we actually skip here? + llwarns << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl; } std::vector found_by_type(LLWearableType::WT_COUNT,0); @@ -417,7 +427,7 @@ void LLWearableHoldingPattern::checkMissingWearables() { if (requested_by_type[type] > found_by_type[type]) { - llwarns << "got fewer wearables than requested, type " << type << ": requested " << requested_by_type[type] << ", found " << found_by_type[type] << llendl; + llwarns << self_av_string() << "got fewer wearables than requested, type " << type << ": requested " << requested_by_type[type] << ", found " << found_by_type[type] << llendl; } if (found_by_type[type] > 0) continue; @@ -434,7 +444,7 @@ void LLWearableHoldingPattern::checkMissingWearables() mTypesToRecover.insert(type); mTypesToLink.insert(type); recoverMissingWearable((LLWearableType::EType)type); - llwarns << "need to replace " << type << llendl; + llwarns << self_av_string() << "need to replace " << type << llendl; } } @@ -454,13 +464,14 @@ void LLWearableHoldingPattern::onAllComplete() if (!isMostRecent()) { - llwarns << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl; + // runway need to skip here? + llwarns << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl; } // Activate all gestures in this folder if (mGestItems.count() > 0) { - llinfos << "Activating " << mGestItems.count() << " gestures" << llendl; + LL_DEBUGS("Avatar") << self_av_string() << "Activating " << mGestItems.count() << " gestures" << LL_ENDL; LLGestureMgr::instance().activateGestures(mGestItems); @@ -477,7 +488,7 @@ void LLWearableHoldingPattern::onAllComplete() } // Update wearables. - llinfos << "Updating agent wearables with " << mResolved << " wearable items " << llendl; + LL_INFOS("Avatar") << self_av_string() << "Updating agent wearables with " << mResolved << " wearable items " << LL_ENDL; LLAppearanceMgr::instance().updateAgentWearables(this, false); // [SL:KB] - Patch: Appearance-SyncAttach | Checked: 2010-03-22 (Catznip-3.0.0a) | Added: Catznip-2.1.2a @@ -504,7 +515,8 @@ void LLWearableHoldingPattern::onFetchCompletion() { if (!isMostRecent()) { - llwarns << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl; + // runway skip here? + llwarns << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl; } checkMissingWearables(); @@ -515,7 +527,8 @@ bool LLWearableHoldingPattern::pollFetchCompletion() { if (!isMostRecent()) { - llwarns << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl; + // runway skip here? + llwarns << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl; // [SL:KB] - Patch: Appearance-COFCorruption | Checked: 2010-04-14 (Catznip-3.0.0a) | Added: Catznip-2.0.0a // If we were signalled to stop then we shouldn't do anything else except poll for when it's safe to delete ourselves @@ -530,14 +543,14 @@ bool LLWearableHoldingPattern::pollFetchCompletion() if (done) { - llinfos << "polling, done status: " << completed << " timed out " << timed_out - << " elapsed " << mWaitTime.getElapsedTimeF32() << llendl; + LL_INFOS("Avatar") << self_av_string() << "polling, done status: " << completed << " timed out " << timed_out + << " elapsed " << mWaitTime.getElapsedTimeF32() << LL_ENDL; mFired = true; if (timed_out) { - llwarns << "Exceeded max wait time for wearables, updating appearance based on what has arrived" << llendl; + llwarns << self_av_string() << "Exceeded max wait time for wearables, updating appearance based on what has arrived" << llendl; } onFetchCompletion(); @@ -585,12 +598,12 @@ public: } else { - llwarns << "inventory item not found for recovered wearable" << llendl; + llwarns << self_av_string() << "inventory item not found for recovered wearable" << llendl; } } else { - llwarns << "inventory link not found for recovered wearable" << llendl; + llwarns << self_av_string() << "inventory link not found for recovered wearable" << llendl; } } private: @@ -612,7 +625,8 @@ public: { if (!mHolder->isMostRecent()) { - llwarns << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl; + // runway skip here? + llwarns << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl; // [SL:KB] - Patch: Appearance-COFCorruption | Checked: 2010-04-14 (Catznip-3.0.0a) | Added: Catznip-2.0.0a // If we were signalled to stop then we shouldn't do anything else except poll for when it's safe to delete ourselves @@ -620,7 +634,7 @@ public: // [/SL:KB] } - llinfos << "Recovered item for type " << mType << llendl; + LL_DEBUGS("Avatar") << self_av_string() << "Recovered item for type " << mType << LL_ENDL; LLViewerInventoryItem *itemp = gInventory.getItem(item_id); mWearable->setItemID(item_id); LLPointer cb = new RecoveredItemLinkCB(mType,mWearable,mHolder); @@ -647,7 +661,8 @@ void LLWearableHoldingPattern::recoverMissingWearable(LLWearableType::EType type { if (!isMostRecent()) { - llwarns << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl; + // runway skip here? + llwarns << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl; } // Try to recover by replacing missing wearable with a new one. @@ -686,7 +701,7 @@ void LLWearableHoldingPattern::clearCOFLinksForMissingWearables() if ((data.mWearableType < LLWearableType::WT_COUNT) && (!data.mWearable)) { // Wearable link that was never resolved; remove links to it from COF - llinfos << "removing link for unresolved item " << data.mItemID.asString() << llendl; + LL_INFOS("Avatar") << self_av_string() << "removing link for unresolved item " << data.mItemID.asString() << LL_ENDL; LLAppearanceMgr::instance().removeCOFItemLinks(data.mItemID,false); } } @@ -709,7 +724,8 @@ bool LLWearableHoldingPattern::pollMissingWearables() { if (!isMostRecent()) { - llwarns << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl; + // runway skip here? + llwarns << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl; // [SL:KB] - Patch: Appearance-COFCorruption | Checked: 2010-04-14 (Catznip-3.0.0a) | Added: Catznip-2.0.0a // If we were signalled to stop then we shouldn't do anything else except poll for when it's safe to delete ourselves @@ -724,11 +740,11 @@ bool LLWearableHoldingPattern::pollMissingWearables() if (!done) { - llinfos << "polling missing wearables, waiting for items " << mTypesToRecover.size() + LL_INFOS("Avatar") << self_av_string() << "polling missing wearables, waiting for items " << mTypesToRecover.size() << " links " << mTypesToLink.size() << " wearables, timed out " << timed_out << " elapsed " << mWaitTime.getElapsedTimeF32() - << " done " << done << llendl; + << " done " << done << LL_ENDL; } if (done) @@ -762,14 +778,14 @@ void LLWearableHoldingPattern::handleLateArrivals() } if (!isMostRecent()) { - llwarns << "Late arrivals not handled - outfit change no longer valid" << llendl; + llwarns << self_av_string() << "Late arrivals not handled - outfit change no longer valid" << llendl; } if (!mIsAllComplete) { - llwarns << "Late arrivals not handled - in middle of missing wearables processing" << llendl; + llwarns << self_av_string() << "Late arrivals not handled - in middle of missing wearables processing" << llendl; } - llinfos << "Need to handle " << mLateArrivals.size() << " late arriving wearables" << llendl; + LL_INFOS("Avatar") << self_av_string() << "Need to handle " << mLateArrivals.size() << " late arriving wearables" << LL_ENDL; // Update mFoundList using late-arriving wearables. std::set replaced_types; @@ -845,19 +861,19 @@ void LLWearableHoldingPattern::onWearableAssetFetch(LLWearable *wearable) { if (!isMostRecent()) { - llwarns << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl; + llwarns << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl; } mResolved += 1; // just counting callbacks, not successes. - llinfos << "resolved " << mResolved << "/" << getFoundList().size() << llendl; + LL_DEBUGS("Avatar") << self_av_string() << "resolved " << mResolved << "/" << getFoundList().size() << LL_ENDL; if (!wearable) { - llwarns << "no wearable found" << llendl; + llwarns << self_av_string() << "no wearable found" << llendl; } if (mFired) { - llwarns << "called after holder fired" << llendl; + llwarns << self_av_string() << "called after holder fired" << llendl; if (wearable) { mLateArrivals.insert(wearable); @@ -883,7 +899,7 @@ void LLWearableHoldingPattern::onWearableAssetFetch(LLWearable *wearable) // Failing this means inventory or asset server are corrupted in a way we don't handle. if ((data.mWearableType >= LLWearableType::WT_COUNT) || (wearable->getType() != data.mWearableType)) { - llwarns << "recovered wearable but type invalid. inventory wearable type: " << data.mWearableType << " asset wearable type: " << wearable->getType() << llendl; + llwarns << self_av_string() << "recovered wearable but type invalid. inventory wearable type: " << data.mWearableType << " asset wearable type: " << wearable->getType() << llendl; break; } @@ -1554,7 +1570,7 @@ void LLAppearanceMgr::linkAll(const LLUUID& cat_uuid, const LLViewerInventoryCategory *cat = gInventory.getCategory(cat_uuid); const std::string cat_name = cat ? cat->getName() : "CAT NOT FOUND"; #ifndef LL_RELEASE_FOR_DOWNLOAD - llinfos << "Linking Item [ name:" << item->getName() << " UUID:" << item->getUUID() << " ] to Category [ name:" << cat_name << " UUID:" << cat_uuid << " ] " << llendl; + LL_DEBUGS("Avatar") << self_av_string() << "Linking Item [ name:" << item->getName() << " UUID:" << item->getUUID() << " ] to Category [ name:" << cat_name << " UUID:" << cat_uuid << " ] " << LL_ENDL; #endif } } @@ -1685,7 +1701,7 @@ void LLAppearanceMgr::updateCOF(LLInventoryModel::item_array_t& body_items_new, removeDuplicateItems(gest_items); // Create links to new COF contents. - llinfos << "creating LLUpdateAppearanceOnDestroy" << llendl; + LL_DEBUGS("Avatar") << self_av_string() << "creating LLUpdateAppearanceOnDestroy" << LL_ENDL; LLPointer link_waiter = new LLUpdateAppearanceOnDestroy(!append); // [SL:KB] - Checked: 2010-04-24 (RLVa-1.2.0f) | Added: RLVa-1.2.0f @@ -1696,24 +1712,24 @@ void LLAppearanceMgr::updateCOF(LLInventoryModel::item_array_t& body_items_new, bool keep_outfit_links = append; purgeCategory(cof, keep_outfit_links); gInventory.notifyObservers(); - #ifndef LL_RELEASE_FOR_DOWNLOAD - llinfos << "Linking body items" << llendl; - #endif - linkAll(cof, body_items, link_waiter); +#ifndef LL_RELEASE_FOR_DOWNLOAD + LL_DEBUGS("Avatar") << self_av_string() << "Linking body items" << LL_ENDL; +#endif + linkAll(cof, body_items, link_waiter); - #ifndef LL_RELEASE_FOR_DOWNLOAD - llinfos << "Linking wear items" << llendl; - #endif - linkAll(cof, wear_items, link_waiter); +#ifndef LL_RELEASE_FOR_DOWNLOAD + LL_DEBUGS("Avatar") << self_av_string() << "Linking wear items" << LL_ENDL; +#endif + linkAll(cof, wear_items, link_waiter); - #ifndef LL_RELEASE_FOR_DOWNLOAD - llinfos << "Linking obj items" << llendl; - #endif - linkAll(cof, obj_items, link_waiter); +#ifndef LL_RELEASE_FOR_DOWNLOAD + LL_DEBUGS("Avatar") << self_av_string() << "Linking obj items" << LL_ENDL; +#endif + linkAll(cof, obj_items, link_waiter); - #ifndef LL_RELEASE_FOR_DOWNLOAD - llinfos << "Linking gesture items" << llendl; - #endif +#ifndef LL_RELEASE_FOR_DOWNLOAD + LL_DEBUGS("Avatar") << self_av_string() << "Linking gesture items" << LL_ENDL; +#endif linkAll(cof, gest_items, link_waiter); // [SL:KB] - Checked: 2010-04-24 (RLVa-1.2.0f) | Added: RLVa-1.2.0f } @@ -1741,7 +1757,7 @@ void LLAppearanceMgr::updateCOF(LLInventoryModel::item_array_t& body_items_new, // createBaseOutfitLink(category, link_waiter); // } - llinfos << "waiting for LLUpdateAppearanceOnDestroy" << llendl; + LL_DEBUGS("Avatar") << self_av_string() << "waiting for LLUpdateAppearanceOnDestroy" << LL_ENDL; } void LLAppearanceMgr::updatePanelOutfitName(const std::string& name) @@ -1954,7 +1970,7 @@ void LLAppearanceMgr::enforceItemRestrictions() ++it) { LLViewerInventoryItem *item = *it; - llinfos << "purging duplicate or excess item " << item->getName() << llendl; + LL_DEBUGS("Avatar") << self_av_string() << "purging duplicate or excess item " << item->getName() << LL_ENDL; gInventory.purgeObject(item->getUUID()); } gInventory.notifyObservers(); @@ -1971,7 +1987,7 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering) BoolSetter setIsInUpdateAppearanceFromCOF(mIsInUpdateAppearanceFromCOF); - llinfos << "starting" << llendl; + LL_INFOS("Avatar") << self_av_string() << "starting" << LL_ENDL; //checking integrity of the COF in terms of ordering of wearables, //checking and updating links' descriptions of wearables in the COF (before analyzed for "dirty" state) @@ -2125,7 +2141,7 @@ void LLAppearanceMgr::updateAppearanceFromCOF(bool update_base_outfit_ordering) { LLFoundData& found = *it; - lldebugs << "waiting for onWearableAssetFetch callback, asset " << found.mAssetID.asString() << llendl; + lldebugs << self_av_string() << "waiting for onWearableAssetFetch callback, asset " << found.mAssetID.asString() << llendl; // Fetch the wearables about to be worn. LLWearableList::instance().getAsset(found.mAssetID, @@ -2214,8 +2230,8 @@ void LLAppearanceMgr::wearInventoryCategory(LLInventoryCategory* category, bool gAgentWearables.notifyLoadingStarted(); - llinfos << "wearInventoryCategory( " << category->getName() - << " )" << llendl; + LL_INFOS("Avatar") << self_av_string() << "wearInventoryCategory( " << category->getName() + << " )" << LL_ENDL; callAfterCategoryFetch(category->getUUID(),boost::bind(&LLAppearanceMgr::wearCategoryFinal, &LLAppearanceMgr::instance(), @@ -2224,7 +2240,7 @@ void LLAppearanceMgr::wearInventoryCategory(LLInventoryCategory* category, bool void LLAppearanceMgr::wearCategoryFinal(LLUUID& cat_id, bool copy_items, bool append) { - llinfos << "starting" << llendl; + LL_INFOS("Avatar") << self_av_string() << "starting" << LL_ENDL; // We now have an outfit ready to be copied to agent inventory. Do // it, and wear that outfit normally. @@ -2307,8 +2323,8 @@ void LLAppearanceMgr::wearInventoryCategoryOnAvatar( LLInventoryCategory* catego // wearables being dirty. if(!category) return; - llinfos << "wearInventoryCategoryOnAvatar( " << category->getName() - << " )" << llendl; + LL_INFOS("Avatar") << self_av_string() << "wearInventoryCategoryOnAvatar '" << category->getName() + << "'" << LL_ENDL; if (gAgentCamera.cameraCustomizeAvatar()) { @@ -2321,7 +2337,7 @@ void LLAppearanceMgr::wearInventoryCategoryOnAvatar( LLInventoryCategory* catego void LLAppearanceMgr::wearOutfitByName(const std::string& name) { - llinfos << "Wearing category " << name << llendl; + LL_INFOS("Avatar") << self_av_string() << "Wearing category " << name << LL_ENDL; //inc_busy_count(); LLInventoryModel::cat_array_t cat_array; @@ -2651,7 +2667,7 @@ const std::string OTHER_GESTURES_FOLDER = "Other Gestures"; void LLAppearanceMgr::copyLibraryGestures() { - llinfos << "Copying library gestures" << llendl; + LL_INFOS("Avatar") << self_av_string() << "Copying library gestures" << LL_ENDL; // Copy gestures LLUUID lib_gesture_cat_id = @@ -2707,11 +2723,11 @@ void LLAppearanceMgr::copyLibraryGestures() LLUUID cat_id = findDescendentCategoryIDByName(lib_gesture_cat_id,folder_name); if (cat_id.isNull()) { - llwarns << "failed to find gesture folder for " << folder_name << llendl; + llwarns << self_av_string() << "failed to find gesture folder for " << folder_name << llendl; } else { - llinfos << "initiating fetch and copy for " << folder_name << " cat_id " << cat_id << llendl; + LL_DEBUGS("Avatar") << self_av_string() << "initiating fetch and copy for " << folder_name << " cat_id " << cat_id << LL_ENDL; callAfterCategoryFetch(cat_id, boost::bind(&LLAppearanceMgr::shallowCopyCategory, &LLAppearanceMgr::instance(), @@ -2725,7 +2741,7 @@ void LLAppearanceMgr::autopopulateOutfits() // If this is the very first time the user has logged into viewer2+ (from a legacy viewer, or new account) // then auto-populate outfits from the library into the My Outfits folder. - llinfos << "avatar fully visible" << llendl; + LL_INFOS("Avatar") << self_av_string() << "avatar fully visible" << LL_ENDL; static bool check_populate_my_outfits = true; if (check_populate_my_outfits && @@ -3454,9 +3470,8 @@ void LLAppearanceMgr::dumpItemArray(const LLInventoryModel::item_array_t& items, { asset_id = linked_item->getAssetUUID(); } - llinfos << msg << " " << i <<" " << (item ? item->getName() : "(nullitem)") << " " << asset_id.asString() << llendl; + LL_DEBUGS("Avatar") << self_av_string() << msg << " " << i <<" " << (item ? item->getName() : "(nullitem)") << " " << asset_id.asString() << LL_ENDL; } - llinfos << llendl; } LLAppearanceMgr::LLAppearanceMgr(): diff --git a/indra/newview/lltexlayer.cpp b/indra/newview/lltexlayer.cpp index 3ed7d65e0..2b6195521 100644 --- a/indra/newview/lltexlayer.cpp +++ b/indra/newview/lltexlayer.cpp @@ -55,6 +55,9 @@ using namespace LLVOAvatarDefines; static const S32 BAKE_UPLOAD_ATTEMPTS = 7; static const F32 BAKE_UPLOAD_RETRY_DELAY = 2.f; // actual delay grows by power of 2 each attempt +// runway consolidate +extern std::string self_av_string(); + class LLTexLayerInfo { friend class LLTexLayer; @@ -495,7 +498,7 @@ void LLTexLayerSetBuffer::doUpload() } LLPointer compressedImage = new LLImageJ2C; - compressedImage->setRate(0.f); + //compressedImage->setRate(0.f); const char* comment_text = LINDEN_J2C_COMMENT_PREFIX "RGBHM"; // writes into baked_color_data. 5 channels (rgb, heightfield/alpha, mask) if (compressedImage->encode(baked_image, comment_text)) { @@ -578,7 +581,7 @@ void LLTexLayerSetBuffer::doUpload() args["BODYREGION"] = mTexLayerSet->getBodyRegionName(); args["RESOLUTION"] = lod_str; LLNotificationsUtil::add("AvatarRezSelfBakedTextureUploadNotification",args); - llinfos << "Uploading [ name: " << mTexLayerSet->getBodyRegionName() << " res:" << lod_str << " time:" << (U32)mNeedsUploadTimer.getElapsedTimeF32() << " ]" << llendl; + LL_DEBUGS("Avatar") << self_av_string() << "Uploading [ name: " << mTexLayerSet->getBodyRegionName() << " res:" << lod_str << " time:" << (U32)mNeedsUploadTimer.getElapsedTimeF32() << " ]" << LL_ENDL; } } else @@ -632,7 +635,7 @@ void LLTexLayerSetBuffer::doUpdate() args["BODYREGION"] = mTexLayerSet->getBodyRegionName(); args["RESOLUTION"] = lod_str; LLNotificationsUtil::add("AvatarRezSelfBakedTextureUpdateNotification",args); - llinfos << "Locally updating [ name: " << mTexLayerSet->getBodyRegionName() << " res:" << lod_str << " time:" << (U32)mNeedsUpdateTimer.getElapsedTimeF32() << " ]" << llendl; + LL_DEBUGS("Avatar") << self_av_string() << "Locally updating [ name: " << mTexLayerSet->getBodyRegionName() << " res:" << lod_str << " time:" << (U32)mNeedsUpdateTimer.getElapsedTimeF32() << " ]" << LL_ENDL; } } diff --git a/indra/newview/lltexlayer.h b/indra/newview/lltexlayer.h index f220b68d0..4f43547da 100644 --- a/indra/newview/lltexlayer.h +++ b/indra/newview/lltexlayer.h @@ -31,7 +31,6 @@ #include "lldynamictexture.h" #include "llvoavatardefines.h" #include "lltexlayerparams.h" -#include "lllocaltextureobject.h" class LLVOAvatar; class LLVOAvatarSelf; diff --git a/indra/newview/llviewerjointmesh.h b/indra/newview/llviewerjointmesh.h index 0191f0cae..dd5dae1dc 100644 --- a/indra/newview/llviewerjointmesh.h +++ b/indra/newview/llviewerjointmesh.h @@ -61,6 +61,7 @@ public: //----------------------------------------------------------------------------- class LLViewerJointMesh : public LLViewerJoint { + friend class LLVOAvatar; protected: LLColor4 mColor; // color value // LLColor4 mSpecular; // specular color (always white for now) diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 775250cf9..c3fb3bc6e 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -1044,6 +1044,7 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id, mNeedsSkin(FALSE), mLastSkinTime(0.f), mUpdatePeriod(1), + mFirstFullyVisible(TRUE), mFullyLoaded(FALSE), mPreviousFullyLoaded(FALSE), mFullyLoadedInitialized(FALSE), @@ -1051,6 +1052,7 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id, mLoadedCallbacksPaused(FALSE), mHasPelvisOffset( FALSE ), mRenderUnloadedAvatar(LLCachedControl(gSavedSettings, "RenderUnloadedAvatar")), + mLastRezzedStatus(-1), mFirstSetActualBoobGravRan( false ), mSupportsPhysics( false ), // @@ -1137,33 +1139,45 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id, mLastPelvisFixup = 0.0f; } -//------------------------------------------------------------------------ -// LLVOAvatar::~LLVOAvatar() -//------------------------------------------------------------------------ +std::string LLVOAvatar::avString() const +{ + std::string viz_string = LLVOAvatar::rezStatusToString(getRezzedStatus()); + return " Avatar '" + getFullname() + "' " + viz_string + " "; +} + +void LLVOAvatar::debugAvatarRezTime(std::string notification_name, std::string comment) +{ + LL_INFOS("Avatar") << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() + << "sec ]" + << avString() + << "RuthTimer " << (U32)mRuthDebugTimer.getElapsedTimeF32() + << " Notification " << notification_name + << " : " << comment + << llendl; + + if (gSavedSettings.getBOOL("DebugAvatarRezTime")) + { + LLSD args; + args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32()); + args["TIME"] = llformat("%d",(U32)mRuthDebugTimer.getElapsedTimeF32()); + args["NAME"] = getFullname(); + LLNotificationsUtil::add(notification_name,args); + } +} LLVOAvatar::~LLVOAvatar() { //App teardown is a mess. Avatar destruction can be unpredictable due to all potential refs to the smartptr. //Cannot guarantee that LLNotificationUtil will be usable during shutdown chain. - if (!LLApp::isQuitting() && gSavedSettings.getBOOL("DebugAvatarRezTime")) + if (!LLApp::isQuitting()) { if (!mFullyLoaded) { - llinfos << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() << "sec ] Avatar '" << getFullname() << "' left after " << (U32)mRuthDebugTimer.getElapsedTimeF32() << " seconds as cloud." << llendl; - LLSD args; - args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32()); - args["TIME"] = llformat("%d",(U32)mRuthDebugTimer.getElapsedTimeF32()); - args["NAME"] = getFullname(); - LLNotificationsUtil::add("AvatarRezLeftCloudNotification",args); + debugAvatarRezTime("AvatarRezLeftCloudNotification","left after ruth seconds as cloud"); } else { - llinfos << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() << "sec ] Avatar '" << getFullname() << "' left." << llendl; - LLSD args; - args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32()); - args["NAME"] = getFullname(); - LLNotificationsUtil::add("AvatarRezLeftNotification",args); + debugAvatarRezTime("AvatarRezLeftNotification","left sometime after declouding"); } - } lldebugs << "LLVOAvatar Destructor (0x" << this << ") id:" << mID << llendl; @@ -1248,6 +1262,55 @@ BOOL LLVOAvatar::isFullyBaked() return TRUE; } +BOOL LLVOAvatar::isFullyTextured() const +{ + for (U32 i = 0; i < (U32)mMeshLOD.size(); i++) + { + LLViewerJoint* joint = (LLViewerJoint*) mMeshLOD[i]; + if (i==MESH_ID_SKIRT && !isWearingWearableType(LLWearableType::WT_SKIRT)) + { + continue; // don't care about skirt textures if we're not wearing one. + } + if (!joint) + { + continue; // nonexistent LOD OK. + } + std::vector::iterator meshIter = joint->mMeshParts.begin(); + if (meshIter != joint->mMeshParts.end()) + { + LLViewerJointMesh *mesh = (LLViewerJointMesh *) *meshIter; + if (!mesh) + { + continue; // nonexistent mesh OK + } + if (mesh->mTexture.notNull() && mesh->mTexture->hasGLTexture()) + { + continue; // Mesh exists and has a baked texture. + } + if (mesh->mLayerSet && mesh->mLayerSet->hasComposite()) + { + continue; // Mesh exists and has a composite texture. + } + // Fail + return FALSE; + } + } + return TRUE; +} + +BOOL LLVOAvatar::hasGray() const +{ + return !getIsCloud() && !isFullyTextured(); +} + +S32 LLVOAvatar::getRezzedStatus() const +{ + if (getIsCloud()) return 0; + if (isFullyTextured()) return 2; + llassert(hasGray()); + return 1; // gray +} + void LLVOAvatar::deleteLayerSetCaches(bool clearAll) { for (U32 i = 0; i < mBakedTextureDatas.size(); i++) @@ -1294,6 +1357,31 @@ BOOL LLVOAvatar::areAllNearbyInstancesBaked(S32& grey_avatars) return res; } +// static +void LLVOAvatar::getNearbyRezzedStats(std::vector& counts) +{ + counts.clear(); + counts.resize(3); + for (std::vector::iterator iter = LLCharacter::sInstances.begin(); + iter != LLCharacter::sInstances.end(); ++iter) + { + LLVOAvatar* inst = (LLVOAvatar*) *iter; + if (!inst) + continue; + S32 rez_status = inst->getRezzedStatus(); + counts[rez_status]++; + } +} + +// static +std::string LLVOAvatar::rezStatusToString(S32 rez_status) +{ + if (rez_status==0) return "cloud"; + if (rez_status==1) return "gray"; + if (rez_status==2) return "textured"; + return "unknown"; +} + // static void LLVOAvatar::getMeshInfo (mesh_info_t* mesh_info) { @@ -2669,18 +2757,12 @@ U32 LLVOAvatar::processUpdateMessage(LLMessageSystem *mesgsys, U32 retval = LLViewerObject::processUpdateMessage(mesgsys, user_data, block_num, update_type, dp); // Print out arrival information once we have name of avatar. - if (gSavedSettings.getBOOL("DebugAvatarRezTime")) + if (has_name && getNVPair("FirstName")) { - if (has_name && getNVPair("FirstName")) - { - mDebugExistenceTimer.reset(); - LLSD args; - args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32()); - args["NAME"] = getFullname(); - LLNotificationsUtil::add("AvatarRezArrivedNotification",args); - llinfos << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() << "sec ] Avatar '" << getFullname() << "' arrived." << llendl; - } + mDebugExistenceTimer.reset(); + debugAvatarRezTime("AvatarRezArrivedNotification","avatar arrived"); } + if(retval & LLViewerObject::INVALID_UPDATE) { if(isSelf()) @@ -3258,16 +3340,16 @@ void LLVOAvatar::idleUpdateLoadingEffect() // update visibility when avatar is partially loaded if (updateIsFullyLoaded()) // changed? { - if (isFullyLoaded() && isSelf()) + if (isFullyLoaded() && mFirstFullyVisible && isSelf()) { - static bool first_fully_visible = true; - if (first_fully_visible) - { - llinfos << "self isFullyLoaded, first_fully_visible" << llendl; - - first_fully_visible = false; - LLAppearanceMgr::instance().onFirstFullyVisible(); - } + LL_INFOS("Avatar") << avString() << "self isFullyLoaded, mFirstFullyVisible" << LL_ENDL; + mFirstFullyVisible = FALSE; + LLAppearanceMgr::instance().onFirstFullyVisible(); + } + if (isFullyLoaded() && mFirstFullyVisible && !isSelf()) + { + LL_INFOS("Avatar") << avString() << "other isFullyLoaded, mFirstFullyVisible" << LL_ENDL; + mFirstFullyVisible = FALSE; } if (isFullyLoaded()) { @@ -3576,26 +3658,15 @@ void LLVOAvatar::idleUpdateNameTagText(BOOL new_name) bool is_friend = LLAvatarTracker::instance().isBuddy(getID()); bool is_cloud = getIsCloud(); - if (gSavedSettings.getBOOL("DebugAvatarRezTime")) + if (is_appearance != mNameAppearance) { - if (is_appearance != mNameAppearance) + if (is_appearance) { - if (is_appearance) - { - LLSD args; - args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32()); - args["NAME"] = getFullname(); - LLNotificationsUtil::add("AvatarRezEnteredAppearanceNotification",args); - llinfos << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() << "sec ] Avatar '" << getFullname() << "' entered appearance mode." << llendl; - } - else - { - LLSD args; - args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32()); - args["NAME"] = getFullname(); - LLNotificationsUtil::add("AvatarRezLeftAppearanceNotification",args); - llinfos << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() << "sec ] Avatar '" << getFullname() << "' left appearance mode." << llendl; - } + debugAvatarRezTime("AvatarRezEnteredAppearanceNotification","entered appearance mode"); + } + else + { + debugAvatarRezTime("AvatarRezLeftAppearanceNotification","left appearance mode"); } } @@ -4617,7 +4688,7 @@ void LLVOAvatar::updateVisibility() LLNameValue* firstname = getNVPair("FirstName"); if (firstname) { - llinfos << "Avatar " << firstname->getString() << " updating visiblity" << llendl; + LL_DEBUGS("Avatar") << avString() << " updating visibility" << LL_ENDL; } else { @@ -4789,7 +4860,7 @@ U32 LLVOAvatar::renderSkinned(EAvatarRenderPass pass) LLNameValue* firstname = getNVPair("FirstName"); if (firstname) { - llinfos << "Avatar " << firstname->getString() << " in render" << llendl; + LL_DEBUGS("Avatar") << avString() << " in render" << LL_ENDL; } else { @@ -7366,10 +7437,10 @@ BOOL LLVOAvatar::isVisible() const } // Determine if we have enough avatar data to render -BOOL LLVOAvatar::getIsCloud() +BOOL LLVOAvatar::getIsCloud() const { // Do we have a shape? - if (visualParamWeightsAreDefault()) + if ((const_cast(this))->visualParamWeightsAreDefault()) { return TRUE; } @@ -7388,11 +7459,53 @@ BOOL LLVOAvatar::getIsCloud() return FALSE; } +void LLVOAvatar::updateRezzedStatusTimers() +{ + // State machine for rezzed status. Statuses are 0 = cloud, 1 = gray, 2 = textured. + // Purpose is to collect time data for each period of cloud or cloud+gray. + S32 rez_status = getRezzedStatus(); + if (rez_status != mLastRezzedStatus) + { + LL_DEBUGS("Avatar") << avString() << "rez state change: " << mLastRezzedStatus << " -> " << rez_status << LL_ENDL; + /*bool is_cloud_or_gray = (rez_status==0 || rez_status==1); + bool was_cloud_or_gray = (mLastRezzedStatus==0 || mLastRezzedStatus==1); + bool is_cloud = (rez_status==0); + bool was_cloud = (mLastRezzedStatus==0); + + ]// Non-cloud to cloud + if (is_cloud && !was_cloud) + { + // start cloud timer. + getPhases().startPhase("cloud"); + } + else if (was_cloud && !is_cloud) + { + // stop cloud timer, which will capture stats. + getPhases().stopPhase("cloud"); + } + + // Non-cloud-or-gray to cloud-or-gray + if (is_cloud_or_gray && !was_cloud_or_gray) + { + // start cloud-or-gray timer. + getPhases().startPhase("cloud-or-gray"); + } + else if (was_cloud_or_gray && !is_cloud_or_gray) + { + // stop cloud-or-gray timer, which will capture stats. + getPhases().stopPhase("cloud-or-gray"); + }*/ + + mLastRezzedStatus = rez_status; + } +} + // call periodically to keep isFullyLoaded up to date. // returns true if the value has changed. BOOL LLVOAvatar::updateIsFullyLoaded() { const BOOL loading = getIsCloud(); + updateRezzedStatusTimers(); updateRuthTimer(loading); return processFullyLoadedChange(loading); } @@ -7407,27 +7520,19 @@ void LLVOAvatar::updateRuthTimer(bool loading) if (mPreviousFullyLoaded) { mRuthTimer.reset(); - if (gSavedSettings.getBOOL("DebugAvatarRezTime")) - { - llinfos << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() << "sec ] Avatar '" << getFullname() << "' became cloud." << llendl; - LLSD args; - args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32()); - args["TIME"] = llformat("%d",(U32)mRuthDebugTimer.getElapsedTimeF32()); - args["NAME"] = getFullname(); - LLNotificationsUtil::add("AvatarRezCloudNotification",args); - } - mRuthDebugTimer.reset(); + debugAvatarRezTime("AvatarRezCloudNotification","became cloud"); } const F32 LOADING_TIMEOUT__SECONDS = 120.f; if (mRuthTimer.getElapsedTimeF32() > LOADING_TIMEOUT__SECONDS) { - llinfos << "Ruth Timer timeout: Missing texture data for '" << getFullname() << "' " + LL_DEBUGS("Avatar") << avString() + << "Ruth Timer timeout: Missing texture data for '" << getFullname() << "' " << "( Params loaded : " << !visualParamWeightsAreDefault() << " ) " << "( Lower : " << isTextureDefined(TEX_LOWER_BAKED) << " ) " << "( Upper : " << isTextureDefined(TEX_UPPER_BAKED) << " ) " << "( Head : " << isTextureDefined(TEX_HEAD_BAKED) << " )." - << llendl; + << LL_ENDL; LLAvatarPropertiesProcessor::getInstance()->sendAvatarTexturesRequest(getID()); mRuthTimer.reset(); @@ -7444,20 +7549,13 @@ BOOL LLVOAvatar::processFullyLoadedChange(bool loading) mFullyLoaded = (mFullyLoadedTimer.getElapsedTimeF32() > PAUSE); - if (gSavedSettings.getBOOL("DebugAvatarRezTime")) + if (!mPreviousFullyLoaded && !loading && mFullyLoaded) { - if (!mPreviousFullyLoaded && !loading && mFullyLoaded) - { - llinfos << "REZTIME: [ " << (U32)mDebugExistenceTimer.getElapsedTimeF32() << "sec ] Avatar '" << getFullname() << "' resolved in " << (U32)mRuthDebugTimer.getElapsedTimeF32() << " seconds." << llendl; - LLSD args; - args["EXISTENCE"] = llformat("%d",(U32)mDebugExistenceTimer.getElapsedTimeF32()); - args["TIME"] = llformat("%d",(U32)mRuthDebugTimer.getElapsedTimeF32()); - args["NAME"] = getFullname(); - LLNotificationsUtil::add("AvatarRezNotification",args); - } + debugAvatarRezTime("AvatarRezNotification","fully loaded"); } // did our loading state "change" from last call? + // runway - why are we updating every 30 calls even if nothing has changed? const S32 UPDATE_RATE = 30; BOOL changed = ((mFullyLoaded != mPreviousFullyLoaded) || // if the value is different from the previous call @@ -7909,8 +8007,8 @@ LLColor4 LLVOAvatar::getDummyColor() } void LLVOAvatar::dumpAvatarTEs( const std::string& context ) const -{ - llinfos << (isSelf() ? "Self: " : "Other: ") << context << llendl; +{ + LL_DEBUGS("Avatar") << avString() << (isSelf() ? "Self: " : "Other: ") << context << LL_ENDL; for (LLVOAvatarDictionary::Textures::const_iterator iter = LLVOAvatarDictionary::getInstance()->getTextures().begin(); iter != LLVOAvatarDictionary::getInstance()->getTextures().end(); ++iter) @@ -7920,27 +8018,27 @@ void LLVOAvatar::dumpAvatarTEs( const std::string& context ) const const LLViewerTexture* te_image = getImage(iter->first,0); if( !te_image ) { - llinfos << " " << texture_dict->mName << ": null ptr" << llendl; + LL_DEBUGS("Avatar") << avString() << " " << texture_dict->mName << ": null ptr" << LL_ENDL; } else if( te_image->getID().isNull() ) { - llinfos << " " << texture_dict->mName << ": null UUID" << llendl; + LL_DEBUGS("Avatar") << avString() << " " << texture_dict->mName << ": null UUID" << LL_ENDL; } else if( te_image->getID() == IMG_DEFAULT ) { - llinfos << " " << texture_dict->mName << ": IMG_DEFAULT" << llendl; + LL_DEBUGS("Avatar") << avString() << " " << texture_dict->mName << ": IMG_DEFAULT" << LL_ENDL; } else if (te_image->getID() == IMG_INVISIBLE) { - llinfos << " " << texture_dict->mName << ": IMG_INVISIBLE" << llendl; + LL_DEBUGS("Avatar") << avString() << " " << texture_dict->mName << ": IMG_INVISIBLE" << LL_ENDL; } else if( te_image->getID() == IMG_DEFAULT_AVATAR ) { - llinfos << " " << texture_dict->mName << ": IMG_DEFAULT_AVATAR" << llendl; + LL_DEBUGS("Avatar") << avString() << " " << texture_dict->mName << ": IMG_DEFAULT_AVATAR" << LL_ENDL; } else { - llinfos << " " << texture_dict->mName << ": " << te_image->getID() << llendl; + LL_DEBUGS("Avatar") << avString() << " " << texture_dict->mName << ": " << te_image->getID() << LL_ENDL; } } } @@ -8071,6 +8169,7 @@ void LLVOAvatar::rebuildHUD() //----------------------------------------------------------------------------- void LLVOAvatar::onFirstTEMessageReceived() { + LL_INFOS("Avatar") << avString() << LL_ENDL; if( !mFirstTEMessageReceived ) { mFirstTEMessageReceived = TRUE; @@ -8099,6 +8198,7 @@ void LLVOAvatar::onFirstTEMessageReceived() image->setLoadedCallback( onBakedTextureMasksLoaded, MORPH_MASK_REQUESTED_DISCARD, TRUE, TRUE, new LLTextureMaskData( mID ), src_callback_list, paused); } + LL_DEBUGS("Avatar") << avString() << "layer_baked, setting onInitialBakedTextureLoaded as callback" << LL_ENDL; image->setLoadedCallback( onInitialBakedTextureLoaded, MAX_DISCARD_LEVEL, FALSE, FALSE, new LLUUID( mID ), src_callback_list, paused ); } @@ -8157,14 +8257,16 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys ) LLMemType mt(LLMemType::MTYPE_AVATAR); -// llinfos << "processAvatarAppearance start " << mID << llendl; BOOL is_first_appearance_message = !mFirstAppearanceMessageReceived; - mFirstAppearanceMessageReceived = TRUE; + LL_INFOS("Avatar") << avString() << "processAvatarAppearance start " << mID + << " first? " << is_first_appearance_message << " self? " << isSelf() << LL_ENDL; + + if( isSelf() ) { - llwarns << "Received AvatarAppearance for self" << llendl; + llwarns << avString() << "Received AvatarAppearance for self" << llendl; if( mFirstTEMessageReceived ) { // llinfos << "processAvatarAppearance end " << mID << llendl; @@ -8229,6 +8331,7 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys ) S32 num_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_VisualParam); if( num_blocks > 1 ) { + LL_DEBUGS("Avatar") << avString() << " handle visual params, num_blocks " << num_blocks << LL_ENDL; BOOL params_changed = FALSE; BOOL interp_params = FALSE; @@ -8476,6 +8579,11 @@ void LLVOAvatar::onInitialBakedTextureLoaded( BOOL success, LLViewerFetchedTextu { LLUUID *avatar_idp = (LLUUID *)userdata; LLVOAvatar *selfp = gObjectList.findAvatar(*avatar_idp); + + if (selfp) + { + LL_DEBUGS("Avatar") << selfp->avString() << "discard_level " << discard_level << " success " << success << " final " << final << LL_ENDL; + } if (!success && selfp) { @@ -8487,13 +8595,20 @@ void LLVOAvatar::onInitialBakedTextureLoaded( BOOL success, LLViewerFetchedTextu } } -void LLVOAvatar::onBakedTextureLoaded(BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata) +// Static +void LLVOAvatar::onBakedTextureLoaded(BOOL success, + LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, + S32 discard_level, BOOL final, void* userdata) { //llinfos << "onBakedTextureLoaded: " << src_vi->getID() << llendl; LLUUID id = src_vi->getID(); LLUUID *avatar_idp = (LLUUID *)userdata; LLVOAvatar *selfp = gObjectList.findAvatar(*avatar_idp); + if (selfp) + { + LL_DEBUGS("Avatar") << selfp->avString() << "discard_level " << discard_level << " success " << success << " final " << final << " id " << src_vi->getID() << LL_ENDL; + } if (selfp && !success) { @@ -8525,6 +8640,7 @@ void LLVOAvatar::useBakedTexture( const LLUUID& id ) LLViewerTexture* image_baked = getImage( mBakedTextureDatas[i].mTextureIndex, 0 ); if (id == image_baked->getID()) { + LL_DEBUGS("Avatar") << avString() << " i " << i << " id " << id << LL_ENDL; mBakedTextureDatas[i].mIsLoaded = true; mBakedTextureDatas[i].mLastTextureIndex = id; mBakedTextureDatas[i].mIsUsed = true; @@ -8608,6 +8724,11 @@ void LLVOAvatar::dumpArchetypeXML( void* ) } apr_file_printf( file, "\t\n" ); apr_file_printf( file, "\n\n" ); + //explictly close the file if it is still open which it should be + if (file) + { + outfile.close(); + } } @@ -9492,7 +9613,9 @@ void LLVOAvatar::idleUpdateRenderCost() } } - setDebugText(llformat("%d", cost)); + + std::string viz_string = LLVOAvatar::rezStatusToString(getRezzedStatus()); + setDebugText(llformat("%s %d", viz_string.c_str(), cost)); mVisualComplexity = cost; F32 green = 1.f-llclamp(((F32) cost-(F32)ARC_LIMIT)/(F32)ARC_LIMIT, 0.f, 1.f); F32 red = llmin((F32) cost/(F32)ARC_LIMIT, 1.f); diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index 87e23906c..34815d555 100644 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -326,14 +326,21 @@ public: public: BOOL isFullyLoaded() const; bool visualParamWeightsAreDefault(); + virtual BOOL getIsCloud() const; + BOOL isFullyTextured() const; + BOOL hasGray() const; + S32 getRezzedStatus() const; // 0 = cloud, 1 = gray, 2 = fully textured. + void updateRezzedStatusTimers(); + + S32 mLastRezzedStatus; protected: - virtual BOOL getIsCloud(); BOOL updateIsFullyLoaded(); BOOL processFullyLoadedChange(bool loading); void updateRuthTimer(bool loading); F32 calcMorphAmount(); private: + BOOL mFirstFullyVisible; BOOL mFullyLoaded; BOOL mPreviousFullyLoaded; BOOL mFullyLoadedInitialized; @@ -567,9 +574,10 @@ public: virtual BOOL isTextureVisible(LLVOAvatarDefines::ETextureIndex type, U32 index = 0) const; virtual BOOL isTextureVisible(LLVOAvatarDefines::ETextureIndex type, LLWearable *wearable) const; -protected: BOOL isFullyBaked(); static BOOL areAllNearbyInstancesBaked(S32& grey_avatars); + static void getNearbyRezzedStats(std::vector& counts); + static std::string rezStatusToString(S32 status); //-------------------------------------------------------------------- // Baked textures @@ -600,9 +608,6 @@ protected: bakedtexturedata_vec_t mBakedTextureDatas; LLLoadedCallbackEntry::source_callback_list_t mCallbackTextureList ; BOOL mLoadedCallbacksPaused; - -public: - const BakedTextureData& getBakedTextureData(LLVOAvatarDefines::ETextureIndex idx) const {return mBakedTextureDatas[idx];} //-------------------------------------------------------------------- // Local Textures //-------------------------------------------------------------------- @@ -980,6 +985,7 @@ private: public: std::string getFullname() const; // Returns "FirstName LastName" + std::string avString() const; // Frequently used string in log messages "Avatar '* labels); static void getAnimNames(LLDynamicArray* names); @@ -1078,11 +1084,14 @@ private: F32 mAdjustedPixelArea; std::string mDebugText; + //-------------------------------------------------------------------- // Avatar Rez Metrics //-------------------------------------------------------------------- public: + void debugAvatarRezTime(std::string notification_name, std::string comment = ""); F32 debugGetExistenceTimeElapsedF32() const { return mDebugExistenceTimer.getElapsedTimeF32(); } + protected: LLFrameTimer mRuthDebugTimer; // For tracking how long it takes for av to rez LLFrameTimer mDebugExistenceTimer; // Debugging for how long the avatar has been in memory. diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp index 37921cabf..81b76f1bc 100644 --- a/indra/newview/llvoavatarself.cpp +++ b/indra/newview/llvoavatarself.cpp @@ -136,7 +136,8 @@ LLVOAvatarSelf::LLVOAvatarSelf(const LLUUID& id, LLVOAvatar(id, pcode, regionp), mScreenp(NULL), mLastRegionHandle(0), - mRegionCrossingCount(0) + mRegionCrossingCount(0), + mInitialBakesLoaded(false) { gAgentWearables.setAvatarObject(this); gAgentCamera.setAvatarObject(this); @@ -172,6 +173,7 @@ void LLVOAvatarSelf::initInstance() { mDebugBakedTextureTimes[i][0] = -1.0f; mDebugBakedTextureTimes[i][1] = -1.0f; + mInitialBakeIDs[i] = LLUUID::null; } // [RLVa:KB] - Checked: 2010-12-12 (RLVa-1.2.2c) | Added: RLVa-1.2.2c @@ -710,6 +712,40 @@ void LLVOAvatarSelf::stopMotionFromSource(const LLUUID& source_id) } } +//virtual +U32 LLVOAvatarSelf::processUpdateMessage(LLMessageSystem *mesgsys, + void **user_data, + U32 block_num, + const EObjectUpdateType update_type, + LLDataPacker *dp) +{ + U32 retval = LLVOAvatar::processUpdateMessage(mesgsys,user_data,block_num,update_type,dp); + + if (mInitialBakesLoaded == false && retval == 0x0) + { + // call update textures to force the images to be created + updateMeshTextures(); + + // unpack the texture UUIDs to the texture slots + retval = unpackTEMessage(mesgsys, _PREHASH_ObjectData, block_num); + + // need to trigger a few operations to get the avatar to use the new bakes + for (U32 i = 0; i < mBakedTextureDatas.size(); i++) + { + const LLVOAvatarDefines::ETextureIndex te = mBakedTextureDatas[i].mTextureIndex; + LLUUID texture_id = getTEImage(te)->getID(); + setNewBakedTexture(te, texture_id); + mInitialBakeIDs[i] = texture_id; + } + + onFirstTEMessageReceived(); + + mInitialBakesLoaded = true; + } + + return retval; +} + void LLVOAvatarSelf::setLocalTextureTE(U8 te, LLViewerTexture* image, U32 index) { if (te >= TEX_NUM_INDICES) @@ -1908,7 +1944,7 @@ void LLVOAvatarSelf::dumpTotalLocalTextureByteCount() llinfos << "Total Avatar LocTex GL:" << (gl_bytes/1024) << "KB" << llendl; } -BOOL LLVOAvatarSelf::getIsCloud() +BOOL LLVOAvatarSelf::getIsCloud() const { // do we have our body parts? if (gAgentWearables.getWearableCount(LLWearableType::WT_SHAPE) == 0 || @@ -2369,6 +2405,18 @@ void LLVOAvatarSelf::setCachedBakedTexture( ETextureIndex te, const LLUUID& uuid { if ( mBakedTextureDatas[i].mTextureIndex == te && mBakedTextureDatas[i].mTexLayerSet) { + if (mInitialBakeIDs[i] != LLUUID::null) + { + if (mInitialBakeIDs[i] == uuid) + { + llinfos << "baked texture correctly loaded at login! " << i << llendl; + } + else + { + llwarns << "baked texture does not match id loaded at login!" << i << llendl; + } + mInitialBakeIDs[i] = LLUUID::null; + } mBakedTextureDatas[i].mTexLayerSet->cancelUpload(); } } @@ -2496,6 +2544,20 @@ LLTexLayerSet* LLVOAvatarSelf::getLayerSet(ETextureIndex index) const return NULL; } +LLTexLayerSet* 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 mBakedTextureDatas[baked_index].mTexLayerSet; + } + return NULL; +} + + // static void LLVOAvatarSelf::onCustomizeStart() { diff --git a/indra/newview/llvoavatarself.h b/indra/newview/llvoavatarself.h index adb2874eb..0105315ff 100644 --- a/indra/newview/llvoavatarself.h +++ b/indra/newview/llvoavatarself.h @@ -93,15 +93,27 @@ public: /*virtual*/ void updateVisualParams(); /*virtual*/ void idleUpdateAppearanceAnimation(); + /*virtual*/ U32 processUpdateMessage(LLMessageSystem *mesgsys, + void **user_data, + U32 block_num, + const EObjectUpdateType update_type, + LLDataPacker *dp); + private: // helper function. Passed in param is assumed to be in avatar's parameter list. BOOL setParamWeight(LLViewerVisualParam *param, F32 weight, BOOL upload_bake = FALSE ); + /** Initialization ** ** *******************************************************************************/ +private: + LLUUID mInitialBakeIDs[6]; + bool mInitialBakesLoaded; + + /******************************************************************************** ** ** ** STATE @@ -121,7 +133,7 @@ public: // Loading state //-------------------------------------------------------------------- public: - /*virtual*/ BOOL getIsCloud(); + /*virtual*/ BOOL getIsCloud() const; //-------------------------------------------------------------------- // Region state @@ -229,6 +241,7 @@ public: void requestLayerSetUpload(LLVOAvatarDefines::EBakedTextureIndex i); void requestLayerSetUpdate(LLVOAvatarDefines::ETextureIndex i); LLTexLayerSet* getLayerSet(LLVOAvatarDefines::ETextureIndex index) const; + LLTexLayerSet* getLayerSet(LLVOAvatarDefines::EBakedTextureIndex baked_index) const; //-------------------------------------------------------------------- // Composites diff --git a/indra/newview/llwearable.cpp b/indra/newview/llwearable.cpp index d8e8792bc..c40351d23 100644 --- a/indra/newview/llwearable.cpp +++ b/indra/newview/llwearable.cpp @@ -608,7 +608,7 @@ BOOL LLWearable::isDirty() const if( a != b ) { - llwarns << "param ID " << param->getID() << " was changed." << llendl; + //llwarns << "param ID " << param->getID() << " was changed." << llendl; return TRUE; } } From 945c663359f33ddea35ca477e00198fdfa8f297c Mon Sep 17 00:00:00 2001 From: Shyotl Date: Mon, 11 Jun 2012 06:57:54 -0500 Subject: [PATCH 10/28] Updated LLInventoryModelBackgroundFetch and LLInventoryModel(code migration) --- indra/newview/llfolderview.cpp | 4 +- indra/newview/llfolderviewitem.cpp | 2 +- indra/newview/llinventorybridge.cpp | 230 +++++---- indra/newview/llinventoryfilter.cpp | 2 +- indra/newview/llinventoryfunctions.cpp | 112 +---- indra/newview/llinventoryfunctions.h | 11 - indra/newview/llinventorymodel.cpp | 181 ++++++- indra/newview/llinventorymodel.h | 17 +- .../llinventorymodelbackgroundfetch.cpp | 465 ++++++++++++------ .../newview/llinventorymodelbackgroundfetch.h | 20 +- indra/newview/llinventorypanel.cpp | 2 +- indra/newview/llpanelmaininventory.cpp | 2 +- 12 files changed, 637 insertions(+), 411 deletions(-) diff --git a/indra/newview/llfolderview.cpp b/indra/newview/llfolderview.cpp index 6f638b695..f7ba56bf8 100644 --- a/indra/newview/llfolderview.cpp +++ b/indra/newview/llfolderview.cpp @@ -957,7 +957,7 @@ void LLFolderView::draw() else if (mShowEmptyMessage) { static LLCachedControl sSearchStatusColor(gColors, "InventorySearchStatusColor", LLColor4::white ); - if (LLInventoryModelBackgroundFetch::instance().backgroundFetchActive() || mCompletedFilterGeneration < mFilter->getMinRequiredGeneration()) + if (LLInventoryModelBackgroundFetch::instance().folderFetchActive() || mCompletedFilterGeneration < mFilter->getMinRequiredGeneration()) { mStatusText = std::string("Searching..."); // *TODO:translate } @@ -2003,7 +2003,7 @@ void LLFolderView::scrollToShowSelection() // However we allow scrolling for folder views with mAutoSelectOverride // (used in Places SP) as an exception because the selection in them // is not reset during items filtering. See STORM-133. - if ( (!LLInventoryModelBackgroundFetch::instance().backgroundFetchActive() || mAutoSelectOverride) + if ( (!LLInventoryModelBackgroundFetch::instance().folderFetchActive() || mAutoSelectOverride) && mSelectedItems.size() ) { mNeedsScroll = TRUE; diff --git a/indra/newview/llfolderviewitem.cpp b/indra/newview/llfolderviewitem.cpp index ae48372e3..3c59b36fe 100644 --- a/indra/newview/llfolderviewitem.cpp +++ b/indra/newview/llfolderviewitem.cpp @@ -1049,7 +1049,7 @@ void LLFolderViewItem::draw() } if ((mIsLoading && mTimeSinceRequestStart.getElapsedTimeF32() >= gSavedSettings.getF32("FolderLoadingMessageWaitTime")) - || (LLInventoryModelBackgroundFetch::instance().backgroundFetchActive() + || (LLInventoryModelBackgroundFetch::instance().folderFetchActive() && root_is_loading && mShowLoadStatus)) { diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index d0ffee5c9..126f38464 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -200,6 +200,42 @@ bool isMarketplaceSendAction(const std::string& action) return ("send_to_marketplace" == action); } +// Used by LLFolderBridge as callback for directory fetching recursion +class LLRightClickInventoryFetchDescendentsObserver : public LLInventoryFetchDescendentsObserver +{ +public: + LLRightClickInventoryFetchDescendentsObserver(const uuid_vec_t& ids) : LLInventoryFetchDescendentsObserver(ids) {} + ~LLRightClickInventoryFetchDescendentsObserver() {} + virtual void execute(bool clear_observer = false); + virtual void done() + { + execute(true); + } +}; + +// Used by LLFolderBridge as callback for directory content items fetching +class LLRightClickInventoryFetchObserver : public LLInventoryFetchItemsObserver +{ +public: + LLRightClickInventoryFetchObserver(const uuid_vec_t& ids) : LLInventoryFetchItemsObserver(ids) { }; + ~LLRightClickInventoryFetchObserver() {} + void execute(bool clear_observer = false) + { + if (clear_observer) + { + dec_busy_count(); + gInventory.removeObserver(this); + delete this; + } + // we've downloaded all the items, so repaint the dialog + LLFolderBridge::staticFolderOptionsMenu(); + } + virtual void done() + { + execute(true); + } +}; + // void gotImageForSaveItemAs(BOOL success, LLViewerTexture *src_vi, @@ -1050,7 +1086,7 @@ void LLInvFVBridge::changeItemParent(LLInventoryModel* model, const LLUUID& new_parent_id, BOOL restamp) { - change_item_parent(model, item, new_parent_id, restamp); + model->changeItemParent(item, new_parent_id, restamp); } // static @@ -1059,7 +1095,7 @@ void LLInvFVBridge::changeCategoryParent(LLInventoryModel* model, const LLUUID& new_parent_id, BOOL restamp) { - change_category_parent(model, cat, new_parent_id, restamp); + model->changeCategoryParent(cat, new_parent_id, restamp); } LLInvFVBridge* LLInvFVBridge::createBridge(LLAssetType::EType asset_type, @@ -1464,7 +1500,8 @@ void LLItemBridge::selectItem() // if(!(gInventory.isObjectDescendentOf(mUUID, gSystemFolderRoot))) // - item->fetchFromServer(); + //item->fetchFromServer(); + LLInventoryModelBackgroundFetch::instance().start(item->getUUID(), false); } } @@ -2498,9 +2535,16 @@ BOOL move_inv_category_world_to_agent(const LLUUID& object_id, LLInventoryObject::object_list_t::iterator end = inventory_objects.end(); for ( ; it != end; ++it) { + LLInventoryItem* item = dynamic_cast(it->get()); + if (!item) + { + llwarns << "Invalid inventory item for drop" << llendl; + continue; + } + // coming from a task. Need to figure out if the person can // move/copy this item. - LLPermissions perm(((LLInventoryItem*)((LLInventoryObject*)(*it)))->getPermissions()); + LLPermissions perm(item->getPermissions()); if((perm.allowCopyBy(gAgent.getID(), gAgent.getGroupID()) && perm.allowTransferTo(gAgent.getID()))) // || gAgent.isGodlike()) @@ -2553,121 +2597,114 @@ BOOL move_inv_category_world_to_agent(const LLUUID& object_id, return accept; } -//Used by LLFolderBridge as callback for directory recursion. -class LLRightClickInventoryFetchObserver : public LLInventoryFetchItemsObserver +void LLRightClickInventoryFetchDescendentsObserver::execute(bool clear_observer) { -public: - LLRightClickInventoryFetchObserver(const uuid_vec_t& ids) : - LLInventoryFetchItemsObserver(ids), - mCopyItems(false) - { }; - LLRightClickInventoryFetchObserver(const uuid_vec_t& ids, - const LLUUID& cat_id, - bool copy_items) : - LLInventoryFetchItemsObserver(ids), - mCatID(cat_id), - mCopyItems(copy_items) - { }; - virtual void done() - { - // we've downloaded all the items, so repaint the dialog - LLFolderBridge::staticFolderOptionsMenu(); - - gInventory.removeObserver(this); - delete this; - } - -protected: - LLUUID mCatID; - bool mCopyItems; - -}; - -//Used by LLFolderBridge as callback for directory recursion. -class LLRightClickInventoryFetchDescendentsObserver : public LLInventoryFetchDescendentsObserver -{ -public: - LLRightClickInventoryFetchDescendentsObserver(const uuid_vec_t& ids, - bool copy_items) : - LLInventoryFetchDescendentsObserver(ids), - mCopyItems(copy_items) - {} - ~LLRightClickInventoryFetchDescendentsObserver() {} - virtual void done(); -protected: - bool mCopyItems; -}; - -void LLRightClickInventoryFetchDescendentsObserver::done() -{ - // Avoid passing a NULL-ref as mCompleteFolders.front() down to - // gInventory.collectDescendents() + // Bail out immediately if no descendents if( mComplete.empty() ) { llwarns << "LLRightClickInventoryFetchDescendentsObserver::done with empty mCompleteFolders" << llendl; + if (clear_observer) + { dec_busy_count(); gInventory.removeObserver(this); delete this; + } return; } - // What we do here is get the complete information on the items in - // the library, and set up an observer that will wait for that to - // happen. - LLInventoryModel::cat_array_t cat_array; - LLInventoryModel::item_array_t item_array; - gInventory.collectDescendents(mComplete.front(), - cat_array, - item_array, - LLInventoryModel::EXCLUDE_TRASH); - S32 count = item_array.count(); -#if 0 // HACK/TODO: Why? - // This early causes a giant menu to get produced, and doesn't seem to be needed. - if(!count) + // Copy the list of complete fetched folders while "this" is still valid + uuid_vec_t completed_folder = mComplete; + + // Clean up, and remove this as an observer now since recursive calls + // could notify observers and throw us into an infinite loop. + if (clear_observer) { - llwarns << "Nothing fetched in category " << mComplete.front() - << llendl; dec_busy_count(); gInventory.removeObserver(this); delete this; - return; } -#endif - uuid_vec_t ids; - for(S32 i = 0; i < count; ++i) + for (uuid_vec_t::iterator current_folder = completed_folder.begin(); current_folder != completed_folder.end(); ++current_folder) { - ids.push_back(item_array.get(i)->getUUID()); + // Get the information on the fetched folder items and subfolders and fetch those + LLInventoryModel::cat_array_t* cat_array; + LLInventoryModel::item_array_t* item_array; + gInventory.getDirectDescendentsOf(*current_folder, cat_array, item_array); + + S32 item_count = item_array->count(); + S32 cat_count = cat_array->count(); + + // Move to next if current folder empty + if ((item_count == 0) && (cat_count == 0)) + { + continue; } - LLRightClickInventoryFetchObserver* outfit = new LLRightClickInventoryFetchObserver(ids, mComplete.front(), mCopyItems); + uuid_vec_t ids; + LLRightClickInventoryFetchObserver* outfit = NULL; + LLRightClickInventoryFetchDescendentsObserver* categories = NULL; - // clean up, and remove this as an observer since the call to the - // outfit could notify observers and throw us into an infinite - // loop. - dec_busy_count(); - gInventory.removeObserver(this); - delete this; + // Fetch the items + if (item_count) + { + for (S32 i = 0; i < item_count; ++i) + { + ids.push_back(item_array->get(i)->getUUID()); + } + outfit = new LLRightClickInventoryFetchObserver(ids); + } + // Fetch the subfolders + if (cat_count) + { + for (S32 i = 0; i < cat_count; ++i) + { + ids.push_back(cat_array->get(i)->getUUID()); + } + categories = new LLRightClickInventoryFetchDescendentsObserver(ids); + } - // increment busy count and either tell the inventory to check & - // call done, or add this object to the inventory for observation. - inc_busy_count(); - - // do the fetch + // Perform the item fetch + if (outfit) + { outfit->startFetch(); - outfit->done(); //Not interested in waiting and this will be right 99% of the time. + outfit->execute(); // Not interested in waiting and this will be right 99% of the time. + delete outfit; //Uncomment the following code for laggy Inventory UI. -/* if(outfit->isEverythingComplete()) + /* + if (outfit->isFinished()) { - // everything is already here - call done. - outfit->done(); + // everything is already here - call done. + outfit->execute(); + delete outfit; } else { - // it's all on it's way - add an observer, and the inventory - // will call done for us when everything is here. - gInventory.addObserver(outfit); - }*/ + // it's all on its way - add an observer, and the inventory + // will call done for us when everything is here. + inc_busy_count(); + gInventory.addObserver(outfit); + } + */ + } + // Perform the subfolders fetch : this is where we truly recurse down the folder hierarchy + if (categories) + { + categories->startFetch(); + if (categories->isFinished()) + { + // everything is already here - call done. + categories->execute(); + delete categories; + } + else + { + // it's all on its way - add an observer, and the inventory + // will call done for us when everything is here. + inc_busy_count(); + gInventory.addObserver(categories); + } + } + } } @@ -2980,7 +3017,7 @@ bool LLFolderBridge::removeItemResponse(const LLSD& notification, const LLSD& re { // move it to the trash LLPreview::hide(mUUID); - remove_category(getInventoryModel(), mUUID); + getInventoryModel()->removeCategory(mUUID); return TRUE; } return FALSE; @@ -3336,16 +3373,19 @@ void LLFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags) folders.push_back(category->getUUID()); sSelf = getHandle(); - LLRightClickInventoryFetchDescendentsObserver* fetch = new LLRightClickInventoryFetchDescendentsObserver(folders, FALSE); + LLRightClickInventoryFetchDescendentsObserver* fetch = new LLRightClickInventoryFetchDescendentsObserver(folders); fetch->startFetch(); - inc_busy_count(); if (fetch->isFinished()) { + // Do not call execute() or done() here as if the folder is here, there's likely no point drilling down + // This saves lots of time as buildContextMenu() is called a lot + delete fetch; buildContextMenuFolderOptions(flags); } else { // it's all on its way - add an observer, and the inventory will call done for us when everything is here. + inc_busy_count(); gInventory.addObserver(fetch); } } diff --git a/indra/newview/llinventoryfilter.cpp b/indra/newview/llinventoryfilter.cpp index a5bd75877..828ad5689 100644 --- a/indra/newview/llinventoryfilter.cpp +++ b/indra/newview/llinventoryfilter.cpp @@ -795,7 +795,7 @@ const std::string& LLInventoryFilter::getFilterText() filtered_by_all_types = FALSE; } - if (!LLInventoryModelBackgroundFetch::instance().backgroundFetchActive() + if (!LLInventoryModelBackgroundFetch::instance().folderFetchActive() && filtered_by_type && !filtered_by_all_types) { diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index b4724536d..14c2de40f 100644 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -110,97 +110,6 @@ void append_path(const LLUUID& id, std::string& path) path.append(temp); } -void change_item_parent(LLInventoryModel* model, - LLViewerInventoryItem* item, - const LLUUID& new_parent_id, - BOOL restamp) -{ - // - bool send_parent_update = gInventory.isObjectDescendentOf(item->getUUID(), gInventory.getRootFolderID()); - // - if(item->getParentUUID() != new_parent_id) - { - LLInventoryModel::update_list_t update; - LLInventoryModel::LLCategoryUpdate old_folder(item->getParentUUID(),-1); - update.push_back(old_folder); - LLInventoryModel::LLCategoryUpdate new_folder(new_parent_id, 1); - update.push_back(new_folder); - gInventory.accountForUpdate(update); - - LLPointer new_item = new LLViewerInventoryItem(item); - new_item->setParent(new_parent_id); - // - if(send_parent_update) - // - new_item->updateParentOnServer(restamp); - model->updateItem(new_item); - model->notifyObservers(); - } -} - -void change_category_parent(LLInventoryModel* model, - LLViewerInventoryCategory* cat, - const LLUUID& new_parent_id, - BOOL restamp) -{ - if (!model || !cat) - { - return; - } - - // Can't move a folder into a child of itself. - if (model->isObjectDescendentOf(new_parent_id, cat->getUUID())) - { - return; - } - - LLInventoryModel::update_list_t update; - LLInventoryModel::LLCategoryUpdate old_folder(cat->getParentUUID(), -1); - update.push_back(old_folder); - LLInventoryModel::LLCategoryUpdate new_folder(new_parent_id, 1); - update.push_back(new_folder); - model->accountForUpdate(update); - - LLPointer new_cat = new LLViewerInventoryCategory(cat); - new_cat->setParent(new_parent_id); - new_cat->updateParentOnServer(restamp); - model->updateCategory(new_cat); - model->notifyObservers(); -} - -void remove_category(LLInventoryModel* model, const LLUUID& cat_id) -{ - if (!model || !get_is_category_removable(model, cat_id)) - { - return; - } - - // Look for any gestures and deactivate them - LLInventoryModel::cat_array_t descendent_categories; - LLInventoryModel::item_array_t descendent_items; - gInventory.collectDescendents(cat_id, descendent_categories, descendent_items, FALSE); - - for (LLInventoryModel::item_array_t::const_iterator iter = descendent_items.begin(); - iter != descendent_items.end(); - ++iter) - { - const LLViewerInventoryItem* item = (*iter); - const LLUUID& item_id = item->getUUID(); - if (item->getType() == LLAssetType::AT_GESTURE - && LLGestureMgr::instance().isGestureActive(item_id)) - { - LLGestureMgr::instance().deactivateGesture(item_id); - } - } - - LLViewerInventoryCategory* cat = gInventory.getCategory(cat_id); - if (cat) - { - const LLUUID trash_id = model->findCategoryUUIDForType(LLFolderType::FT_TRASH); - change_category_parent(model, cat, trash_id, TRUE); - } -} - void rename_category(LLInventoryModel* model, const LLUUID& cat_id, const std::string& new_name) { LLViewerInventoryCategory* cat; @@ -553,8 +462,7 @@ void move_to_outbox_cb_action(const LLSD& payload) LLUUID parent = viitem->getParentUUID(); - change_item_parent( - &gInventory, + gInventory.changeItemParent( viitem, dest_folder_id, false); @@ -581,7 +489,7 @@ void move_to_outbox_cb_action(const LLSD& payload) if (cat_array->empty() && item_array->empty()) { - remove_category(&gInventory, parent); + gInventory.removeCategory(parent); } if (parent == top_level_folder) @@ -655,7 +563,7 @@ void move_item_within_outbox(LLInventoryItem* inv_item, LLUUID dest_folder, S32 LLViewerInventoryItem * viewer_inv_item = (LLViewerInventoryItem *) inv_item; - change_item_parent(&gInventory, + gInventory.changeItemParent( viewer_inv_item, dest_folder, false); @@ -976,20 +884,24 @@ void LLSaveFolderState::setApply(BOOL apply) void LLSaveFolderState::doFolder(LLFolderViewFolder* folder) { + LLInvFVBridge* bridge = (LLInvFVBridge*)folder->getListener(); + if(!bridge) return; + if(mApply) { // we're applying the open state - LLInvFVBridge* bridge = (LLInvFVBridge*)folder->getListener(); - if(!bridge) return; LLUUID id(bridge->getUUID()); if(mOpenFolders.find(id) != mOpenFolders.end()) { - folder->setOpen(TRUE); + if (!folder->isOpen()) + { + folder->setOpen(TRUE); + } } else { // keep selected filter in its current state, this is less jarring to user - if (!folder->isSelected()) + if (!folder->isSelected() && folder->isOpen()) { folder->setOpen(FALSE); } @@ -1000,8 +912,6 @@ void LLSaveFolderState::doFolder(LLFolderViewFolder* folder) // we're recording state at this point if(folder->isOpen()) { - LLInvFVBridge* bridge = (LLInvFVBridge*)folder->getListener(); - if(!bridge) return; mOpenFolders.insert(bridge->getUUID()); } } diff --git a/indra/newview/llinventoryfunctions.h b/indra/newview/llinventoryfunctions.h index 689f5f1a2..99d1ef24b 100644 --- a/indra/newview/llinventoryfunctions.h +++ b/indra/newview/llinventoryfunctions.h @@ -55,17 +55,6 @@ BOOL get_is_category_renameable(const LLInventoryModel* model, const LLUUID& id) void show_item_profile(const LLUUID& item_uuid); -void change_item_parent(LLInventoryModel* model, - LLViewerInventoryItem* item, - const LLUUID& new_parent_id, - BOOL restamp); - -void change_category_parent(LLInventoryModel* model, - LLViewerInventoryCategory* cat, - const LLUUID& new_parent_id, - BOOL restamp); - -void remove_category(LLInventoryModel* model, const LLUUID& cat_id); void rename_category(LLInventoryModel* model, const LLUUID& cat_id, const std::string& new_name); // Generates a string containing the path to the item specified by item_id. diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index a2060a2a1..50234039e 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -46,6 +46,8 @@ #include "llviewerregion.h" #include "llcallbacklist.h" #include "llvoavatarself.h" +#include "llgesturemgr.h" +#include #include "statemachine/aievent.h" // [RLVa:KB] - Checked: 2011-05-22 (RLVa-1.3.1a) @@ -1080,6 +1082,72 @@ void LLInventoryModel::moveObject(const LLUUID& object_id, const LLUUID& cat_id) } } +// Migrated from llinventoryfunctions +void LLInventoryModel::changeItemParent(LLViewerInventoryItem* item, + const LLUUID& new_parent_id, + BOOL restamp) +{ + // + bool send_parent_update = gInventory.isObjectDescendentOf(item->getUUID(), gInventory.getRootFolderID()); + // + if (item->getParentUUID() == new_parent_id) + { + LL_DEBUGS("Inventory") << "'" << item->getName() << "' (" << item->getUUID() + << ") is already in folder " << new_parent_id << LL_ENDL; + } + else + { + LL_INFOS("Inventory") << "Moving '" << item->getName() << "' (" << item->getUUID() + << ") from " << item->getParentUUID() << " to folder " + << new_parent_id << LL_ENDL; + LLInventoryModel::update_list_t update; + LLInventoryModel::LLCategoryUpdate old_folder(item->getParentUUID(),-1); + update.push_back(old_folder); + LLInventoryModel::LLCategoryUpdate new_folder(new_parent_id, 1); + update.push_back(new_folder); + accountForUpdate(update); + + LLPointer new_item = new LLViewerInventoryItem(item); + new_item->setParent(new_parent_id); + // + if(send_parent_update) + // + new_item->updateParentOnServer(restamp); + updateItem(new_item); + notifyObservers(); + } +} + +// Migrated from llinventoryfunctions +void LLInventoryModel::changeCategoryParent(LLViewerInventoryCategory* cat, + const LLUUID& new_parent_id, + BOOL restamp) +{ + if (!cat) + { + return; + } + + // Can't move a folder into a child of itself. + if (isObjectDescendentOf(new_parent_id, cat->getUUID())) + { + return; + } + + LLInventoryModel::update_list_t update; + LLInventoryModel::LLCategoryUpdate old_folder(cat->getParentUUID(), -1); + update.push_back(old_folder); + LLInventoryModel::LLCategoryUpdate new_folder(new_parent_id, 1); + update.push_back(new_folder); + accountForUpdate(update); + + LLPointer new_cat = new LLViewerInventoryCategory(cat); + new_cat->setParent(new_parent_id); + new_cat->updateParentOnServer(restamp); + updateCategory(new_cat); + notifyObservers(); +} + // Delete a particular inventory object by ID. void LLInventoryModel::deleteObject(const LLUUID& id) { @@ -1208,13 +1276,12 @@ void LLInventoryModel::purgeDescendentsOf(const LLUUID& id) items, INCLUDE_TRASH); S32 count = items.count(); - S32 i; - for(i = 0; i < count; ++i) + for(S32 i = 0; i < count; ++i) { deleteObject(items.get(i)->getUUID()); } count = categories.count(); - for(i = 0; i < count; ++i) + for(S32 i = 0; i < count; ++i) { deleteObject(categories.get(i)->getUUID()); } @@ -1729,6 +1796,7 @@ bool LLInventoryModel::loadSkeleton( update_map_t child_counts; cat_array_t categories; item_array_t items; + item_array_t possible_broken_links; cat_set_t invalid_categories; // Used to mark categories that weren't successfully loaded. std::string owner_id_str; owner_id.toString(owner_id_str); @@ -1815,6 +1883,8 @@ bool LLInventoryModel::loadSkeleton( // Add all the items loaded which are parented to a // category with a correctly cached parent S32 bad_link_count = 0; + S32 good_link_count = 0; + S32 recovered_link_count = 0; cat_map_t::iterator unparented = mCategoryMap.end(); for(item_array_t::const_iterator item_iter = items.begin(); item_iter != items.end(); @@ -1831,26 +1901,56 @@ bool LLInventoryModel::loadSkeleton( // This can happen if the linked object's baseobj is removed from the cache but the linked object is still in the cache. if (item->getIsBrokenLink()) { - bad_link_count++; + //bad_link_count++; lldebugs << "Attempted to add cached link item without baseobj present ( name: " << item->getName() << " itemID: " << item->getUUID() << " assetID: " << item->getAssetUUID() << " ). Ignoring and invalidating " << cat->getName() << " . " << llendl; - invalid_categories.insert(cit->second); + possible_broken_links.push_back(item); continue; } + else if (item->getIsLinkType()) + { + good_link_count++; + } addItem(item); cached_item_count += 1; ++child_counts[cat->getUUID()]; } } } - if (bad_link_count > 0) + if (possible_broken_links.size() > 0) { - llinfos << "Attempted to add " << bad_link_count - << " cached link items without baseobj present. " - << "The corresponding categories were invalidated." << llendl; + for(item_array_t::const_iterator item_iter = possible_broken_links.begin(); + item_iter != possible_broken_links.end(); + ++item_iter) + { + LLViewerInventoryItem *item = (*item_iter).get(); + const cat_map_t::iterator cit = mCategoryMap.find(item->getParentUUID()); + const LLViewerInventoryCategory* cat = cit->second.get(); + if (item->getIsBrokenLink()) + { + bad_link_count++; + invalid_categories.insert(cit->second); + //llinfos << "link still broken: " << item->getName() << " in folder " << cat->getName() << llendl; + } + else + { + // was marked as broken because of loading order, its actually fine to load + addItem(item); + cached_item_count += 1; + ++child_counts[cat->getUUID()]; + recovered_link_count++; + } + } + + llinfos << "Attempted to add " << bad_link_count + << " cached link items without baseobj present. " + << good_link_count << " link items were successfully added. " + << recovered_link_count << " links added in recovery. " + << "The corresponding categories were invalidated." << llendl; } + } else { @@ -3099,27 +3199,62 @@ void LLInventoryModel::emptyFolderType(const std::string notification, LLFolderT notifyObservers(); } } + +//---------------------------------------------------------------------------- + void LLInventoryModel::removeItem(const LLUUID& item_id) { LLViewerInventoryItem* item = getItem(item_id); - const LLUUID new_parent = findCategoryUUIDForType(LLFolderType::FT_TRASH); - if(item && new_parent.notNull() && item->getParentUUID() != new_parent) + if (! item) { - LLInventoryModel::update_list_t update; - LLInventoryModel::LLCategoryUpdate old_folder(item->getParentUUID(), -1); - update.push_back(old_folder); - LLInventoryModel::LLCategoryUpdate new_folder(new_parent, 1); - update.push_back(new_folder); - accountForUpdate(update); - - LLPointer new_item = new LLViewerInventoryItem(item); - new_item->setParent(new_parent); - new_item->updateParentOnServer(TRUE); - updateItem(new_item); - notifyObservers(); + LL_WARNS("Inventory") << "couldn't find inventory item " << item_id << LL_ENDL; + } + else + { + const LLUUID new_parent = findCategoryUUIDForType(LLFolderType::FT_TRASH); + if (new_parent.notNull()) + { + LL_INFOS("Inventory") << "Moving to Trash (" << new_parent << "):" << LL_ENDL; + changeItemParent(item, new_parent, TRUE); + } } } +void LLInventoryModel::removeCategory(const LLUUID& category_id) +{ + if (! get_is_category_removable(this, category_id)) + { + return; + } + + // Look for any gestures and deactivate them + LLInventoryModel::cat_array_t descendent_categories; + LLInventoryModel::item_array_t descendent_items; + collectDescendents(category_id, descendent_categories, descendent_items, FALSE); + + for (LLInventoryModel::item_array_t::const_iterator iter = descendent_items.begin(); + iter != descendent_items.end(); + ++iter) + { + const LLViewerInventoryItem* item = (*iter); + const LLUUID& item_id = item->getUUID(); + if (item->getType() == LLAssetType::AT_GESTURE + && LLGestureMgr::instance().isGestureActive(item_id)) + { + LLGestureMgr::instance().deactivateGesture(item_id); + } + } + + LLViewerInventoryCategory* cat = getCategory(category_id); + if (cat) + { + const LLUUID trash_id = findCategoryUUIDForType(LLFolderType::FT_TRASH); + if (trash_id.notNull()) + { + changeCategoryParent(cat, trash_id, TRUE); + } + } +} const LLUUID &LLInventoryModel::getRootFolderID() const { return mRootFolderID; diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h index 90e841fef..a7506e19a 100644 --- a/indra/newview/llinventorymodel.h +++ b/indra/newview/llinventorymodel.h @@ -316,6 +316,16 @@ public: // observer notification, or server update is performed. void moveObject(const LLUUID& object_id, const LLUUID& cat_id); + // Migrated from llinventoryfunctions + void changeItemParent(LLViewerInventoryItem* item, + const LLUUID& new_parent_id, + BOOL restamp); + + // Migrated from llinventoryfunctions + void changeCategoryParent(LLViewerInventoryCategory* cat, + const LLUUID& new_parent_id, + BOOL restamp); + //-------------------------------------------------------------------- // Delete //-------------------------------------------------------------------- @@ -325,8 +335,13 @@ public: // consistent internal state. No cache accounting, observer // notification, or server update is performed. void deleteObject(const LLUUID& id); + /// move Item item_id to Trash void removeItem(const LLUUID& item_id); - + /// move Category category_id to Trash + void removeCategory(const LLUUID& category_id); + /// removeItem() or removeCategory(), whichever is appropriate + void removeObject(const LLUUID& object_id); + // Delete a particular inventory object by ID, and delete it from // the server. Also updates linked items. void purgeObject(const LLUUID& id); diff --git a/indra/newview/llinventorymodelbackgroundfetch.cpp b/indra/newview/llinventorymodelbackgroundfetch.cpp index 3fc36a290..74bb12058 100644 --- a/indra/newview/llinventorymodelbackgroundfetch.cpp +++ b/indra/newview/llinventorymodelbackgroundfetch.cpp @@ -43,6 +43,7 @@ const S32 MAX_FETCH_RETRIES = 10; LLInventoryModelBackgroundFetch::LLInventoryModelBackgroundFetch() : mBackgroundFetchActive(FALSE), + mFolderFetchActive(false), mAllFoldersFetched(FALSE), mRecursiveInventoryFetchStarted(FALSE), mRecursiveLibraryFetchStarted(FALSE), @@ -50,7 +51,7 @@ LLInventoryModelBackgroundFetch::LLInventoryModelBackgroundFetch() : mMinTimeBetweenFetches(0.3f), mMaxTimeBetweenFetches(10.f), mTimelyFetchPending(FALSE), - mBulkFetchCount(0) + mFetchCount(0) { } @@ -60,7 +61,7 @@ LLInventoryModelBackgroundFetch::~LLInventoryModelBackgroundFetch() bool LLInventoryModelBackgroundFetch::isBulkFetchProcessingComplete() const { - return mFetchQueue.empty() && mBulkFetchCount<=0; + return mFetchQueue.empty() && mFetchCount<=0; } bool LLInventoryModelBackgroundFetch::libraryFetchStarted() const @@ -98,19 +99,21 @@ bool LLInventoryModelBackgroundFetch::isEverythingFetched() const return mAllFoldersFetched; } -BOOL LLInventoryModelBackgroundFetch::backgroundFetchActive() const +BOOL LLInventoryModelBackgroundFetch::folderFetchActive() const { - return mBackgroundFetchActive; + return mFolderFetchActive; } -void LLInventoryModelBackgroundFetch::start(const LLUUID& cat_id, BOOL recursive) +void LLInventoryModelBackgroundFetch::start(const LLUUID& id, BOOL recursive) { - if (!mAllFoldersFetched || cat_id.notNull()) - { - LL_DEBUGS("InventoryFetch") << "Start fetching category: " << cat_id << ", recursive: " << recursive << LL_ENDL; + LLViewerInventoryCategory* cat = gInventory.getCategory(id); + if (cat || (id.isNull() && !isEverythingFetched())) + { // it's a folder, do a bulk fetch + LL_DEBUGS("InventoryFetch") << "Start fetching category: " << id << ", recursive: " << recursive << LL_ENDL; mBackgroundFetchActive = TRUE; - if (cat_id.isNull()) + mFolderFetchActive = true; + if (id.isNull()) { if (!mRecursiveInventoryFetchStarted) { @@ -128,42 +131,41 @@ void LLInventoryModelBackgroundFetch::start(const LLUUID& cat_id, BOOL recursive else { // Specific folder requests go to front of queue. - if (mFetchQueue.empty() || mFetchQueue.front().mCatUUID != cat_id) + if (mFetchQueue.empty() || mFetchQueue.front().mUUID != id) { - mFetchQueue.push_front(FetchQueueInfo(cat_id, recursive)); + mFetchQueue.push_front(FetchQueueInfo(id, recursive)); gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL); } - if (cat_id == gInventory.getLibraryRootFolderID()) + if (id == gInventory.getLibraryRootFolderID()) { mRecursiveLibraryFetchStarted |= recursive; } - if (cat_id == gInventory.getRootFolderID()) + if (id == gInventory.getRootFolderID()) { mRecursiveInventoryFetchStarted |= recursive; } } } + else if (LLViewerInventoryItem* itemp = gInventory.getItem(id)) + { + if (!itemp->mIsComplete && (mFetchQueue.empty() || mFetchQueue.front().mUUID != id)) + { + mBackgroundFetchActive = TRUE; + + mFetchQueue.push_front(FetchQueueInfo(id, false, false)); + gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL); + } + } } -//static void LLInventoryModelBackgroundFetch::findLostItems() { mBackgroundFetchActive = TRUE; + mFolderFetchActive = true; mFetchQueue.push_back(FetchQueueInfo(LLUUID::null, TRUE)); gIdleCallbacks.addFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL); } -void LLInventoryModelBackgroundFetch::stopBackgroundFetch() -{ - if (mBackgroundFetchActive) - { - mBackgroundFetchActive = FALSE; - gIdleCallbacks.deleteFunction(&LLInventoryModelBackgroundFetch::backgroundFetchCB, NULL); - mBulkFetchCount=0; - mMinTimeBetweenFetches=0.0f; - } -} - void LLInventoryModelBackgroundFetch::setAllFoldersFetched() { if (mRecursiveInventoryFetchStarted && @@ -171,7 +173,7 @@ void LLInventoryModelBackgroundFetch::setAllFoldersFetched() { mAllFoldersFetched = TRUE; } - stopBackgroundFetch(); + mFolderFetchActive = false; } void LLInventoryModelBackgroundFetch::backgroundFetchCB(void *) @@ -185,10 +187,9 @@ void LLInventoryModelBackgroundFetch::backgroundFetch() if (mBackgroundFetchActive && gAgent.getRegion()) { // If we'll be using the capability, we'll be sending batches and the background thing isn't as important. - std::string url = gAgent.getRegion()->getCapability("FetchInventoryDescendents2"); - if (gSavedSettings.getBOOL("UseHTTPInventory") && !url.empty()) + if (gSavedSettings.getBOOL("UseHTTPInventory")) { - bulkFetch(url); + bulkFetch(); return; } @@ -203,6 +204,9 @@ void LLInventoryModelBackgroundFetch::backgroundFetch() llinfos << "Inventory fetch completed" << llendl; setAllFoldersFetched(); + mBackgroundFetchActive = false; + mFolderFetchActive = false; + return; } @@ -232,79 +236,113 @@ void LLInventoryModelBackgroundFetch::backgroundFetch() } const FetchQueueInfo info = mFetchQueue.front(); - LLViewerInventoryCategory* cat = gInventory.getCategory(info.mCatUUID); - // category has been deleted, remove from queue. - if (!cat) + if (info.mIsCategory) { - mFetchQueue.pop_front(); - continue; - } - - if (mFetchTimer.getElapsedTimeF32() > mMinTimeBetweenFetches && - LLViewerInventoryCategory::VERSION_UNKNOWN == cat->getVersion()) - { - // category exists but has no children yet, fetch the descendants - // for now, just request every time and rely on retry timer to throttle - if (cat->fetch()) + + LLViewerInventoryCategory* cat = gInventory.getCategory(info.mUUID); + + // Category has been deleted, remove from queue. + if (!cat) { + mFetchQueue.pop_front(); + continue; + } + + if (mFetchTimer.getElapsedTimeF32() > mMinTimeBetweenFetches && + LLViewerInventoryCategory::VERSION_UNKNOWN == cat->getVersion()) + { + // Category exists but has no children yet, fetch the descendants + // for now, just request every time and rely on retry timer to throttle. + if (cat->fetch()) + { + mFetchTimer.reset(); + mTimelyFetchPending = TRUE; + } + else + { + // The catagory also tracks if it has expired and here it says it hasn't + // yet. Get out of here because nothing is going to happen until we + // update the timers. + break; + } + } + // Do I have all my children? + else if (gInventory.isCategoryComplete(info.mUUID)) + { + // Finished with this category, remove from queue. + mFetchQueue.pop_front(); + + // Add all children to queue. + LLInventoryModel::cat_array_t* categories; + gInventory.getDirectDescendentsOf(cat->getUUID(), categories); + for (LLInventoryModel::cat_array_t::const_iterator it = categories->begin(); + it != categories->end(); + ++it) + { + mFetchQueue.push_back(FetchQueueInfo((*it)->getUUID(),info.mRecursive)); + } + + // We received a response in less than the fast time. + if (mTimelyFetchPending && mFetchTimer.getElapsedTimeF32() < fast_fetch_time) + { + // Shrink timeouts based on success. + mMinTimeBetweenFetches = llmax(mMinTimeBetweenFetches * 0.8f, 0.3f); + mMaxTimeBetweenFetches = llmax(mMaxTimeBetweenFetches * 0.8f, 10.f); + lldebugs << "Inventory fetch times shrunk to (" << mMinTimeBetweenFetches << ", " << mMaxTimeBetweenFetches << ")" << llendl; + } + + mTimelyFetchPending = FALSE; + continue; + } + else if (mFetchTimer.getElapsedTimeF32() > mMaxTimeBetweenFetches) + { + // Received first packet, but our num descendants does not match db's num descendants + // so try again later. + mFetchQueue.pop_front(); + + if (mNumFetchRetries++ < MAX_FETCH_RETRIES) + { + // push on back of queue + mFetchQueue.push_back(info); + } + mTimelyFetchPending = FALSE; + mFetchTimer.reset(); + break; + } + + // Not enough time has elapsed to do a new fetch + break; + } + else + { + LLViewerInventoryItem* itemp = gInventory.getItem(info.mUUID); + + mFetchQueue.pop_front(); + if (!itemp) + { + continue; + } + + if (mFetchTimer.getElapsedTimeF32() > mMinTimeBetweenFetches) + { + itemp->fetchFromServer(); mFetchTimer.reset(); mTimelyFetchPending = TRUE; } - else + else if (itemp->mIsComplete) { - // The catagory also tracks if it has expired and here it says it hasn't - // yet. Get out of here because nothing is going to happen until we - // update the timers. - break; + mTimelyFetchPending = FALSE; } - } - // do I have all my children? - else if (gInventory.isCategoryComplete(info.mCatUUID)) - { - // finished with this category, remove from queue - mFetchQueue.pop_front(); - - // Add all children to queue. - LLInventoryModel::cat_array_t* categories; - gInventory.getDirectDescendentsOf(cat->getUUID(), categories); - for (LLInventoryModel::cat_array_t::const_iterator it = categories->begin(); - it != categories->end(); - ++it) + else if (mFetchTimer.getElapsedTimeF32() > mMaxTimeBetweenFetches) { - mFetchQueue.push_back(FetchQueueInfo((*it)->getUUID(),info.mRecursive)); - } - - // we received a response in less than the fast time - if (mTimelyFetchPending && mFetchTimer.getElapsedTimeF32() < fast_fetch_time) - { - // shrink timeouts based on success - mMinTimeBetweenFetches = llmax(mMinTimeBetweenFetches * 0.8f, 0.3f); - mMaxTimeBetweenFetches = llmax(mMaxTimeBetweenFetches * 0.8f, 10.f); - lldebugs << "Inventory fetch times shrunk to (" << mMinTimeBetweenFetches << ", " << mMaxTimeBetweenFetches << ")" << llendl; - } - - mTimelyFetchPending = FALSE; - continue; - } - else if (mFetchTimer.getElapsedTimeF32() > mMaxTimeBetweenFetches) - { - // received first packet, but our num descendants does not match db's num descendants - // so try again later. - mFetchQueue.pop_front(); - - if (mNumFetchRetries++ < MAX_FETCH_RETRIES) - { - // push on back of queue mFetchQueue.push_back(info); + mFetchTimer.reset(); + mTimelyFetchPending = FALSE; } - mTimelyFetchPending = FALSE; - mFetchTimer.reset(); + // Not enough time has elapsed to do a new fetch break; } - - // not enough time has elapsed to do a new fetch - break; } // @@ -314,15 +352,35 @@ void LLInventoryModelBackgroundFetch::backgroundFetch() } } -void LLInventoryModelBackgroundFetch::incrBulkFetch(S16 fetching) +void LLInventoryModelBackgroundFetch::incrFetchCount(S16 fetching) { - mBulkFetchCount += fetching; - if (mBulkFetchCount < 0) + mFetchCount += fetching; + if (mFetchCount < 0) { - mBulkFetchCount = 0; + mFetchCount = 0; } } +class LLInventoryModelFetchItemResponder : public LLInventoryModel::fetchInventoryResponder +{ +public: + LLInventoryModelFetchItemResponder(const LLSD& request_sd) : LLInventoryModel::fetchInventoryResponder(request_sd) {}; + void result(const LLSD& content); + void error(U32 status, const std::string& reason); +}; + +void LLInventoryModelFetchItemResponder::result( const LLSD& content ) +{ + LLInventoryModel::fetchInventoryResponder::result(content); + LLInventoryModelBackgroundFetch::instance().incrFetchCount(-1); +} + +void LLInventoryModelFetchItemResponder::error( U32 status, const std::string& reason ) +{ + LLInventoryModel::fetchInventoryResponder::error(status, reason); + LLInventoryModelBackgroundFetch::instance().incrFetchCount(-1); +} + class LLInventoryModelFetchDescendentsResponder: public LLHTTPClient::Responder { @@ -459,7 +517,7 @@ void LLInventoryModelFetchDescendentsResponder::result(const LLSD& content) } } - fetcher->incrBulkFetch(-1); + fetcher->incrFetchCount(-1); if (fetcher->isBulkFetchProcessingComplete()) { @@ -478,9 +536,9 @@ void LLInventoryModelFetchDescendentsResponder::error(U32 status, const std::str llinfos << "LLInventoryModelFetchDescendentsResponder::error " << status << ": " << reason << llendl; - fetcher->incrBulkFetch(-1); + fetcher->incrFetchCount(-1); - if (status==499) //timed out. Let's be awesome! + if (status==499) // timed out { for(LLSD::array_const_iterator folder_it = mRequestSD["folders"].beginArray(); folder_it != mRequestSD["folders"].endArray(); @@ -509,27 +567,29 @@ BOOL LLInventoryModelFetchDescendentsResponder::getIsRecursive(const LLUUID& cat // Bundle up a bunch of requests to send all at once. // static -void LLInventoryModelBackgroundFetch::bulkFetch(std::string url) +void LLInventoryModelBackgroundFetch::bulkFetch() { //Background fetch is called from gIdleCallbacks in a loop until background fetch is stopped. - //If there are items in sFetchQueue, we want to check the time since the last bulkFetch was + //If there are items in mFetchQueue, we want to check the time since the last bulkFetch was //sent. If it exceeds our retry time, go ahead and fire off another batch. - //Stopbackgroundfetch will be run from the Responder instead of here. + LLViewerRegion* region = gAgent.getRegion(); + if (!region) return; S16 max_concurrent_fetches=8; F32 new_min_time = 0.5f; //HACK! Clean this up when old code goes away entirely. - if (mMinTimeBetweenFetches < new_min_time) + if (mMinTimeBetweenFetches < new_min_time) { mMinTimeBetweenFetches=new_min_time; //HACK! See above. } if (gDisconnected || - (mBulkFetchCount > max_concurrent_fetches) || + (mFetchCount > max_concurrent_fetches) || (mFetchTimer.getElapsedTimeF32() < mMinTimeBetweenFetches)) { - return; // just bail if we are disconnected. + return; // just bail if we are disconnected } + U32 item_count=0; U32 folder_count=0; U32 max_batch_size=5; @@ -537,86 +597,163 @@ void LLInventoryModelBackgroundFetch::bulkFetch(std::string url) uuid_vec_t recursive_cats; - LLSD body; - LLSD body_lib; + LLSD folder_request_body; + LLSD folder_request_body_lib; + LLSD item_request_body; + LLSD item_request_body_lib; - while( !(mFetchQueue.empty() ) && (folder_count < max_batch_size) ) + while (!mFetchQueue.empty() + && (item_count + folder_count) < max_batch_size) { const FetchQueueInfo& fetch_info = mFetchQueue.front(); - const LLUUID &cat_id = fetch_info.mCatUUID; - if (cat_id.isNull()) //DEV-17797 - { - LLSD folder_sd; - folder_sd["folder_id"] = LLUUID::null.asString(); - folder_sd["owner_id"] = gAgent.getID(); - folder_sd["sort_order"] = (LLSD::Integer)sort_order; - folder_sd["fetch_folders"] = (LLSD::Boolean)FALSE; - folder_sd["fetch_items"] = (LLSD::Boolean)TRUE; - body["folders"].append(folder_sd); - folder_count++; - } - else - { - LLViewerInventoryCategory* cat = gInventory.getCategory(cat_id); + if (fetch_info.mIsCategory) + { + const LLUUID &cat_id = fetch_info.mUUID; + if (cat_id.isNull()) //DEV-17797 + { + LLSD folder_sd; + folder_sd["folder_id"] = LLUUID::null.asString(); + folder_sd["owner_id"] = gAgent.getID(); + folder_sd["sort_order"] = (LLSD::Integer)sort_order; + folder_sd["fetch_folders"] = (LLSD::Boolean)FALSE; + folder_sd["fetch_items"] = (LLSD::Boolean)TRUE; + folder_request_body["folders"].append(folder_sd); + folder_count++; + } + else + { + const LLViewerInventoryCategory* cat = gInventory.getCategory(cat_id); - if (cat) - { - if (LLViewerInventoryCategory::VERSION_UNKNOWN == cat->getVersion()) - { - LLSD folder_sd; - folder_sd["folder_id"] = cat->getUUID(); - folder_sd["owner_id"] = cat->getOwnerID(); - folder_sd["sort_order"] = (LLSD::Integer)sort_order; - folder_sd["fetch_folders"] = TRUE; //(LLSD::Boolean)sFullFetchStarted; - folder_sd["fetch_items"] = (LLSD::Boolean)TRUE; - - if (ALEXANDRIA_LINDEN_ID == cat->getOwnerID()) - body_lib["folders"].append(folder_sd); - else - body["folders"].append(folder_sd); - folder_count++; - } - // May already have this folder, but append child folders to list. - if (fetch_info.mRecursive) - { - LLInventoryModel::cat_array_t* categories; - gInventory.getDirectDescendentsOf(cat->getUUID(), categories); - for (LLInventoryModel::cat_array_t::const_iterator it = categories->begin(); - it != categories->end(); - ++it) + if (cat) + { + if (LLViewerInventoryCategory::VERSION_UNKNOWN == cat->getVersion()) { - mFetchQueue.push_back(FetchQueueInfo((*it)->getUUID(), fetch_info.mRecursive)); - } - } - } - } - if (fetch_info.mRecursive) - recursive_cats.push_back(cat_id); + LLSD folder_sd; + folder_sd["folder_id"] = cat->getUUID(); + folder_sd["owner_id"] = cat->getOwnerID(); + folder_sd["sort_order"] = (LLSD::Integer)sort_order; + folder_sd["fetch_folders"] = TRUE; //(LLSD::Boolean)sFullFetchStarted; + folder_sd["fetch_items"] = (LLSD::Boolean)TRUE; + + if (ALEXANDRIA_LINDEN_ID == cat->getOwnerID()) + folder_request_body_lib["folders"].append(folder_sd); + else + folder_request_body["folders"].append(folder_sd); + folder_count++; + } + // May already have this folder, but append child folders to list. + if (fetch_info.mRecursive) + { + LLInventoryModel::cat_array_t* categories; + LLInventoryModel::item_array_t* items; + gInventory.getDirectDescendentsOf(cat->getUUID(), categories, items); + for (LLInventoryModel::cat_array_t::const_iterator it = categories->begin(); + it != categories->end(); + ++it) + { + mFetchQueue.push_back(FetchQueueInfo((*it)->getUUID(), fetch_info.mRecursive)); + } + } + } + } + if (fetch_info.mRecursive) + recursive_cats.push_back(cat_id); + } + else + { + LLViewerInventoryItem* itemp = gInventory.getItem(fetch_info.mUUID); + if (itemp) + { + LLSD item_sd; + item_sd["owner_id"] = itemp->getPermissions().getOwner(); + item_sd["item_id"] = itemp->getUUID(); + if (itemp->getPermissions().getOwner() == gAgent.getID()) + { + item_request_body.append(item_sd); + } + else + { + item_request_body_lib.append(item_sd); + } + //itemp->fetchFromServer(); + item_count++; + } + } mFetchQueue.pop_front(); } - if (folder_count > 0) + if (item_count + folder_count > 0) { - mBulkFetchCount++; - if (body["folders"].size()) + if (folder_count) { - LLInventoryModelFetchDescendentsResponder *fetcher = new LLInventoryModelFetchDescendentsResponder(body, recursive_cats); - LLHTTPClient::post(url, body, fetcher, 300.0); + std::string url = region->getCapability("FetchInventoryDescendents2"); + mFetchCount++; + if (folder_request_body["folders"].size()) + { + LLInventoryModelFetchDescendentsResponder *fetcher = new LLInventoryModelFetchDescendentsResponder(folder_request_body, recursive_cats); + LLHTTPClient::post(url, folder_request_body, fetcher, 300.0); + } + if (folder_request_body_lib["folders"].size()) + { + std::string url_lib = gAgent.getRegion()->getCapability("FetchLibDescendents2"); + + LLInventoryModelFetchDescendentsResponder *fetcher = new LLInventoryModelFetchDescendentsResponder(folder_request_body_lib, recursive_cats); + LLHTTPClient::post(url_lib, folder_request_body_lib, fetcher, 300.0); + } } - if (body_lib["folders"].size()) + if (item_count) { - std::string url_lib = gAgent.getRegion()->getCapability("FetchLibDescendents2"); - - LLInventoryModelFetchDescendentsResponder *fetcher = new LLInventoryModelFetchDescendentsResponder(body_lib, recursive_cats); - LLHTTPClient::post(url_lib, body_lib, fetcher, 300.0); + std::string url; + + if (item_request_body.size()) + { + mFetchCount++; + url = region->getCapability("FetchInventory2"); + if (!url.empty()) + { + LLSD body; + body["agent_id"] = gAgent.getID(); + body["items"] = item_request_body; + + LLHTTPClient::post(url, body, new LLInventoryModelFetchItemResponder(body)); + } + //else + //{ + // LLMessageSystem* msg = gMessageSystem; + // msg->newMessage("FetchInventory"); + // msg->nextBlock("AgentData"); + // msg->addUUID("AgentID", gAgent.getID()); + // msg->addUUID("SessionID", gAgent.getSessionID()); + // msg->nextBlock("InventoryData"); + // msg->addUUID("OwnerID", mPermissions.getOwner()); + // msg->addUUID("ItemID", mUUID); + // gAgent.sendReliableMessage(); + //} + } + + if (item_request_body_lib.size()) + { + mFetchCount++; + + url = region->getCapability("FetchLib2"); + if (!url.empty()) + { + LLSD body; + body["agent_id"] = gAgent.getID(); + body["items"] = item_request_body_lib; + + LLHTTPClient::post(url, body, new LLInventoryModelFetchItemResponder(body)); + } + } } mFetchTimer.reset(); } + else if (isBulkFetchProcessingComplete()) { setAllFoldersFetched(); - } + } } bool LLInventoryModelBackgroundFetch::fetchQueueContainsNoDescendentsOf(const LLUUID& cat_id) const @@ -624,7 +761,7 @@ bool LLInventoryModelBackgroundFetch::fetchQueueContainsNoDescendentsOf(const LL for (fetch_queue_t::const_iterator it = mFetchQueue.begin(); it != mFetchQueue.end(); ++it) { - const LLUUID& fetch_id = (*it).mCatUUID; + const LLUUID& fetch_id = (*it).mUUID; if (gInventory.isObjectDescendentOf(fetch_id, cat_id)) return false; } diff --git a/indra/newview/llinventorymodelbackgroundfetch.h b/indra/newview/llinventorymodelbackgroundfetch.h index 0fac2c7a2..bc40cc5cb 100644 --- a/indra/newview/llinventorymodelbackgroundfetch.h +++ b/indra/newview/llinventorymodelbackgroundfetch.h @@ -48,7 +48,7 @@ public: // This gets triggered when performing a filter-search. void start(const LLUUID& cat_id = LLUUID::null, BOOL recursive = TRUE); - BOOL backgroundFetchActive() const; + BOOL folderFetchActive() const; bool isEverythingFetched() const; // completing the fetch once per session should be sufficient bool libraryFetchStarted() const; @@ -60,14 +60,13 @@ public: bool inventoryFetchInProgress() const; void findLostItems(); + void incrFetchCount(S16 fetching); protected: - void incrBulkFetch(S16 fetching); bool isBulkFetchProcessingComplete() const; - void bulkFetch(std::string url); + void bulkFetch(); void backgroundFetch(); static void backgroundFetchCB(void*); // background fetch idle function - void stopBackgroundFetch(); // stop fetch process void setAllFoldersFetched(); bool fetchQueueContainsNoDescendentsOf(const LLUUID& cat_id) const; @@ -77,7 +76,8 @@ private: BOOL mAllFoldersFetched; BOOL mBackgroundFetchActive; - S16 mBulkFetchCount; + bool mFolderFetchActive; + S16 mFetchCount; BOOL mTimelyFetchPending; S32 mNumFetchRetries; @@ -87,11 +87,11 @@ private: struct FetchQueueInfo { - FetchQueueInfo(const LLUUID& id, BOOL recursive) : - mCatUUID(id), mRecursive(recursive) - { - } - LLUUID mCatUUID; + FetchQueueInfo(const LLUUID& id, BOOL recursive, bool is_category = true) : + mUUID(id), mRecursive(recursive), mIsCategory(is_category) + {} + LLUUID mUUID; + bool mIsCategory; BOOL mRecursive; }; typedef std::deque fetch_queue_t; diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index d957b9f94..0f6fa9e78 100644 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -841,7 +841,7 @@ BOOL LLInventoryPanel::handleHover(S32 x, S32 y, MASK mask) if(handled) { ECursorType cursor = getWindow()->getCursor(); - if (LLInventoryModelBackgroundFetch::instance().backgroundFetchActive() && cursor == UI_CURSOR_ARROW) + if (LLInventoryModelBackgroundFetch::instance().folderFetchActive() && cursor == UI_CURSOR_ARROW) { // replace arrow cursor with arrow and hourglass cursor getWindow()->setCursor(UI_CURSOR_WORKING); diff --git a/indra/newview/llpanelmaininventory.cpp b/indra/newview/llpanelmaininventory.cpp index ac746097b..f37772a37 100644 --- a/indra/newview/llpanelmaininventory.cpp +++ b/indra/newview/llpanelmaininventory.cpp @@ -862,7 +862,7 @@ void LLInventoryView::updateItemcountText() { std::ostringstream title; title << "Inventory"; - if (LLInventoryModelBackgroundFetch::instance().backgroundFetchActive()) + if (LLInventoryModelBackgroundFetch::instance().folderFetchActive()) { LLLocale locale(LLLocale::USER_LOCALE); std::string item_count_string; From 349006637e42a913d36f34d2a98a701c55b3f637 Mon Sep 17 00:00:00 2001 From: Shyotl Date: Mon, 11 Jun 2012 07:04:02 -0500 Subject: [PATCH 11/28] LL has played with texture discard priority/bias. Giving it a trial here. --- indra/newview/llviewertexture.cpp | 77 +++++++++++++++++---------- indra/newview/llviewertexture.h | 14 +++++ indra/newview/llviewertexturelist.cpp | 24 +++++++++ indra/newview/llviewertexturelist.h | 39 ++++++-------- 4 files changed, 104 insertions(+), 50 deletions(-) diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index 10b608761..0455f18a7 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -2,33 +2,26 @@ * @file llviewertexture.cpp * @brief Object which handles a received image (and associated texture(s)) * - * $LicenseInfo:firstyear=2000&license=viewergpl$ - * - * Copyright (c) 2000-2010, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlife.com/developers/opensource/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ - * */ #include "llviewerprecompiledheaders.h" @@ -100,6 +93,7 @@ S32 LLViewerTexture::sMaxBoundTextureMemInMegaBytes = 0; S32 LLViewerTexture::sMaxTotalTextureMemInMegaBytes = 0; S32 LLViewerTexture::sMaxDesiredTextureMemInBytes = 0 ; S8 LLViewerTexture::sCameraMovingDiscardBias = 0 ; +F32 LLViewerTexture::sCameraMovingBias = 0.0f ; S32 LLViewerTexture::sMaxSculptRez = 128 ; //max sculpt image size const S32 MAX_CACHED_RAW_IMAGE_AREA = 64 * 64 ; const S32 MAX_CACHED_RAW_SCULPT_IMAGE_AREA = LLViewerTexture::sMaxSculptRez * LLViewerTexture::sMaxSculptRez ; @@ -109,6 +103,9 @@ S32 LLViewerTexture::sMaxSmallImageSize = MAX_CACHED_RAW_IMAGE_AREA ; BOOL LLViewerTexture::sFreezeImageScalingDown = FALSE ; F32 LLViewerTexture::sCurrentTime = 0.0f ; //BOOL LLViewerTexture::sUseTextureAtlas = FALSE ; +F32 LLViewerTexture::sTexelPixelRatio = 1.0f; + +LLViewerTexture::EDebugTexels LLViewerTexture::sDebugTexelsMode = LLViewerTexture::DEBUG_TEXELS_OFF; const F32 desired_discard_bias_min = -2.0f; // -max number of levels to improve image quality by const F32 desired_discard_bias_max = (F32)MAX_DISCARD_LEVEL; // max number of levels to reduce image quality by @@ -192,7 +189,12 @@ LLViewerTexture* LLViewerTextureManager::findTexture(const LLUUID& id) #endif //NEW_MEDIA_TEXTURE return tex ; } - + +LLViewerFetchedTexture* LLViewerTextureManager::findFetchedTexture(const LLUUID& id) +{ + return gTextureList.findImage(id); +} + #if NEW_MEDIA_TEXTURE LLViewerMediaTexture* LLViewerTextureManager::findMediaTexture(const LLUUID &media_id) { @@ -406,7 +408,7 @@ void LLViewerTextureManager::cleanup() void LLViewerTexture::initClass() { LLImageGL::sDefaultGLTexture = LLViewerFetchedTexture::sDefaultImagep->getGLTexture() ; - + sTexelPixelRatio = gSavedSettings.getF32("TexelPixelRatio"); if(gAuditTexture) { LLImageGL::setHighlightTexture(LLViewerTexture::OTHER) ; @@ -561,7 +563,8 @@ void LLViewerTexture::updateClass(const F32 velocity, const F32 angular_velocity F32 camera_moving_speed = LLViewerCamera::getInstance()->getAverageSpeed() ; F32 camera_angular_speed = LLViewerCamera::getInstance()->getAverageAngularSpeed(); - sCameraMovingDiscardBias = (S8)llmax(0.2f * camera_moving_speed, 2.0f * camera_angular_speed - 1) ; + sCameraMovingBias = llmax(0.2f * camera_moving_speed, 2.0f * camera_angular_speed - 1); + sCameraMovingDiscardBias = (S8)(sCameraMovingBias); LLViewerTexture::sFreezeImageScalingDown = (BYTES_TO_MEGA_BYTES(sBoundTextureMemoryInBytes) < 0.75f * sMaxBoundTextureMemInMegaBytes * texmem_middle_bound_scale) && (BYTES_TO_MEGA_BYTES(sTotalTextureMemoryInBytes) < 0.75f * sMaxTotalTextureMemInMegaBytes * texmem_middle_bound_scale) ; @@ -745,6 +748,7 @@ void LLViewerTexture::addTextureStats(F32 virtual_size, BOOL needs_gltexture) co mNeedsGLTexture = TRUE ; } + virtual_size *= sTexelPixelRatio; if(!mMaxVirtualSizeResetCounter) { //flag to reset the values because the old values are used. @@ -1923,6 +1927,8 @@ S32 LLViewerFetchedTexture::getCurrentDiscardLevelForFetching() bool LLViewerFetchedTexture::updateFetch() { static LLCachedControl textures_decode_disabled(gSavedSettings,"TextureDecodeDisabled"); + static LLCachedControl sCameraMotionThreshold(gSavedSettings,"TextureCameraMotionThreshold"); + static LLCachedControl sCameraMotionBoost(gSavedSettings,"TextureCameraMotionBoost"); if(textures_decode_disabled) { return false ; @@ -2091,14 +2097,18 @@ bool LLViewerFetchedTexture::updateFetch() { //load the texture progressively. S32 delta_level = (mBoostLevel > LLViewerTexture::BOOST_NONE) ? 2 : 1 ; - if(current_discard < 0) + if (current_discard < 0) { desired_discard = llmax(desired_discard, getMaxDiscardLevel() - delta_level); } - else + else if (LLViewerTexture::sCameraMovingBias < sCameraMotionThreshold) { - desired_discard = llmax(desired_discard, current_discard - delta_level); + desired_discard = llmax(desired_discard, current_discard - sCameraMotionBoost); } + else + { + desired_discard = llmax(desired_discard, current_discard - delta_level); + } if (mIsFetching) { @@ -2166,6 +2176,17 @@ bool LLViewerFetchedTexture::updateFetch() return mIsFetching ? true : false; } +void LLViewerFetchedTexture::forceToDeleteRequest() +{ + if (mHasFetcher) + { + LLAppViewer::getTextureFetch()->deleteRequest(getID(), true); + mHasFetcher = FALSE; + mIsFetching = FALSE ; + resetTextureStats(); + } +} + void LLViewerFetchedTexture::setIsMissingAsset() { if (mUrl.empty()) diff --git a/indra/newview/llviewertexture.h b/indra/newview/llviewertexture.h index 9c019b03d..85a6b4915 100644 --- a/indra/newview/llviewertexture.h +++ b/indra/newview/llviewertexture.h @@ -322,6 +322,7 @@ protected: } LLGLTextureState; LLGLTextureState mTextureState ; + static F32 sTexelPixelRatio; public: static const U32 sCurrentFileVersion; static S32 sImageCount; @@ -336,6 +337,7 @@ public: static S32 sMaxTotalTextureMemInMegaBytes; static S32 sMaxDesiredTextureMemInBytes ; static S8 sCameraMovingDiscardBias; + static F32 sCameraMovingBias; static S32 sMaxSculptRez ; static S32 sMinLargeImageSize ; static S32 sMaxSmallImageSize ; @@ -343,6 +345,16 @@ public: static F32 sCurrentTime ; //static BOOL sUseTextureAtlas ; + enum EDebugTexels + { + DEBUG_TEXELS_OFF, + DEBUG_TEXELS_CURRENT, + DEBUG_TEXELS_DESIRED, + DEBUG_TEXELS_FULL + }; + + static EDebugTexels sDebugTexelsMode; + static LLPointer sNullImagep; // Null texture for non-textured objects. static LLPointer sBlackImagep; // Texture to show NOTHING (pure black) }; @@ -491,6 +503,7 @@ public: BOOL hasFetcher() const { return mHasFetcher;} void setCanUseHTTP(bool can_use_http) {mCanUseHTTP = can_use_http;} + void forceToDeleteRequest(); protected: /*virtual*/ void switchToCachedImage(); S32 getCurrentDiscardLevelForFetching() ; @@ -710,6 +723,7 @@ public: //"find-texture" just check if the texture exists, if yes, return it, otherwise return null. // static LLViewerTexture* findTexture(const LLUUID& id) ; + static LLViewerFetchedTexture* findFetchedTexture(const LLUUID& id) ; #if NEW_MEDIA_TEXTURE static LLViewerMediaTexture* findMediaTexture(const LLUUID& id) ; diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp index 4f5f3272f..4be8df0e9 100644 --- a/indra/newview/llviewertexturelist.cpp +++ b/indra/newview/llviewertexturelist.cpp @@ -64,6 +64,7 @@ #include "llviewerstats.h" #include "pipeline.h" #include "llappviewer.h" +#include "llagent.h" //////////////////////////////////////////////////////////////////////////// @@ -622,6 +623,11 @@ static LLFastTimer::DeclareTimer FTM_IMAGE_MEDIA("Media"); void LLViewerTextureList::updateImages(F32 max_time) { + if(gAgent.getTeleportState() != LLAgent::TELEPORT_NONE) + { + clearFetchingRequests(); + return; + } LLAppViewer::getTextureFetch()->setTextureBandwidth(LLViewerStats::getInstance()->mTextureKBitStat.getMeanPerSec()); S32 global_raw_memory; @@ -693,6 +699,24 @@ void LLViewerTextureList::updateImages(F32 max_time) } } +void LLViewerTextureList::clearFetchingRequests() +{ + if (LLAppViewer::getTextureFetch()->getNumRequests() == 0) + { + return; + } + + for (image_priority_list_t::iterator iter = mImageList.begin(); + iter != mImageList.end(); ++iter) + { + LLViewerFetchedTexture* image = *iter; + if(image->hasFetcher()) + { + image->forceToDeleteRequest() ; + } + } +} + void LLViewerTextureList::updateImagesDecodePriorities() { // Update the decode priority for N images each frame diff --git a/indra/newview/llviewertexturelist.h b/indra/newview/llviewertexturelist.h index 034dc3e69..fa414ad5f 100644 --- a/indra/newview/llviewertexturelist.h +++ b/indra/newview/llviewertexturelist.h @@ -2,33 +2,26 @@ * @file llviewertexturelist.h * @brief Object for managing the list of images within a region * - * $LicenseInfo:firstyear=2000&license=viewergpl$ - * - * Copyright (c) 2000-2010, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlife.com/developers/opensource/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * 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$ - * */ #ifndef LL_LLVIEWERTEXTURELIST_H @@ -116,6 +109,8 @@ public: void doPreloadImages(); void doPrefetchImages(); + void clearFetchingRequests(); + static S32 getMinVideoRamSetting(); static S32 getMaxVideoRamSetting(bool get_recommended = false); From a399580c84b2255d041833af7b87822789043a6a Mon Sep 17 00:00:00 2001 From: Shyotl Date: Mon, 11 Jun 2012 07:12:58 -0500 Subject: [PATCH 12/28] Stale/unloaded textures apparently sticking around. SH-3074 would probably explain better, but the issue is restricted as per usual. --- indra/newview/lltexturefetch.cpp | 47 ++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp index cff601fde..72132496e 100644 --- a/indra/newview/lltexturefetch.cpp +++ b/indra/newview/lltexturefetch.cpp @@ -2,31 +2,25 @@ * @file lltexturefetch.cpp * @brief Object which fetches textures from the cache and/or network * - * $LicenseInfo:firstyear=2000&license=viewergpl$ - * - * Copyright (c) 2000-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * 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$ */ @@ -937,6 +931,8 @@ void LLTextureFetchWorker::startWork(S32 param) // Called from LLWorkerThread::processRequest() bool LLTextureFetchWorker::doWork(S32 param) { + static const F32 FETCHING_TIMEOUT = 120.f;//seconds + LLMutexLock lock(&mWorkMutex); if ((mFetcher->isQuitting() || getFlags(LLWorkerClass::WCF_DELETE_REQUESTED))) @@ -1296,6 +1292,8 @@ bool LLTextureFetchWorker::doWork(S32 param) bool res = false; if (!mUrl.empty()) { + mRequestedTimer.reset(); + mLoaded = FALSE; mGetStatus = 0; mGetReason.clear(); @@ -1487,6 +1485,13 @@ bool LLTextureFetchWorker::doWork(S32 param) } else { + if(FETCHING_TIMEOUT < mRequestedTimer.getElapsedTimeF32()) + { + //timeout, abort. + mState = DONE; + return true; + } + setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); return false; } From 0286c8bf55df683aa6b5555a9e06e09f87ae6e05 Mon Sep 17 00:00:00 2001 From: Shyotl Date: Mon, 11 Jun 2012 07:18:05 -0500 Subject: [PATCH 13/28] Small GCC fix. --- indra/newview/llvoavatar.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index c3fb3bc6e..be8961b61 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -842,7 +842,7 @@ void SHClientTagMgr::updateAvatarTag(LLVOAvatar* pAvatar) std::map::iterator it = mAvatarTags.find(id); LLSD new_tag = generateClientTag(pAvatar); - LLSD& old_tag = (it != mAvatarTags.end()) ? it->second : LLSD(); + LLSD old_tag = (it != mAvatarTags.end()) ? it->second : LLSD(); bool dirty = old_tag.size() != new_tag.size() || !llsd_equals(new_tag,old_tag); if(dirty) From 5b4700a8eea78ff58738e1b6219d3690584818d1 Mon Sep 17 00:00:00 2001 From: Shyotl Date: Tue, 12 Jun 2012 02:10:22 -0500 Subject: [PATCH 14/28] Added RenderAutoHideSurfaceAreaLimit setting, and tweaked hud rendering(lighting issues) --- indra/newview/llspatialpartition.cpp | 1 + indra/newview/llspatialpartition.h | 2 ++ indra/newview/llvovolume.cpp | 4 +++- indra/newview/pipeline.cpp | 8 ++++++-- 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp index 91ef5123e..db0e490cf 100644 --- a/indra/newview/llspatialpartition.cpp +++ b/indra/newview/llspatialpartition.cpp @@ -1077,6 +1077,7 @@ void LLSpatialGroup::clearOcclusionState(eOcclusionState state, S32 mode) //====================================== LLSpatialGroup::LLSpatialGroup(OctreeNode* node, LLSpatialPartition* part) : + mObjectBoxSize(1.f), mState(0), mGeometryBytes(0), mSurfaceArea(0.f), diff --git a/indra/newview/llspatialpartition.h b/indra/newview/llspatialpartition.h index 19b6e2faf..3cdf95e2c 100644 --- a/indra/newview/llspatialpartition.h +++ b/indra/newview/llspatialpartition.h @@ -363,6 +363,8 @@ public: LLVector4a mViewAngle; LLVector4a mLastUpdateViewAngle; + F32 mObjectBoxSize; //cached mObjectBounds[1].getLength3() + protected: virtual ~LLSpatialGroup(); diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 11fa5bb69..15489ce9b 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -3383,6 +3383,9 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) group->mGeometryBytes = 0; group->mSurfaceArea = 0; + //cache object box size since it might be used for determining visibility + group->mObjectBoxSize = group->mObjectBounds[1].getLength3().getF32(); + group->clearDrawMap(); mFaceList.clear(); @@ -4247,7 +4250,6 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std:: } } else if (gPipeline.canUseVertexShaders() - && group->mSpatialPartition->mPartitionType != LLViewerRegion::PARTITION_HUD && LLPipeline::sRenderBump && te->getShiny()) { //shiny diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 742af1be0..567be4dcd 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -3203,8 +3203,12 @@ void LLPipeline::postSort(LLCamera& camera) for (LLCullResult::sg_list_t::iterator i = sCull->beginVisibleGroups(); i != sCull->endVisibleGroups(); ++i) { LLSpatialGroup* group = *i; + + static LLCachedControl RenderAutoHideSurfaceAreaLimit("RenderAutoHideSurfaceAreaLimit", 0.f); if (sUseOcclusion && - group->isOcclusionState(LLSpatialGroup::OCCLUDED)) + group->isOcclusionState(LLSpatialGroup::OCCLUDED) || + (RenderAutoHideSurfaceAreaLimit > 0.f && + group->mSurfaceArea > RenderAutoHideSurfaceAreaLimit*llmax(group->mObjectBoxSize, 10.f))) { continue; } @@ -3275,7 +3279,7 @@ void LLPipeline::postSort(LLCamera& camera) } llpushcallstacks ; - forAllVisibleDrawables(updateParticleActivity); + forAllVisibleDrawables(updateParticleActivity); //for llfloateravatarlist // only render if the flag is set. The flag is only set if we are in edit mode or the toggle is set in the menus static const LLCachedControl beacons_visible("BeaconsVisible", false); From 21f7df0dccfbc9d0c91cfe97845cd5f80f6c47e7 Mon Sep 17 00:00:00 2001 From: Shyotl Date: Tue, 12 Jun 2012 02:14:19 -0500 Subject: [PATCH 15/28] Stuck a space between realname and legacy name so long names now are more likely to split between lines more elegantly. --- indra/newview/llvoavatar.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index be8961b61..900d705a9 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -3769,6 +3769,7 @@ void LLVOAvatar::idleUpdateNameTagText(BOOL new_name) // Suppress SLID display if display name matches exactly (ugh) if (show_usernames && !av_name.mIsDisplayNameDefault && !av_name.mUsername.empty()) { + firstnameText.push_back(' '); firstnameText.push_back('('); firstnameText.append(av_name.mUsername); //Defer for later formatting firstnameText.push_back(')'); From 3796a216d290049d5a6fdf2f65b399f8f5dd5334 Mon Sep 17 00:00:00 2001 From: Shyotl Date: Fri, 15 Jun 2012 09:09:58 -0500 Subject: [PATCH 16/28] Removed a few old settings from settings.xml. Added absent RenderAutoHideSurfaceAreaLimit setting. --- indra/newview/app_settings/settings.xml | 37 ++++++++++--------------- 1 file changed, 14 insertions(+), 23 deletions(-) diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index e2db9c442..69090ccd2 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -11219,7 +11219,7 @@ Comment Maximum size of a single node's vertex data (in KB). Persist - 0 + 1 Type S32 Value @@ -11600,28 +11600,19 @@ Value 0 - RenderUseShaderLOD - - Comment - Whether we want to have different shaders for LOD - Persist - 1 - Type - Boolean - Value - 1 - - RenderUseShaderNearParticles - - Comment - Whether we want to use shaders on near particles - Persist - 1 - Type - Boolean - Value - 0 - + + RenderAutoHideSurfaceAreaLimit + + Comment + Maximum surface area of a set of proximal objects inworld before automatically hiding geometry to prevent system overload. + Persist + 1 + Type + F32 + Value + 0 + + RenderVBOEnable Comment From 4c45e9a9d1f8c78a20cbb45f713e81c599449965 Mon Sep 17 00:00:00 2001 From: Shyotl Date: Fri, 15 Jun 2012 09:51:11 -0500 Subject: [PATCH 17/28] Inital full retooling of appearance editor for multi-wearables. Also updated LLTabContainer to use standard commit and validate callback signals. --- indra/llui/llbutton.cpp | 3 +- indra/llui/llmultifloater.cpp | 14 +- indra/llui/llmultifloater.h | 4 +- indra/llui/llpanel.cpp | 18 - indra/llui/llpanel.h | 1 - indra/llui/lltabcontainer.cpp | 158 ++++----- indra/llui/lltabcontainer.h | 42 +-- indra/newview/llagentwearables.cpp | 52 +-- indra/newview/llagentwearables.h | 2 +- indra/newview/llappearancemgr.cpp | 16 +- indra/newview/llfloateravatarpicker.cpp | 16 +- indra/newview/llfloateravatarpicker.h | 2 +- indra/newview/llfloatercustomize.cpp | 159 ++++----- indra/newview/llfloatercustomize.h | 10 +- indra/newview/llfloaterdirectory.cpp | 29 +- indra/newview/llfloaterdirectory.h | 2 +- indra/newview/llfloatergodtools.cpp | 16 +- indra/newview/llfloatergodtools.h | 2 +- indra/newview/llfloaterpreference.cpp | 38 +- indra/newview/llfloaterpreference.h | 2 +- indra/newview/llfloatertest.cpp | 8 +- indra/newview/llpaneleditwearable.cpp | 328 ++++++++++++------ indra/newview/llpaneleditwearable.h | 15 +- indra/newview/llpanelgroup.cpp | 13 +- indra/newview/llpanelgroup.h | 1 - indra/newview/llpanelgrouplandmoney.cpp | 12 +- indra/newview/llpanelgrouproles.cpp | 14 +- indra/newview/llpanelgrouproles.h | 1 - indra/newview/llpanelmaininventory.cpp | 22 +- indra/newview/llpanelmaininventory.h | 2 +- indra/newview/llpreview.cpp | 2 +- indra/newview/llpreview.h | 2 +- indra/newview/llscrollingpanelparam.cpp | 39 +-- indra/newview/llscrollingpanelparam.h | 3 +- indra/newview/llscrollingpanelparambase.cpp | 21 +- indra/newview/llscrollingpanelparambase.h | 3 +- indra/newview/lltoolmorph.cpp | 12 +- indra/newview/lltoolmorph.h | 2 + indra/newview/llvoavatar.cpp | 11 - indra/newview/llwearable.cpp | 2 +- .../default/xui/en-us/floater_customize.xml | 300 ++++++++-------- 41 files changed, 717 insertions(+), 682 deletions(-) diff --git a/indra/llui/llbutton.cpp b/indra/llui/llbutton.cpp index 7c2fd3a81..f10e211f1 100644 --- a/indra/llui/llbutton.cpp +++ b/indra/llui/llbutton.cpp @@ -297,8 +297,7 @@ boost::signals2::connection LLButton::setHeldDownCallback(const CommitCallbackPa boost::signals2::connection LLButton::setClickedCallback( const commit_signal_t::slot_type& cb ) { - if (!mCommitSignal) mCommitSignal = new commit_signal_t(); - return mCommitSignal->connect(cb); + return LLUICtrl::setCommitCallback(cb); } boost::signals2::connection LLButton::setMouseDownCallback( const commit_signal_t::slot_type& cb ) { diff --git a/indra/llui/llmultifloater.cpp b/indra/llui/llmultifloater.cpp index 29ea32816..377c9a12b 100644 --- a/indra/llui/llmultifloater.cpp +++ b/indra/llui/llmultifloater.cpp @@ -280,7 +280,7 @@ void LLMultiFloater::addFloater(LLFloater* floaterp, BOOL select_added_floater, } //add the panel, add it to proper maps - mTabContainer->addTabPanel(floaterp, floaterp->getShortTitle(), FALSE, onTabSelected, this, 0, FALSE, insertion_point); + mTabContainer->addTabPanel(floaterp, floaterp->getShortTitle(), FALSE, 0, FALSE, insertion_point); mFloaterDataMap[floaterp->getHandle()] = floater_data; updateResizeLimits(); @@ -366,10 +366,10 @@ void LLMultiFloater::removeFloater(LLFloater* floaterp) updateResizeLimits(); - tabOpen((LLFloater*)mTabContainer->getCurrentPanel(), false); + tabOpen((LLFloater*)mTabContainer->getCurrentPanel()); } -void LLMultiFloater::tabOpen(LLFloater* opened_floater, bool from_click) +void LLMultiFloater::tabOpen(LLFloater* opened_floater) { // default implementation does nothing } @@ -464,12 +464,9 @@ void LLMultiFloater::setFloaterFlashing(LLFloater* floaterp, BOOL flashing) mTabContainer->setTabPanelFlashing(floaterp, flashing); } -//static -void LLMultiFloater::onTabSelected(void* userdata, bool from_click) +void LLMultiFloater::onTabSelected() { - LLMultiFloater* floaterp = (LLMultiFloater*)userdata; - - floaterp->tabOpen((LLFloater*)floaterp->mTabContainer->getCurrentPanel(), from_click); + tabOpen((LLFloater*)mTabContainer->getCurrentPanel()); } void LLMultiFloater::setCanResize(BOOL can_resize) @@ -499,6 +496,7 @@ BOOL LLMultiFloater::postBuild() if (checkRequirements()) { mTabContainer = getChild("Preview Tabs"); + mTabContainer->setCommitCallback(boost::bind(&LLMultiFloater::onTabSelected, this)); return TRUE; } diff --git a/indra/llui/llmultifloater.h b/indra/llui/llmultifloater.h index 29c03b3c4..0ac9ee856 100644 --- a/indra/llui/llmultifloater.h +++ b/indra/llui/llmultifloater.h @@ -60,7 +60,7 @@ public: virtual void showFloater(LLFloater* floaterp); virtual void removeFloater(LLFloater* floaterp); - virtual void tabOpen(LLFloater* opened_floater, bool from_click); + virtual void tabOpen(LLFloater* opened_floater); virtual void tabClose(); virtual BOOL selectFloater(LLFloater* floaterp); @@ -74,7 +74,7 @@ public: virtual void setFloaterFlashing(LLFloater* floaterp, BOOL flashing); virtual BOOL closeAllFloaters(); //Returns FALSE if the floater could not be closed due to pending confirmation dialogs void setTabContainer(LLTabContainer* tab_container) { if (!mTabContainer) mTabContainer = tab_container; } - static void onTabSelected(void* userdata, bool); + void onTabSelected(); virtual void updateResizeLimits(); diff --git a/indra/llui/llpanel.cpp b/indra/llui/llpanel.cpp index 627f06c80..136dcf524 100644 --- a/indra/llui/llpanel.cpp +++ b/indra/llui/llpanel.cpp @@ -931,24 +931,6 @@ LLPanel *LLPanel::childGetVisibleTab(const std::string& id) const return NULL; } -void LLPanel::childSetTabChangeCallback(const std::string& id, const std::string& tabname, void (*on_tab_clicked)(void*, bool), void *userdata, void (*on_precommit)(void*,bool)) -{ - LLTabContainer* child = getChild(id); - if (child) - { - LLPanel *panel = child->getPanelByName(tabname); - if (panel) - { - child->setTabChangeCallback(panel, on_tab_clicked); - child->setTabUserData(panel, userdata); - if (on_precommit) - { - child->setTabPrecommitChangeCallback(panel, on_precommit); - } - } - } -} - void LLPanel::childSetKeystrokeCallback(const std::string& id, void (*keystroke_callback)(LLLineEditor* caller, void* user_data), void *user_data) { LLLineEditor* child = getChild(id); diff --git a/indra/llui/llpanel.h b/indra/llui/llpanel.h index bb16b6e02..ad721cbf5 100644 --- a/indra/llui/llpanel.h +++ b/indra/llui/llpanel.h @@ -198,7 +198,6 @@ public: // LLTabContainer void childShowTab(const std::string& id, const std::string& tabname, bool visible = true); LLPanel *childGetVisibleTab(const std::string& id) const; - void childSetTabChangeCallback(const std::string& id, const std::string& tabname, void (*on_tab_clicked)(void*, bool), void *userdata, void (*on_precommit)(void*,bool) = NULL); // LLTextBox void childSetWrappedText(const std::string& id, const std::string& text, bool visible = true); diff --git a/indra/llui/lltabcontainer.cpp b/indra/llui/lltabcontainer.cpp index 0f08f2c58..8ce359b8f 100644 --- a/indra/llui/lltabcontainer.cpp +++ b/indra/llui/lltabcontainer.cpp @@ -69,12 +69,33 @@ const S32 TABCNTRV_PAD = 0; static LLRegisterWidget r("tab_container"); +// Structure used to map tab buttons to and from tab panels +class LLTabTuple +{ +public: + LLTabTuple( LLTabContainer* c, LLPanel* p, LLButton* b, LLTextBox* placeholder = NULL) + : + mTabContainer(c), + mTabPanel(p), + mButton(b), + mOldState(FALSE), + mPlaceholderText(placeholder), + mPadding(0) + {} + + LLTabContainer* mTabContainer; + LLPanel* mTabPanel; + LLButton* mButton; + BOOL mOldState; + LLTextBox* mPlaceholderText; + S32 mPadding; +}; + LLTabContainer::LLTabContainer(const std::string& name, const LLRect& rect, TabPosition pos, BOOL bordered, BOOL is_vertical ) : LLPanel(name, rect, bordered), mCurrentTabIdx(-1), - mNextTabIdx(-1), mTabsHidden(FALSE), mScrolled(FALSE), mScrollPos(0), @@ -221,10 +242,13 @@ void LLTabContainer::draw() } // Hide all the buttons - for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) + if (getTabsHidden()) { - LLTabTuple* tuple = *iter; - tuple->mButton->setVisible( FALSE ); + for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) + { + LLTabTuple* tuple = *iter; + tuple->mButton->setVisible( FALSE ); + } } LLPanel::draw(); @@ -320,7 +344,7 @@ void LLTabContainer::draw() BOOL LLTabContainer::handleMouseDown( S32 x, S32 y, MASK mask ) { BOOL handled = FALSE; - BOOL has_scroll_arrows = (getMaxScrollPos() > 0); + BOOL has_scroll_arrows = (getMaxScrollPos() > 0) && !getTabsHidden(); if (has_scroll_arrows) { @@ -355,7 +379,7 @@ BOOL LLTabContainer::handleMouseDown( S32 x, S32 y, MASK mask ) } S32 tab_count = getTabCount(); - if (tab_count > 0) + if (tab_count > 0 && !getTabsHidden()) { LLTabTuple* firsttuple = getTab(0); LLRect tab_rect; @@ -379,7 +403,7 @@ BOOL LLTabContainer::handleMouseDown( S32 x, S32 y, MASK mask ) index = llclamp(index, 0, tab_count-1); LLButton* tab_button = getTab(index)->mButton; gFocusMgr.setMouseCapture(this); - gFocusMgr.setKeyboardFocus(tab_button); + tab_button->setFocus(TRUE); } } return handled; @@ -389,7 +413,7 @@ BOOL LLTabContainer::handleMouseDown( S32 x, S32 y, MASK mask ) BOOL LLTabContainer::handleHover( S32 x, S32 y, MASK mask ) { BOOL handled = FALSE; - BOOL has_scroll_arrows = (getMaxScrollPos() > 0); + BOOL has_scroll_arrows = (getMaxScrollPos() > 0) && !getTabsHidden(); if (has_scroll_arrows) { @@ -431,7 +455,7 @@ BOOL LLTabContainer::handleHover( S32 x, S32 y, MASK mask ) BOOL LLTabContainer::handleMouseUp( S32 x, S32 y, MASK mask ) { BOOL handled = FALSE; - BOOL has_scroll_arrows = (getMaxScrollPos() > 0); + BOOL has_scroll_arrows = (getMaxScrollPos() > 0) && !getTabsHidden(); if (has_scroll_arrows) { @@ -487,7 +511,7 @@ BOOL LLTabContainer::handleMouseUp( S32 x, S32 y, MASK mask ) BOOL LLTabContainer::handleToolTip( S32 x, S32 y, std::string& msg, LLRect* sticky_rect ) { BOOL handled = LLPanel::handleToolTip( x, y, msg, sticky_rect ); - if (!handled && getTabCount() > 0) + if (!handled && getTabCount() > 0 && !getTabsHidden()) { LLTabTuple* firsttuple = getTab(0); @@ -523,12 +547,6 @@ BOOL LLTabContainer::handleToolTip( S32 x, S32 y, std::string& msg, LLRect* stic } } } - - for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) - { - LLTabTuple* tuple = *iter; - tuple->mButton->setVisible( FALSE ); - } } return handled; } @@ -695,8 +713,6 @@ BOOL LLTabContainer::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDrag void LLTabContainer::addTabPanel(LLPanel* child, const std::string& label, BOOL select, - void (*on_tab_clicked)(void*, bool), - void* userdata, S32 indent, BOOL placeholder, eInsertionPoint insertion_point) @@ -722,20 +738,28 @@ void LLTabContainer::addTabPanel(LLPanel* child, // Tab panel S32 tab_panel_top; S32 tab_panel_bottom; - if( getTabPosition() == LLTabContainer::TOP ) + if (!getTabsHidden()) { - S32 tab_height = mIsVertical ? BTN_HEIGHT : TABCNTR_TAB_HEIGHT; - tab_panel_top = getRect().getHeight() - getTopBorderHeight() - (tab_height - TABCNTR_BUTTON_PANEL_OVERLAP); - tab_panel_bottom = LLPANEL_BORDER_WIDTH; + if( getTabPosition() == LLTabContainer::TOP ) + { + S32 tab_height = mIsVertical ? BTN_HEIGHT : TABCNTR_TAB_HEIGHT; + tab_panel_top = getRect().getHeight() - getTopBorderHeight() - (tab_height - TABCNTR_BUTTON_PANEL_OVERLAP); + tab_panel_bottom = LLPANEL_BORDER_WIDTH; + } + else + { + tab_panel_top = getRect().getHeight() - getTopBorderHeight(); + tab_panel_bottom = (TABCNTR_TAB_HEIGHT - TABCNTR_BUTTON_PANEL_OVERLAP); // Run to the edge, covering up the border + } } else { - tab_panel_top = getRect().getHeight() - getTopBorderHeight(); - tab_panel_bottom = (TABCNTR_TAB_HEIGHT - TABCNTR_BUTTON_PANEL_OVERLAP); // Run to the edge, covering up the border + //Scip tab button space if they are invisible(EXT - 576) + tab_panel_top = getRect().getHeight(); + tab_panel_bottom = LLPANEL_BORDER_WIDTH; } - LLRect tab_panel_rect; - if (mIsVertical) + if (!getTabsHidden() && mIsVertical) { tab_panel_rect = LLRect(mMinTabWidth + (LLPANEL_BORDER_WIDTH * 2) + TABCNTRV_PAD, getRect().getHeight() - LLPANEL_BORDER_WIDTH, @@ -854,7 +878,7 @@ void LLTabContainer::addTabPanel(LLPanel* child, } } - LLTabTuple* tuple = new LLTabTuple( this, child, btn, on_tab_clicked, userdata, textbox ); + LLTabTuple* tuple = new LLTabTuple( this, child, btn, textbox ); insertTuple( tuple, insertion_point ); if (textbox) @@ -883,7 +907,7 @@ void LLTabContainer::addTabPanel(LLPanel* child, void LLTabContainer::addPlaceholder(LLPanel* child, const std::string& label) { - addTabPanel(child, label, FALSE, NULL, NULL, 0, TRUE); + addTabPanel(child, label, FALSE, 0, TRUE); } void LLTabContainer::removeTabPanel(LLPanel* child) @@ -1154,8 +1178,8 @@ BOOL LLTabContainer::selectTabPanel(LLPanel* child) BOOL LLTabContainer::selectTab(S32 which) { - if (which >= getTabCount()) return FALSE; - if (which < 0) return FALSE; + if (which >= getTabCount() || which < 0) + return FALSE; //if( gFocusMgr.childHasKeyboardFocus( this ) ) //{ @@ -1167,28 +1191,26 @@ BOOL LLTabContainer::selectTab(S32 which) { return FALSE; } + + LLSD cbdata; + if (selected_tuple->mTabPanel) + cbdata = selected_tuple->mTabPanel->getName(); - if (!selected_tuple->mPrecommitChangeCallback) + BOOL res = FALSE; + if( !mValidateSignal || (*mValidateSignal)( this, cbdata ) ) { - return setTab(which); + res = setTab(which); + if (res && mCommitSignal) + { + (*mCommitSignal)(this, cbdata); + } } - - mNextTabIdx = which; - selected_tuple->mPrecommitChangeCallback(selected_tuple->mUserData, false); - return TRUE; + + return res; } BOOL LLTabContainer::setTab(S32 which) { - if (which == -1) - { - if (mNextTabIdx == -1) - { - return FALSE; - } - which = mNextTabIdx; - mNextTabIdx = -1; - } LLTabTuple* selected_tuple = getTab(which); if (!selected_tuple) @@ -1212,7 +1234,7 @@ BOOL LLTabContainer::setTab(S32 which) // RN: this limits tab-stops to active button only, which would require arrow keys to switch tabs tuple->mButton->setTabStop( is_selected ); - if( is_selected && (mIsVertical || (getMaxScrollPos() > 0))) + if (is_selected) { // Make sure selected tab is within scroll region if (mIsVertical) @@ -1228,7 +1250,7 @@ BOOL LLTabContainer::setTab(S32 which) is_visible = FALSE; } } - else + else if (getMaxScrollPos() > 0) { if( i < getScrollPos() ) { @@ -1259,13 +1281,13 @@ BOOL LLTabContainer::setTab(S32 which) } is_visible = TRUE; } + else + { + is_visible = TRUE; + } } i++; } - if( selected_tuple->mOnChangeCallback ) - { - selected_tuple->mOnChangeCallback( selected_tuple->mUserData, false ); - } } if (mIsVertical && getCurrentPanelIndex() >= 0) { @@ -1368,33 +1390,6 @@ S32 LLTabContainer::getTopBorderHeight() const return mTopBorderHeight; } -void LLTabContainer::setTabChangeCallback(LLPanel* tab, void (*on_tab_clicked)(void*, bool)) -{ - LLTabTuple* tuplep = getTabByPanel(tab); - if (tuplep) - { - tuplep->mOnChangeCallback = on_tab_clicked; - } -} - -void LLTabContainer::setTabPrecommitChangeCallback(LLPanel* tab, void (*on_precommit)(void*, bool)) -{ - LLTabTuple* tuplep = getTabByPanel(tab); - if (tuplep) - { - tuplep->mPrecommitChangeCallback = on_precommit; - } -} - -void LLTabContainer::setTabUserData(LLPanel* tab, void* userdata) -{ - LLTabTuple* tuplep = getTabByPanel(tab); - if (tuplep) - { - tuplep->mUserData = userdata; - } -} - void LLTabContainer::setRightTabBtnOffset(S32 offset) { mNextArrowBtn->translate( -offset - mRightTabBtnOffset, 0 ); @@ -1583,8 +1578,7 @@ LLView* LLTabContainer::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFacto } BOOL placeholder = FALSE; child->getAttributeBOOL("placeholder", placeholder); - tab_container->addTabPanel(panelp, label, false, - NULL, NULL, 0, placeholder); + tab_container->addTabPanel(panelp, label, false, 0, placeholder); } } @@ -1745,7 +1739,7 @@ void LLTabContainer::initButtons() setDefaultTabGroup(1); } -LLTabContainer::LLTabTuple* LLTabContainer::getTabByPanel(LLPanel* child) +LLTabTuple* LLTabContainer::getTabByPanel(LLPanel* child) { for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) { @@ -1846,7 +1840,7 @@ void LLTabContainer::updateMaxScrollPos() void LLTabContainer::commitHoveredButton(S32 x, S32 y) { - if (hasMouseCapture()) + if (!getTabsHidden() && hasMouseCapture()) { for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) { diff --git a/indra/llui/lltabcontainer.h b/indra/llui/lltabcontainer.h index 8117cdee9..4ad691e49 100644 --- a/indra/llui/lltabcontainer.h +++ b/indra/llui/lltabcontainer.h @@ -36,6 +36,7 @@ #include "llpanel.h" #include "lltextbox.h" #include "llframetimer.h" +class LLTabTuple; extern const S32 TABCNTR_HEADER_HEIGHT; @@ -79,9 +80,7 @@ public: void addTabPanel(LLPanel* child, const std::string& label, - BOOL select = FALSE, - void (*on_tab_clicked)(void*, bool) = NULL, - void* userdata = NULL, + BOOL select = FALSE, S32 indent = 0, BOOL placeholder = FALSE, eInsertionPoint insertion_point = END); @@ -108,7 +107,6 @@ public: BOOL selectTabPanel( LLPanel* child ); BOOL selectTab(S32 which); BOOL selectTabByName(const std::string& title); - BOOL setTab(S32 which); BOOL getTabPanelFlashing(LLPanel* child); void setTabPanelFlashing(LLPanel* child, BOOL state); @@ -118,10 +116,6 @@ public: void setTopBorderHeight(S32 height); S32 getTopBorderHeight() const; - - void setTabChangeCallback(LLPanel* tab, void (*on_tab_clicked)(void*,bool)); - void setTabPrecommitChangeCallback(LLPanel* tab, void (*on_precommit)(void*, bool)); - void setTabUserData(LLPanel* tab, void* userdata); void setRightTabBtnOffset( S32 offset ); void setPanelTitle(S32 index, const std::string& title); @@ -146,39 +140,11 @@ public: static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory); private: - // Structure used to map tab buttons to and from tab panels - struct LLTabTuple - { - LLTabTuple( LLTabContainer* c, LLPanel* p, LLButton* b, - void (*cb)(void*,bool), void* userdata, LLTextBox* placeholder = NULL, - void (*pcb)(void*,bool) = NULL) - : - mTabContainer(c), - mTabPanel(p), - mButton(b), - mOnChangeCallback( cb ), - mPrecommitChangeCallback( pcb ), - mUserData( userdata ), - mOldState(FALSE), - mPlaceholderText(placeholder), - mPadding(0) - {} - - LLTabContainer* mTabContainer; - LLPanel* mTabPanel; - LLButton* mButton; - void (*mOnChangeCallback)(void*, bool); - void (*mPrecommitChangeCallback)(void*,bool); // Precommit callback gets called before tab is changed and - // can prevent it from being changed. onChangeCallback is called - // immediately after tab is actually changed - Nyx - void* mUserData; - BOOL mOldState; - LLTextBox* mPlaceholderText; - S32 mPadding; - }; void initButtons(); + BOOL setTab(S32 which); + LLTabTuple* getTab(S32 index) { return mTabList[index]; } LLTabTuple* getTabByPanel(LLPanel* child); void insertTuple(LLTabTuple * tuple, eInsertionPoint insertion_point); diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp index c264b73a7..ab33da86c 100644 --- a/indra/newview/llagentwearables.cpp +++ b/indra/newview/llagentwearables.cpp @@ -281,8 +281,6 @@ void LLAgentWearables::addWearabletoAgentInventoryDone(const LLWearableType::ETy const LLUUID& item_id, LLWearable* wearable) { - //llassert_always(index == 0); - llinfos << "type " << type << " index " << index << " item " << item_id.asString() << llendl; if (item_id.isNull()) @@ -472,29 +470,28 @@ void LLAgentWearables::saveWearable(const LLWearableType::EType type, const U32 } } -void LLAgentWearables::saveWearableAs(const LLWearableType::EType type, +LLWearable* LLAgentWearables::saveWearableAs(const LLWearableType::EType type, const U32 index, const std::string& new_name, BOOL save_in_lost_and_found) { - //llassert_always(index == 0); if (!isWearableCopyable(type, index)) { llwarns << "LLAgent::saveWearableAs() not copyable." << llendl; - return; + return NULL; } LLWearable* old_wearable = getWearable(type, index); if (!old_wearable) { llwarns << "LLAgent::saveWearableAs() no old wearable." << llendl; - return; + return NULL; } LLInventoryItem* item = gInventory.getItem(getWearableItemID(type,index)); if (!item) { llwarns << "LLAgent::saveWearableAs() no inventory item." << llendl; - return; + return NULL; } std::string trunc_name(new_name); LLStringUtil::truncate(trunc_name, DB_INV_ITEM_NAME_STR_LEN); @@ -532,6 +529,7 @@ void LLAgentWearables::saveWearableAs(const LLWearableType::EType type, // unsaved changes so other inventory items aren't affected by the changes // that were just saved. old_wearable->revertValues(); + return new_wearable; } void LLAgentWearables::revertWearable(const LLWearableType::EType type, const U32 index) @@ -755,7 +753,7 @@ void LLAgentWearables::setWearable(const LLWearableType::EType type, U32 index, pushWearable(type,wearable); return; } - + wearableentry_map_t::iterator wearable_iter = mWearableDatas.find(type); if (wearable_iter == mWearableDatas.end()) { @@ -835,9 +833,8 @@ void LLAgentWearables::wearableUpdated(LLWearable *wearable) //while the wearable being created has not yet been stuffed into the wearable list. //This results in the param hints being buggered and screwing up the current wearable during LLVisualParamHint::preRender, //thus making the wearable 'dirty'. The code below basically 'forces' a refresh of the panel to fix this. - U32 index = gAgentWearables.getWearableIndex(wearable); - if(gFloaterCustomize && index==0) - gFloaterCustomize->setWearable(wearable->getType(), wearable); + if(gFloaterCustomize) + gFloaterCustomize->wearablesChanged(wearable->getType()); } @@ -1712,21 +1709,21 @@ bool LLAgentWearables::onSetWearableDialog( const LLSD& notification, const LLSD switch( option ) { - case 0: // "Save" + case 0: // "Save" gAgentWearables.saveWearable(wearable->getType(),index); - gAgentWearables.setWearableFinal( new_item, wearable ); - break; + gAgentWearables.setWearableFinal( new_item, wearable ); + break; - case 1: // "Don't Save" - gAgentWearables.setWearableFinal( new_item, wearable ); - break; + case 1: // "Don't Save" + gAgentWearables.setWearableFinal( new_item, wearable ); + break; - case 2: // "Cancel" - break; + case 2: // "Cancel" + break; - default: - llassert(0); - break; + default: + llassert(0); + break; } delete wearable; @@ -1742,10 +1739,11 @@ void LLAgentWearables::setWearableFinal(LLInventoryItem* new_item, LLWearable* n if (do_append && getWearableItemID(type,0).notNull()) { new_wearable->setItemID(new_item->getUUID()); - mWearableDatas[type].push_back(new_wearable); + /*mWearableDatas[type].push_back(new_wearable); llinfos << "Added additional wearable for type " << type << " size is now " << mWearableDatas[type].size() << llendl; - checkWearableAgainstInventory(new_wearable); + checkWearableAgainstInventory(new_wearable);*/ + pushWearable(type,new_wearable); //To call LLAgentWearables::wearableUpdated } else { @@ -2228,6 +2226,12 @@ bool LLAgentWearables::moveWearable(const LLViewerInventoryItem* item, bool clos U32 swap_i = closer_to_body ? i-1 : i+1; wearable_vec[i] = wearable_vec[swap_i]; wearable_vec[swap_i] = wearable; + + if(gFloaterCustomize) + { + gFloaterCustomize->wearablesChanged(item->getWearableType()); + } + return true; } diff --git a/indra/newview/llagentwearables.h b/indra/newview/llagentwearables.h index 231edc7fb..c3aad9500 100644 --- a/indra/newview/llagentwearables.h +++ b/indra/newview/llagentwearables.h @@ -205,7 +205,7 @@ private: // Save Wearables //-------------------------------------------------------------------- public: - void saveWearableAs(const LLWearableType::EType type, const U32 index, const std::string& new_name, BOOL save_in_lost_and_found); + LLWearable* saveWearableAs(const LLWearableType::EType type, const U32 index, const std::string& new_name, BOOL save_in_lost_and_found); void saveWearable(const LLWearableType::EType type, const U32 index, BOOL send_update = TRUE, const std::string new_name = ""); void saveAllWearables(); diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index 7bf71fe36..60ebf402e 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -2508,7 +2508,21 @@ void LLAppearanceMgr::addCOFItemLink(const LLInventoryItem *item, bool do_update { cb = new ModifiedCOFCallback; } - const std::string description = vitem->getIsLinkType() ? vitem->getDescription() : ""; + std::string description = vitem->getIsLinkType() ? vitem->getDescription() : ""; + if(description.empty()) + { + LLWearable* wearable = gAgentWearables.getWearableFromItemID(vitem->getLinkedUUID()); + if(wearable) + { + U32 index = gAgentWearables.getWearableIndex(wearable); + if(index < LLAgentWearables::MAX_CLOTHING_PER_TYPE) + { + std::ostringstream order_num; + order_num << ORDER_NUMBER_SEPARATOR << wearable->getType() * 100 + index; + description = order_num.str(); + } + } + } link_inventory_item( gAgent.getID(), vitem->getLinkedUUID(), getCOF(), diff --git a/indra/newview/llfloateravatarpicker.cpp b/indra/newview/llfloateravatarpicker.cpp index 02db1cc7b..b93812506 100644 --- a/indra/newview/llfloateravatarpicker.cpp +++ b/indra/newview/llfloateravatarpicker.cpp @@ -142,24 +142,16 @@ BOOL LLFloaterAvatarPicker::postBuild() inventory_panel->openDefaultFolderForType(LLAssetType::AT_CALLINGCARD); inventory_panel->setSelectCallback(boost::bind(&LLFloaterAvatarPicker::onCallingCardSelectionChange, _1, _2, (void*)this)); - childSetTabChangeCallback("ResidentChooserTabs", "SearchPanel", onTabChanged, this); - childSetTabChangeCallback("ResidentChooserTabs", "CallingCardsPanel", onTabChanged, this); - childSetTabChangeCallback("ResidentChooserTabs", "NearMePanel", onTabChanged, this); - childSetTabChangeCallback("ResidentChooserTabs", "KeyPanel", onTabChanged, this); + getChild("ResidentChooserTabs")->setCommitCallback(boost::bind(&LLFloaterAvatarPicker::onTabChanged,this)); + setAllowMultiple(FALSE); return TRUE; } -void LLFloaterAvatarPicker::onTabChanged(void* userdata, bool from_click) +void LLFloaterAvatarPicker::onTabChanged() { - LLFloaterAvatarPicker* self = (LLFloaterAvatarPicker*)userdata; - if (!self) - { - return; - } - - self->childSetEnabled("Select", self->visibleItemsSelected()); + childSetEnabled("Select", visibleItemsSelected()); } // Destroys the object diff --git a/indra/newview/llfloateravatarpicker.h b/indra/newview/llfloateravatarpicker.h index 56bc387bc..17b928f40 100644 --- a/indra/newview/llfloateravatarpicker.h +++ b/indra/newview/llfloateravatarpicker.h @@ -62,7 +62,7 @@ private: static void onRangeAdjust(LLUICtrl* source, void* data); static void onBtnClose(void* userdata); static void onList(class LLUICtrl* ctrl, void* userdata); - static void onTabChanged(void* userdata, bool from_click); + void onTabChanged(); void doCallingCardSelectionChange(const std::deque &items, BOOL user_action, void* data); static void onCallingCardSelectionChange(const std::deque &items, BOOL user_action, void* data); diff --git a/indra/newview/llfloatercustomize.cpp b/indra/newview/llfloatercustomize.cpp index dd8a3742c..890d80829 100644 --- a/indra/newview/llfloatercustomize.cpp +++ b/indra/newview/llfloatercustomize.cpp @@ -405,25 +405,19 @@ BOOL LLFloaterCustomize::postBuild() initWearablePanels(); // Tab container - const std::string &invalid_name = LLWearableType::getTypeName(LLWearableType::WT_INVALID); - for(U32 type=LLWearableType::WT_SHAPE;type("customize tab container"); + if(tab_container) { - std::string name = LLWearableType::getTypeName((LLWearableType::EType)type); - if(name != invalid_name) - { - name[0] = toupper(name[0]); - childSetTabChangeCallback("customize tab container", name, onTabChanged, (void*)type, onTabPrecommit ); - } + tab_container->setCommitCallback(boost::bind(&LLFloaterCustomize::onTabChanged, _2)); + tab_container->setValidateCallback(boost::bind(&LLFloaterCustomize::onTabPrecommit, this, _1, _2)); } // Remove underwear panels for teens if (gAgent.isTeen()) { - LLTabContainer* tab_container = getChild("customize tab container"); if (tab_container) { - LLPanel* panel; - panel = tab_container->getPanelByName("Undershirt"); + LLPanel* panel = tab_container->getPanelByName("Undershirt"); if (panel) tab_container->removeTabPanel(panel); panel = tab_container->getPanelByName("Underpants"); if (panel) tab_container->removeTabPanel(panel); @@ -553,7 +547,7 @@ void LLFloaterCustomize::onBtnExport_continued(AIFilePicker* filepicker) LLWearable* old_wearable = gAgentWearables.getWearable((LLWearableType::EType)i, 0); // TODO: MULTI-WEARABLE if( old_wearable ) { - item = (LLViewerInventoryItem*)gAgentWearables.getWearableInventoryItem((LLWearableType::EType)i, 0); // TODO: MULTI-WEARABLE + item = gInventory.getItem(old_wearable->getItemID()); if(item) { const LLPermissions& perm = item->getPermissions(); @@ -577,7 +571,7 @@ void LLFloaterCustomize::onBtnExport_continued(AIFilePicker* filepicker) LLWearable* old_wearable = gAgentWearables.getWearable((LLWearableType::EType)i, 0); // TODO: MULTI-WEARABLE if( old_wearable ) { - item = (LLViewerInventoryItem*)gAgentWearables.getWearableInventoryItem((LLWearableType::EType)i, 0); // TODO: MULTI-WEARABLE + item = gInventory.getItem(old_wearable->getItemID()); if(item) { const LLPermissions& perm = item->getPermissions(); @@ -728,39 +722,51 @@ void LLFloaterCustomize::draw() BOOL LLFloaterCustomize::isDirty() const { - for(S32 i = 0; i < LLWearableType::WT_COUNT; i++) + LLWearableType::EType cur = getCurrentWearableType(); + for(U32 i = 0; i < gAgentWearables.getWearableCount(cur); ++i) { - if( mWearablePanelList[i] - && mWearablePanelList[i]->isDirty() ) - { + LLWearable* wearable = gAgentWearables.getWearable(cur,i); + if(wearable && wearable->isDirty()) return TRUE; - } } return FALSE; } -// static -void LLFloaterCustomize::onTabPrecommit( void* userdata, bool from_click ) +bool LLFloaterCustomize::onTabPrecommit( LLUICtrl* ctrl, const LLSD& param ) { - LLWearableType::EType type = (LLWearableType::EType)(intptr_t) userdata; - if (type != LLWearableType::WT_INVALID && gFloaterCustomize && gFloaterCustomize->getCurrentWearableType() != type) + std::string panel_name = param.asString(); + for(U32 type=LLWearableType::WT_SHAPE;typeaskToSaveIfDirty(boost::bind(&onCommitChangeTab, _1)); - } - else - { - onCommitChangeTab(true); + std::string type_name = LLWearableType::getTypeName((LLWearableType::EType)type); + std::transform(panel_name.begin(), panel_name.end(), panel_name.begin(), tolower); + + if(type_name == panel_name) + { + if(LLFloaterCustomize::sCurrentWearableType != type) + { + askToSaveIfDirty(boost::bind(&LLFloaterCustomize::onCommitChangeTab, _1, (LLTabContainer*)ctrl, param.asString(), (LLWearableType::EType)type)); + return false; + } + } } + return true; } // static -void LLFloaterCustomize::onTabChanged( void* userdata, bool from_click ) +void LLFloaterCustomize::onTabChanged( const LLSD& param ) { - LLWearableType::EType wearable_type = (LLWearableType::EType) (intptr_t)userdata; - if (wearable_type != LLWearableType::WT_INVALID) + std::string panel_name = param.asString(); + for(U32 type=LLWearableType::WT_SHAPE;typegetChild("customize tab container"); - if (tab_container) - { - tab_container->setTab(-1); - } + LLFloaterCustomize::setCurrentWearableType(type); + ctrl->selectTabByName(panel_name); } @@ -812,7 +815,7 @@ void LLFloaterCustomize::initScrollingPanelList() } } -void LLFloaterCustomize::setWearable(LLWearableType::EType type, LLWearable* wearable) +void LLFloaterCustomize::wearablesChanged(LLWearableType::EType type) { llassert( type < LLWearableType::WT_COUNT ); gSavedSettings.setU32("AvatarSex", (gAgentAvatarp->getSex() == SEX_MALE) ); @@ -820,22 +823,7 @@ void LLFloaterCustomize::setWearable(LLWearableType::EType type, LLWearable* wea LLPanelEditWearable* panel = mWearablePanelList[ type ]; if( panel ) { - U32 perm_mask = wearable ? PERM_NONE : PERM_ALL; - BOOL is_complete = wearable ? FALSE : TRUE; - if(wearable) - { - LLViewerInventoryItem* item = (LLViewerInventoryItem*)gInventory.getItem(gAgentWearables.getWearableItemID(type, 0)); // TODO: MULTI-WEARABLE - if(item) - { - perm_mask = item->getPermissions().getMaskOwner(); - is_complete = item->isComplete(); - if(!is_complete) - { - item->fetchFromServer(); - } - } - } - panel->setWearable(wearable, perm_mask, is_complete); + panel->wearablesChanged(); } } @@ -846,7 +834,7 @@ void LLFloaterCustomize::updateScrollingPanelList() void LLFloaterCustomize::askToSaveIfDirty( boost::function cb ) { - if( isDirty()) + if(isDirty()) { // Ask if user wants to save, then continue to next step afterwards mNextStepAfterSaveCallback.connect(cb); @@ -857,7 +845,7 @@ void LLFloaterCustomize::askToSaveIfDirty( boost::function cb ) } else { - cb(TRUE); //just clal it immediately. + cb(TRUE); //just call it immediately. } } @@ -869,28 +857,36 @@ bool LLFloaterCustomize::onSaveDialog(const LLSD& notification, const LLSD& resp BOOL proceed = FALSE; LLWearableType::EType cur = getCurrentWearableType(); - switch( option ) + for(U32 i = 0;i < gAgentWearables.getWearableCount(cur);++i) { - case 0: // "Save" - gAgentWearables.saveWearable( cur, 0 ); // TODO: MULTI-WEARABLE - proceed = TRUE; - break; - - case 1: // "Don't Save" + LLWearable* wearable = gAgentWearables.getWearable(cur,i); + if(wearable && wearable->isDirty()) { - gAgentWearables.revertWearable( cur, 0 ); // TODO: MULTI-WEARABLE - proceed = TRUE; + switch( option ) + { + case 0: // "Save" + gAgentWearables.saveWearable( cur, i ); + proceed = TRUE; + break; + + case 1: // "Don't Save" + { + gAgentWearables.revertWearable( cur, i ); + proceed = TRUE; + } + break; + + case 2: // "Cancel" + break; + + default: + llassert(0); + break; + } } - break; - - case 2: // "Cancel" - break; - - default: - llassert(0); - break; } + mNextStepAfterSaveCallback(proceed); mNextStepAfterSaveCallback.disconnect_all_slots(); //Should this be done? @@ -913,10 +909,13 @@ void LLFloaterCustomize::fetchInventory() LLUUID item_id; for(S32 type = (S32)LLWearableType::WT_SHAPE; type < (S32)LLWearableType::WT_COUNT; ++type) { - item_id = gAgentWearables.getWearableItemID((LLWearableType::EType)type, 0); // TODO: MULTI-WEARABLE - if(item_id.notNull()) + for(U32 i = 0; i < gAgentWearables.getWearableCount((LLWearableType::EType)type); ++i) { - ids.push_back(item_id); + item_id = gAgentWearables.getWearableItemID((LLWearableType::EType)type, i); + if(item_id.notNull()) + { + ids.push_back(item_id); + } } } @@ -939,7 +938,9 @@ void LLFloaterCustomize::updateInventoryUI() panel = mWearablePanelList[i]; if(panel) { - item = (LLViewerInventoryItem*)gAgentWearables.getWearableInventoryItem(panel->getType(), 0); // TODO: MULTI-WEARABLE + LLWearable* wearable = panel->getWearable(); + if(wearable) + item = gInventory.getItem(wearable->getItemID()); } if(item) { @@ -961,8 +962,8 @@ void LLFloaterCustomize::updateInventoryUI() { panel->setUIPermissions(perm_mask, is_complete); } - BOOL is_vis = panel && item && is_complete && (perm_mask & PERM_MODIFY); - childSetVisible("panel_container", is_vis); + //BOOL is_vis = panel && item && is_complete && (perm_mask & PERM_MODIFY); + //childSetVisible("panel_container", is_vis); } } diff --git a/indra/newview/llfloatercustomize.h b/indra/newview/llfloatercustomize.h index 31343d199..e603209fe 100644 --- a/indra/newview/llfloatercustomize.h +++ b/indra/newview/llfloatercustomize.h @@ -55,7 +55,7 @@ class LLMakeOutfitDialog; class LLRadioGroup; class LLScrollableContainerView; class LLScrollingPanelList; -class LLTabContainerVertical; +class LLTabContainer; class LLTextBox; class LLTextureCtrl; class LLViewerJointMesh; @@ -84,7 +84,7 @@ public: // New methods - void setWearable(LLWearableType::EType type, LLWearable* wearable); + void wearablesChanged(LLWearableType::EType type); void updateScrollingPanelList(); LLPanelEditWearable* getCurrentWearablePanel() { return mWearablePanelList[ sCurrentWearableType ]; } @@ -106,10 +106,10 @@ public: static void onBtnExport( void* userdata ); static void onBtnExport_continued(AIFilePicker* filepicker); - static void onTabChanged( void* userdata, bool from_click ); - static void onTabPrecommit( void* userdata, bool from_click ); + static void onTabChanged( const LLSD& param ); + bool onTabPrecommit( LLUICtrl* ctrl, const LLSD& param ); bool onSaveDialog(const LLSD& notification, const LLSD& response); - static void onCommitChangeTab(BOOL proceed); + static void onCommitChangeTab(BOOL proceed, LLTabContainer* ctrl, std::string panel_name, LLWearableType::EType type); void fetchInventory(); void updateInventoryUI(); diff --git a/indra/newview/llfloaterdirectory.cpp b/indra/newview/llfloaterdirectory.cpp index 7546370cc..128d7a379 100644 --- a/indra/newview/llfloaterdirectory.cpp +++ b/indra/newview/llfloaterdirectory.cpp @@ -144,23 +144,7 @@ LLFloaterDirectory::LLFloaterDirectory(const std::string& name) mPanelAvatarp->selectTab(0); } - childSetTabChangeCallback("Directory Tabs", "classified_panel", onTabChanged, this); - childSetTabChangeCallback("Directory Tabs", "events_panel", onTabChanged, this); - childSetTabChangeCallback("Directory Tabs", "places_panel", onTabChanged, this); - childSetTabChangeCallback("Directory Tabs", "land_sales_panel", onTabChanged, this); - childSetTabChangeCallback("Directory Tabs", "people_panel", onTabChanged, this); - childSetTabChangeCallback("Directory Tabs", "groups_panel", onTabChanged, this); - if (enableWebSearch) - { - // web search and showcase for SecondLife - childSetTabChangeCallback("Directory Tabs", "find_all_panel", onTabChanged, this); - childSetTabChangeCallback("Directory Tabs", "showcase_panel", onTabChanged, this); - } - - if(enableClassicAllSearch) - { - childSetTabChangeCallback("Directory Tabs", "find_all_old_panel", onTabChanged, this); - } + getChild("Directory Tabs")->setCommitCallback(boost::bind(&LLFloaterDirectory::onTabChanged,_2)); } LLFloaterDirectory::~LLFloaterDirectory() @@ -508,16 +492,9 @@ void LLFloaterDirectory::onClose(bool app_quitting) } // static -void LLFloaterDirectory::onTabChanged(void* data, bool from_click) +void LLFloaterDirectory::onTabChanged( const LLSD& param ) { - LLFloaterDirectory* self = (LLFloaterDirectory*)data; - if (!self) return; - - LLPanel *panel = self->childGetVisibleTab("Directory Tabs"); - if (panel) - { - gSavedSettings.setString("LastFindPanel", panel->getName()); - } + gSavedSettings.setString("LastFindPanel", param.asString()); } void LLFloaterDirectory::hideAllDetailPanels() diff --git a/indra/newview/llfloaterdirectory.h b/indra/newview/llfloaterdirectory.h index e43968624..0f57b0ff7 100644 --- a/indra/newview/llfloaterdirectory.h +++ b/indra/newview/llfloaterdirectory.h @@ -81,7 +81,7 @@ public: static void toggleEvents(void*); static void toggleFind(void*); - static void onTabChanged(void*, bool); + static void onTabChanged( const LLSD& param ); void hideAllDetailPanels(); diff --git a/indra/newview/llfloatergodtools.cpp b/indra/newview/llfloatergodtools.cpp index 9a629d7d4..37bcb873b 100644 --- a/indra/newview/llfloatergodtools.cpp +++ b/indra/newview/llfloatergodtools.cpp @@ -130,10 +130,7 @@ LLFloaterGodTools::LLFloaterGodTools() factory_map["request"] = LLCallbackMap(createPanelRequest, this); LLUICtrlFactory::getInstance()->buildFloater(this, "floater_god_tools.xml", &factory_map); - childSetTabChangeCallback("GodTools Tabs", "grid", onTabChanged, this); - childSetTabChangeCallback("GodTools Tabs", "region", onTabChanged, this); - childSetTabChangeCallback("GodTools Tabs", "objects", onTabChanged, this); - childSetTabChangeCallback("GodTools Tabs", "request", onTabChanged, this); + getChild("GodTools Tabs")->setCommitCallback(boost::bind(&LLFloaterGodTools::onTabChanged,_1,_2)); sendRegionInfoRequest(); @@ -244,15 +241,12 @@ void LLFloaterGodTools::showPanel(const std::string& panel_name) if (panel) panel->setFocus(TRUE); } - -// static -void LLFloaterGodTools::onTabChanged(void* data, bool from_click) +//static +void LLFloaterGodTools::onTabChanged(LLUICtrl* ctrl, const LLSD& param) { - LLPanel* panel = (LLPanel*)data; - if (panel) - { + LLPanel* panel = (LLPanel*)ctrl->getChildView(param.asString(),false,false); + if(panel) panel->setFocus(TRUE); - } } diff --git a/indra/newview/llfloatergodtools.h b/indra/newview/llfloatergodtools.h index 75813ca88..3c36f256f 100644 --- a/indra/newview/llfloatergodtools.h +++ b/indra/newview/llfloatergodtools.h @@ -101,7 +101,7 @@ public: // Send possibly changed values to simulator. void sendGodUpdateRegionInfo(); - static void onTabChanged(void *data, bool from_click); + static void onTabChanged(LLUICtrl* ctrl, const LLSD& param); protected: U32 computeRegionFlags() const; diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index 6e102d58c..d5e9702d7 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -144,39 +144,39 @@ LLPreferenceCore::LLPreferenceCore(LLTabContainer* tab_container, LLButton * def mPrefsAscentVan(NULL) { mGeneralPanel = new LLPanelGeneral(); - mTabContainer->addTabPanel(mGeneralPanel, mGeneralPanel->getLabel(), FALSE, onTabChanged, mTabContainer); + mTabContainer->addTabPanel(mGeneralPanel, mGeneralPanel->getLabel()); mGeneralPanel->setDefaultBtn(default_btn); mInputPanel = new LLPanelInput(); - mTabContainer->addTabPanel(mInputPanel, mInputPanel->getLabel(), FALSE, onTabChanged, mTabContainer); + mTabContainer->addTabPanel(mInputPanel, mInputPanel->getLabel()); mInputPanel->setDefaultBtn(default_btn); mNetworkPanel = new LLPanelNetwork(); - mTabContainer->addTabPanel(mNetworkPanel, mNetworkPanel->getLabel(), FALSE, onTabChanged, mTabContainer); + mTabContainer->addTabPanel(mNetworkPanel, mNetworkPanel->getLabel()); mNetworkPanel->setDefaultBtn(default_btn); mWebPanel = new LLPanelWeb(); - mTabContainer->addTabPanel(mWebPanel, mWebPanel->getLabel(), FALSE, onTabChanged, mTabContainer); + mTabContainer->addTabPanel(mWebPanel, mWebPanel->getLabel()); mWebPanel->setDefaultBtn(default_btn); mDisplayPanel = new LLPanelDisplay(); - mTabContainer->addTabPanel(mDisplayPanel, mDisplayPanel->getLabel(), FALSE, onTabChanged, mTabContainer); + mTabContainer->addTabPanel(mDisplayPanel, mDisplayPanel->getLabel()); mDisplayPanel->setDefaultBtn(default_btn); mAudioPanel = new LLPanelAudioPrefs(); - mTabContainer->addTabPanel(mAudioPanel, mAudioPanel->getLabel(), FALSE, onTabChanged, mTabContainer); + mTabContainer->addTabPanel(mAudioPanel, mAudioPanel->getLabel()); mAudioPanel->setDefaultBtn(default_btn); mPrefsChat = new LLPrefsChat(); - mTabContainer->addTabPanel(mPrefsChat->getPanel(), mPrefsChat->getPanel()->getLabel(), FALSE, onTabChanged, mTabContainer); + mTabContainer->addTabPanel(mPrefsChat->getPanel(), mPrefsChat->getPanel()->getLabel()); mPrefsChat->getPanel()->setDefaultBtn(default_btn); mPrefsVoice = new LLPrefsVoice(); - mTabContainer->addTabPanel(mPrefsVoice, mPrefsVoice->getLabel(), FALSE, onTabChanged, mTabContainer); + mTabContainer->addTabPanel(mPrefsVoice, mPrefsVoice->getLabel()); mPrefsVoice->setDefaultBtn(default_btn); mPrefsIM = new LLPrefsIM(); - mTabContainer->addTabPanel(mPrefsIM->getPanel(), mPrefsIM->getPanel()->getLabel(), FALSE, onTabChanged, mTabContainer); + mTabContainer->addTabPanel(mPrefsIM->getPanel(), mPrefsIM->getPanel()->getLabel()); mPrefsIM->getPanel()->setDefaultBtn(default_btn); #if LL_LCD_COMPILE @@ -185,7 +185,7 @@ LLPreferenceCore::LLPreferenceCore(LLTabContainer* tab_container, LLButton * def if (gLcdScreen->Enabled()) { mLCDPanel = new LLPanelLCD(); - mTabContainer->addTabPanel(mLCDPanel, mLCDPanel->getLabel(), FALSE, onTabChanged, mTabContainer); + mTabContainer->addTabPanel(mLCDPanel, mLCDPanel->getLabel()); mLCDPanel->setDefaultBtn(default_btn); } @@ -194,29 +194,31 @@ LLPreferenceCore::LLPreferenceCore(LLTabContainer* tab_container, LLButton * def #endif mMsgPanel = new LLPanelMsgs(); - mTabContainer->addTabPanel(mMsgPanel, mMsgPanel->getLabel(), FALSE, onTabChanged, mTabContainer); + mTabContainer->addTabPanel(mMsgPanel, mMsgPanel->getLabel()); mMsgPanel->setDefaultBtn(default_btn); mSkinsPanel = new LLPanelSkins(); - mTabContainer->addTabPanel(mSkinsPanel, mSkinsPanel->getLabel(), FALSE, onTabChanged, mTabContainer); + mTabContainer->addTabPanel(mSkinsPanel, mSkinsPanel->getLabel()); mSkinsPanel->setDefaultBtn(default_btn); mGridsPanel = HippoPanelGrids::create(); - mTabContainer->addTabPanel(mGridsPanel, mGridsPanel->getLabel(), FALSE, onTabChanged, mTabContainer); + mTabContainer->addTabPanel(mGridsPanel, mGridsPanel->getLabel()); mGridsPanel->setDefaultBtn(default_btn); mPrefsAscentChat = new LLPrefsAscentChat(); - mTabContainer->addTabPanel(mPrefsAscentChat, mPrefsAscentChat->getLabel(), FALSE, onTabChanged, mTabContainer); + mTabContainer->addTabPanel(mPrefsAscentChat, mPrefsAscentChat->getLabel()); mPrefsAscentChat->setDefaultBtn(default_btn); mPrefsAscentSys = new LLPrefsAscentSys(); - mTabContainer->addTabPanel(mPrefsAscentSys, mPrefsAscentSys->getLabel(), FALSE, onTabChanged, mTabContainer); + mTabContainer->addTabPanel(mPrefsAscentSys, mPrefsAscentSys->getLabel()); mPrefsAscentSys->setDefaultBtn(default_btn); mPrefsAscentVan = new LLPrefsAscentVan(); - mTabContainer->addTabPanel(mPrefsAscentVan, mPrefsAscentVan->getLabel(), FALSE, onTabChanged, mTabContainer); + mTabContainer->addTabPanel(mPrefsAscentVan, mPrefsAscentVan->getLabel()); mPrefsAscentVan->setDefaultBtn(default_btn); + mTabContainer->setCommitCallback(boost::bind(LLPreferenceCore::onTabChanged,_1)); + if (!mTabContainer->selectTab(gSavedSettings.getS32("LastPrefTab"))) { mTabContainer->selectFirstTab(); @@ -363,9 +365,9 @@ void LLPreferenceCore::cancel() } // static -void LLPreferenceCore::onTabChanged(void* user_data, bool from_click) +void LLPreferenceCore::onTabChanged(LLUICtrl* ctrl) { - LLTabContainer* self = (LLTabContainer*)user_data; + LLTabContainer* self = (LLTabContainer*)ctrl; gSavedSettings.setS32("LastPrefTab", self->getCurrentPanelIndex()); } diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h index a662a08c7..747a3ffb5 100644 --- a/indra/newview/llfloaterpreference.h +++ b/indra/newview/llfloaterpreference.h @@ -78,7 +78,7 @@ public: void setPersonalInfo(const std::string& visibility, bool im_via_email, const std::string& email); - static void onTabChanged(void* user_data, bool from_click); + static void onTabChanged(LLUICtrl* ctrl); // refresh all the graphics preferences menus void refreshEnabledGraphics(); diff --git a/indra/newview/llfloatertest.cpp b/indra/newview/llfloatertest.cpp index e9aada3f6..83a0c6fed 100644 --- a/indra/newview/llfloatertest.cpp +++ b/indra/newview/llfloatertest.cpp @@ -160,6 +160,8 @@ LLFloaterTestImpl::LLFloaterTestImpl() addChild(tab); mTab = tab; + tab->setCommitCallback(boost::bind(&LLFloaterTestImpl::onClickTab,_1,_2)); + //----------------------------------------------------------------------- // First tab container panel //----------------------------------------------------------------------- @@ -167,8 +169,7 @@ LLFloaterTestImpl::LLFloaterTestImpl() LLRect(0, 400, 400, 0), // dummy rect TRUE); // bordered tab->addTabPanel(panel, std::string("First"), - TRUE, // select - onClickTab, this); + TRUE); // select y = panel->getRect().getHeight() - VPAD; @@ -284,8 +285,7 @@ LLFloaterTestImpl::LLFloaterTestImpl() LLRect(0, 400, 400, 0), // dummy rect TRUE); // bordered tab->addTabPanel(panel, std::string("Second"), - FALSE, // select - onClickTab, this); + FALSE); // select y = panel->getRect().getHeight() - VPAD; diff --git a/indra/newview/llpaneleditwearable.cpp b/indra/newview/llpaneleditwearable.cpp index 99917d91e..953d4c243 100644 --- a/indra/newview/llpaneleditwearable.cpp +++ b/indra/newview/llpaneleditwearable.cpp @@ -607,12 +607,14 @@ private: std::string mItemName; void (*mCommitCallback)(LLWearableSaveAsDialog*,void*); void* mCallbackUserData; + LLPanelEditWearable* mParent; public: - LLWearableSaveAsDialog( const std::string& desc, void(*commit_cb)(LLWearableSaveAsDialog*,void*), void* userdata ) + LLWearableSaveAsDialog( const std::string& desc, LLPanelEditWearable* parent, void(*commit_cb)(LLWearableSaveAsDialog*,void*), void* userdata ) : LLModalDialog( LLStringUtil::null, 240, 100 ), mCommitCallback( commit_cb ), - mCallbackUserData( userdata ) + mCallbackUserData( userdata ), + mParent( parent ) { LLUICtrlFactory::getInstance()->buildFloater(this, "floater_wearable_save_as.xml"); @@ -621,7 +623,11 @@ public: childSetTextArg("name ed", "[DESC]", desc); } - + ~LLWearableSaveAsDialog() + { + if(mParent && mParent->mActiveModal == this) + mParent->mActiveModal = NULL; + } virtual void startModal() { LLModalDialog::startModal(); @@ -658,11 +664,20 @@ public: LLPanelEditWearable::LLPanelEditWearable( LLWearableType::EType type ) : LLPanel( LLWearableType::getTypeLabel( type ) ), - mType( type ) + mType( type ), + mActiveModal( NULL ), + mCurrentIndex( 0 ), + mCurrentWearable( NULL ), + mPendingWearable( NULL ), + mPendingRefresh( false ) { } LLPanelEditWearable::~LLPanelEditWearable() { + if(mActiveModal) + { + mActiveModal->close(); + } } BOOL LLPanelEditWearable::postBuild() @@ -729,6 +744,23 @@ BOOL LLPanelEditWearable::postBuild() for_each_picker_ctrl_entry (this, mType, boost::bind(init_color_swatch_ctrl, this, _1, _2)); for_each_picker_ctrl_entry (this, mType, boost::bind(init_texture_ctrl, this, _1, _2)); } + + LLTabContainer* tab = getChild("layer_tabs", true, false); + if(tab) + { + for(U32 i = 1; i <= LLAgentWearables::MAX_CLOTHING_PER_TYPE; ++i) + { + LLPanel* new_panel = new LLPanel(llformat("%i",i)); + tab->addTabPanel(new_panel, llformat("Layer %i",i)); + } + tab->setCommitCallback(boost::bind(&LLPanelEditWearable::onTabChanged, this, _1)); + tab->setValidateCallback(boost::bind(&LLPanelEditWearable::onTabPrecommit, this)); + } + + childSetTextArg("title_not_worn", "[DESC]", LLWearableType::getTypeLabel( mType )); + childSetTextArg("title_loading", "[DESC]", LLWearableType::getTypeLabel( mType )); + childSetTextArg("title_no_modify", "[DESC]", LLWearableType::getTypeLabel( mType )); + childSetTextArg("title", "[DESC]", LLWearableType::getTypeLabel( mType )); return TRUE; } @@ -743,8 +775,11 @@ void LLPanelEditWearable::draw() if( gFloaterCustomize->isMinimized() || !isAgentAvatarValid()) return; + refreshWearables(false); + LLWearable* wearable = getWearable(); BOOL has_wearable = (wearable != NULL ); + BOOL has_any_wearable = has_wearable || gAgentWearables.getWearableCount(mType); BOOL is_dirty = isDirty(); BOOL is_modifiable = FALSE; BOOL is_copyable = FALSE; @@ -758,16 +793,49 @@ void LLPanelEditWearable::draw() is_complete = ((LLViewerInventoryItem*)item)->isComplete(); } - childSetEnabled("Save", is_modifiable && is_complete && has_wearable && is_dirty); - childSetEnabled("Save As", is_copyable && is_complete && has_wearable); - childSetEnabled("Revert", has_wearable && is_dirty ); - childSetEnabled("Take Off", has_wearable ); - childSetVisible("Take Off", mCanTakeOff && has_wearable ); - childSetVisible("Create New", !has_wearable ); + childSetEnabled("Save", has_wearable && is_modifiable && is_complete && is_dirty); + childSetEnabled("Save As", has_wearable && is_copyable && is_complete); + childSetEnabled("Revert", has_wearable && is_dirty ); + childSetEnabled("Take Off", has_wearable); + childSetVisible("Take Off", has_wearable && mCanTakeOff); + childSetVisible("Create New", !has_any_wearable); + childSetVisible("not worn instructions", !has_any_wearable); + childSetVisible("title_not_worn", !has_any_wearable); + childSetVisible("no modify instructions",has_wearable && !is_modifiable); + childSetVisible("title_no_modify", has_wearable && !is_modifiable); + childSetVisible("title", has_wearable && is_modifiable && is_complete); + childSetVisible("title_loading", (!has_wearable && has_any_wearable) || (has_wearable && is_modifiable && !is_complete)); + childSetVisible("path", has_wearable); + childSetVisible("square", has_wearable && !is_modifiable); //lock icon - childSetVisible("not worn instructions", !has_wearable ); - childSetVisible("no modify instructions", has_wearable && !is_modifiable); + /*LLTabContainer* tab = getChild("layer_tabs", true, false); + if(tab) + { + tab->setEnabled(has_any_wearable); + tab->setVisible(has_any_wearable); + }*/ + if(has_wearable && is_modifiable) + { + for_each_picker_ctrl_entry (this, mType, boost::bind(update_color_swatch_ctrl, this, _1, _2)); + for_each_picker_ctrl_entry (this, mType, boost::bind(update_texture_ctrl, this, _1, _2)); + for_each_picker_ctrl_entry (this, mType, boost::bind(set_enabled_color_swatch_ctrl, is_complete, _1, _2)); + for_each_picker_ctrl_entry (this, mType, boost::bind(set_enabled_texture_ctrl, is_complete, _1, _2)); + for(string_texture_index_map_t::iterator iter = mAlphaCheckbox2Index.begin(); + iter != mAlphaCheckbox2Index.end(); ++iter ) + { + LLCheckBoxCtrl* ctrl = getChild(iter->first, true, false); + if (ctrl) + { + ctrl->setEnabled(is_copyable && is_complete); + ctrl->setVisible(is_copyable && is_complete); + } + } + } + else + { + hideTextureControls(); + } const LLEditWearableDictionary::WearableEntry *wearable_entry = LLEditWearableDictionary::getInstance()->getWearable(mType); if (wearable_entry) @@ -798,15 +866,6 @@ void LLPanelEditWearable::draw() } } - childSetVisible("square", !is_modifiable); - - childSetVisible("title", FALSE); - childSetVisible("title_no_modify", FALSE); - childSetVisible("title_not_worn", FALSE); - childSetVisible("title_loading", FALSE); - - childSetVisible("path", FALSE); - LLTextBox *av_height = getChild("avheight",FALSE,FALSE); if(av_height) //Only display this if the element exists { @@ -825,65 +884,6 @@ void LLPanelEditWearable::draw() av_height->setVisible(TRUE); av_height->setTextArg("[AVHEIGHT]",avheight.str()); } - - if(has_wearable && !is_modifiable) - { - // *TODO:Translate - childSetVisible("title_no_modify", TRUE); - childSetTextArg("title_no_modify", "[DESC]", std::string(LLWearableType::getTypeLabel( mType ))); - - hideTextureControls(); - } - else if(has_wearable && !is_complete) - { - // *TODO:Translate - childSetVisible("title_loading", TRUE); - childSetTextArg("title_loading", "[DESC]", std::string(LLWearableType::getTypeLabel( mType ))); - - std::string path; - const LLUUID& item_id = wearable->getItemID(); - append_path(item_id, path); - childSetVisible("path", TRUE); - childSetTextArg("path", "[PATH]", path); - - hideTextureControls(); - } - else if(has_wearable && is_modifiable) - { - childSetVisible("title", TRUE); - childSetTextArg("title", "[DESC]", wearable->getName() ); - - std::string path; - const LLUUID& item_id = wearable->getItemID(); - append_path(item_id, path); - childSetVisible("path", TRUE); - childSetTextArg("path", "[PATH]", path); - - for_each_picker_ctrl_entry (this, mType, boost::bind(update_color_swatch_ctrl, this, _1, _2)); - for_each_picker_ctrl_entry (this, mType, boost::bind(update_texture_ctrl, this, _1, _2)); - for_each_picker_ctrl_entry (this, mType, boost::bind(set_enabled_color_swatch_ctrl, is_complete, _1, _2)); - for_each_picker_ctrl_entry (this, mType, boost::bind(set_enabled_texture_ctrl, is_complete, _1, _2)); - for(string_texture_index_map_t::iterator iter = mAlphaCheckbox2Index.begin(); - iter != mAlphaCheckbox2Index.end(); ++iter ) - { - LLCheckBoxCtrl* ctrl = getChild(iter->first, true, false); - if (ctrl) - { - ctrl->setEnabled(is_copyable && is_complete); - ctrl->setVisible(is_copyable && is_complete); - } - } - } - else - { - // *TODO:Translate - childSetVisible("title_not_worn", TRUE); - childSetTextArg("title_not_worn", "[DESC]", std::string(LLWearableType::getTypeLabel( mType ))); - - hideTextureControls(); - } - - childSetVisible("icon", has_wearable && is_modifiable); LLPanel::draw(); } @@ -897,17 +897,84 @@ void LLPanelEditWearable::setVisible(BOOL visible) } } -void LLPanelEditWearable::setWearable(LLWearable* wearable, U32 perm_mask, BOOL is_complete) +void LLPanelEditWearable::onTabChanged(LLUICtrl* ctrl) { - if( wearable ) + if(mPendingWearable) + return; + U32 tab_index = ((LLTabContainer*)ctrl)->getCurrentPanelIndex(); + U32 wearable_index = gAgentWearables.getWearableCount(mType) - tab_index - 1; + if(wearable_index != mCurrentIndex ) { - setUIPermissions(perm_mask, is_complete); - if (mType == LLWearableType::WT_ALPHA) + setWearableIndex(wearable_index); + } +} + +bool LLPanelEditWearable::onTabPrecommit() +{ + return !mPendingWearable; +} + +void LLPanelEditWearable::setWearableIndex(S32 index) +{ + if(mPendingWearable) + return; + + mCurrentIndex = index; + + LLTabContainer* tab = getChild("layer_tabs", true, false); + if(tab) + { + U32 tab_index = gAgentWearables.getWearableCount(mType) - index - 1; + + if(tab->getCurrentPanelIndex() != tab_index) + tab->selectTab(tab_index); + } + + LLWearable* wearable = gAgentWearables.getWearable(mType,mCurrentIndex); + + if(wearable == getWearable()) + return; + + mCurrentWearable = wearable; + + + if(wearable) + { + childSetTextArg("title", "[DESC]", wearable->getName() ); + childSetTextArg("title_no_modify", "[DESC]", wearable->getName()); + } + else + { + childSetTextArg("title", "[DESC]", std::string(LLWearableType::getTypeLabel( mType )) ); + childSetTextArg("title_no_modify", "[DESC]", std::string(LLWearableType::getTypeLabel( mType ))); + } + + if(mActiveModal) + mActiveModal->close(); + + U32 perm_mask = wearable ? PERM_NONE : PERM_ALL; + BOOL is_complete = wearable ? FALSE : TRUE; + if(wearable) + { + LLViewerInventoryItem* item = (LLViewerInventoryItem*)gInventory.getItem(wearable->getItemID()); + if(item) { - initPreviousAlphaTextures(); - updateAlphaCheckboxes(); + perm_mask = item->getPermissions().getMaskOwner(); + is_complete = item->isComplete(); + if(!is_complete) + { + item->fetchFromServer(); + } } } + setUIPermissions(perm_mask, is_complete); + if (mType == LLWearableType::WT_ALPHA) + { + initPreviousAlphaTextures(); + updateAlphaCheckboxes(); + + } + const LLEditWearableDictionary::SubpartEntry *subpart_entry = LLEditWearableDictionary::getInstance()->getSubpart(mCurrentSubpart); if(subpart_entry) { @@ -916,7 +983,60 @@ void LLPanelEditWearable::setWearable(LLWearable* wearable, U32 perm_mask, BOOL buildParamList(gFloaterCustomize->getScrollingPanelList(), sorted_params); } + if(wearable) + { + std::string path; + const LLUUID& item_id = wearable->getItemID(); + append_path(item_id, path); + childSetTextArg("path", "[PATH]", path); + } + updateScrollingPanelList(); + +} + +void LLPanelEditWearable::refreshWearables(bool force_immediate) +{ + if(!force_immediate && !mPendingRefresh) + return; + + mPendingRefresh = false; + + U32 index; + if(mPendingWearable) + { + index = gAgentWearables.getWearableIndex(mPendingWearable); + if(index == LLAgentWearables::MAX_CLOTHING_PER_TYPE) + return; + mPendingWearable = NULL; + } + else + { + index = gAgentWearables.getWearableIndex(getWearable()); + if(index == LLAgentWearables::MAX_CLOTHING_PER_TYPE) + { + index = gAgentWearables.getWearableCount(mType); + if(index) + --index; + } + } + + + + LLTabContainer* tab = getChild("layer_tabs", true, false); + if(tab) + { + for(U32 i = 0; i < LLAgentWearables::MAX_CLOTHING_PER_TYPE; ++i) + { + tab->enableTabButton(i, i < gAgentWearables.getWearableCount(mType)); + } + } + setWearableIndex(index); +} + +void LLPanelEditWearable::wearablesChanged() +{ + mPendingRefresh = true; } // static @@ -936,11 +1056,13 @@ void LLPanelEditWearable::onBtnSave( void* userdata ) void LLPanelEditWearable::onBtnSaveAs( void* userdata ) { LLPanelEditWearable* self = (LLPanelEditWearable*) userdata; - LLWearable* wearable = gAgentWearables.getWearable( self->getType(), 0 ); // TODO: MULTI-WEARABLE + if(self->mActiveModal) + return; + LLWearable* wearable = self->getWearable(); if( wearable ) { - LLWearableSaveAsDialog* save_as_dialog = new LLWearableSaveAsDialog( wearable->getName(), onSaveAsCommit, self ); - save_as_dialog->startModal(); + self->mActiveModal = new LLWearableSaveAsDialog( wearable->getName(), self, onSaveAsCommit, self ); + self->mActiveModal->startModal(); // LLWearableSaveAsDialog deletes itself. } } @@ -958,7 +1080,7 @@ void LLPanelEditWearable::onCommitSexChange() if (!isAgentAvatarValid()) return; LLWearableType::EType type = mType; // TODO: MULTI-WEARABLE - U32 index = 0; // TODO: MULTI-WEARABLE + U32 index = mCurrentIndex; // TODO: MULTI-WEARABLE if( !gAgentWearables.isWearableModifiable(type, index)) { @@ -1039,7 +1161,7 @@ bool LLPanelEditWearable::onSelectAutoWearOption(const LLSD& notification, const LLWearable* LLPanelEditWearable::getWearable() const { - return gAgentWearables.getWearable(mType, 0); // TODO: MULTI-WEARABLE + return mCurrentWearable;//gAgentWearables.getWearable(mType, mCurrentIndex); // TODO: MULTI-WEARABLE } @@ -1132,7 +1254,7 @@ void LLPanelEditWearable::hideTextureControls() void LLPanelEditWearable::saveChanges(bool force_save_as, std::string new_name) { - if (!getWearable() || !isDirty()) + if (!getWearable() || (!force_save_as && !isDirty())) { // do nothing if no unsaved changes return; @@ -1144,9 +1266,15 @@ void LLPanelEditWearable::saveChanges(bool force_save_as, std::string new_name) { // the name of the wearable has changed, re-save wearable with new name LLAppearanceMgr::instance().removeCOFItemLinks(getWearable()->getItemID(),false); - gAgentWearables.saveWearableAs(mType, index, new_name, FALSE); - childSetTextArg("title", "[DESC]", new_name ); - } + LLWearable* new_wearable = gAgentWearables.saveWearableAs(mType, index, new_name, FALSE); + if(new_wearable) + { + mPendingWearable = new_wearable; + mCurrentWearable = new_wearable; + childSetTextArg("title", "[DESC]", new_wearable->getName()); + childSetTextArg("title_no_modify", "[DESC]", new_wearable->getName()); + } + } else { gAgentWearables.saveWearable(mType, index, TRUE, new_name); @@ -1173,6 +1301,7 @@ void LLPanelEditWearable::revertChanges() void LLPanelEditWearable::showDefaultSubpart() { + refreshWearables(true); changeCamera(0); } @@ -1312,7 +1441,7 @@ void LLPanelEditWearable::updateScrollingPanelUI() return; } - llinfos << llformat("%#.8lX",wearable) << llendl; + llinfos << llformat("%#.8lX",wearable) << llendl; llinfos << "cur_wearable->isDirty()=" << wearable->isDirty() << llendl; LLViewerInventoryItem* item = gInventory.getItem(wearable->getItemID()); @@ -1330,13 +1459,14 @@ void LLPanelEditWearable::onBtnTakeOff( void* userdata ) { LLPanelEditWearable* self = (LLPanelEditWearable*) userdata; - LLWearable* wearable = gAgentWearables.getWearable( self->mType, 0 ); // TODO: MULTI-WEARABLE + LLWearable* wearable = self->getWearable(); if( !wearable ) { return; } - gAgentWearables.removeWearable( self->mType, false, 0 ); // TODO: MULTI-WEARABLE + LLAppearanceMgr::instance().removeItemFromAvatar(wearable->getItemID()); + self->refreshWearables(true); } // static @@ -1382,7 +1512,7 @@ void LLPanelEditWearable::buildParamList(LLScrollingPanelList *panel_list, value for(value_map_t::iterator it = sorted_params.begin(); it != end; ++it) { LLScrollingPanelParam *panel_param = NULL; - panel_param = new LLScrollingPanelParam( "LLScrollingPanelParam", NULL, (*it).second.second, (*it).second.first, (mType != LLWearableType::WT_PHYSICS)); + panel_param = new LLScrollingPanelParam( "LLScrollingPanelParam", NULL, (*it).second.second, (*it).second.first, getWearable(), (mType != LLWearableType::WT_PHYSICS)); panel_list->addPanel( panel_param ); } } diff --git a/indra/newview/llpaneleditwearable.h b/indra/newview/llpaneleditwearable.h index 8f732244a..412e6227b 100644 --- a/indra/newview/llpaneleditwearable.h +++ b/indra/newview/llpaneleditwearable.h @@ -67,7 +67,12 @@ public: LLWearableType::EType getType() const{ return mType; } LLWearable* getWearable() const; - void setWearable(LLWearable* wearable, U32 perm_mask, BOOL is_complete); + void onTabChanged(LLUICtrl* ctrl); + bool onTabPrecommit(); + + void setWearableIndex(S32 index); + void refreshWearables(bool force_immediate); + void wearablesChanged(); void saveChanges(bool force_save_as = false, std::string new_name = std::string()); @@ -124,6 +129,14 @@ private: typedef std::map s32_uuid_map_t; s32_uuid_map_t mPreviousAlphaTexture; ESubpart mCurrentSubpart; + U32 mCurrentIndex; + LLWearable* mCurrentWearable; + LLWearable* mPendingWearable; //For SaveAs. There's a period where the old wearable will be removed, but the new one will still be pending, + //so this is needed to retain focus on this wearables tab over the messy transition. + bool mPendingRefresh; //LLAgentWearables::setWearableOutfit fires a buttload of remove/wear calls which spams wearablesChanged + //a bazillion pointless (and not particularly valid) times. Deferring to draw effectively sorts it all out. +public: + LLModalDialog* mActiveModal; }; #endif diff --git a/indra/newview/llpanelgroup.cpp b/indra/newview/llpanelgroup.cpp index b1e55d30c..49b59720d 100644 --- a/indra/newview/llpanelgroup.cpp +++ b/indra/newview/llpanelgroup.cpp @@ -250,10 +250,8 @@ BOOL LLPanelGroup::postBuild() // Pass on whether or not to allow edit to tabs. panelp->setAllowEdit(mAllowEdit); panelp->addObserver(this); - - mTabContainer->setTabChangeCallback(panelp, onClickTab); - mTabContainer->setTabUserData(panelp, this); } + mTabContainer->setCommitCallback(boost::bind(&LLPanelGroup::handleClickTab,this)); updateTabVisibility(); // Act as though this tab was just activated. @@ -321,13 +319,6 @@ void LLPanelGroup::tabChanged() } } -// static -void LLPanelGroup::onClickTab(void* user_data, bool from_click) -{ - LLPanelGroup* self = static_cast(user_data); - self->handleClickTab(); -} - void LLPanelGroup::handleClickTab() { // If we are already handling a transition, @@ -377,7 +368,7 @@ void LLPanelGroup::selectTab(std::string tab_name) if ( tabp && mTabContainer ) { mTabContainer->selectTabPanel(tabp); - onClickTab(this, false); + handleClickTab(); } } diff --git a/indra/newview/llpanelgroup.h b/indra/newview/llpanelgroup.h index 445fb2850..52cb72f36 100644 --- a/indra/newview/llpanelgroup.h +++ b/indra/newview/llpanelgroup.h @@ -70,7 +70,6 @@ public: static void onBtnCancel(void*); static void onBtnApply(void*); static void onBtnRefresh(void*); - static void onClickTab(void*,bool); void handleClickTab(); void setGroupID(const LLUUID& group_id); diff --git a/indra/newview/llpanelgrouplandmoney.cpp b/indra/newview/llpanelgrouplandmoney.cpp index fa0432b6c..4baa6cd8b 100644 --- a/indra/newview/llpanelgrouplandmoney.cpp +++ b/indra/newview/llpanelgrouplandmoney.cpp @@ -82,7 +82,7 @@ public: static void clickEarlierCallback(void* data); static void clickLaterCallback(void* data); - static void clickTabCallback(void* user_data, bool from_click); + void clickTabCallback(const LLSD ¶m); static LLMap sInstanceIDs; static std::map sTabsToHandlers; @@ -924,8 +924,7 @@ LLGroupMoneyTabEventHandler::LLGroupMoneyTabEventHandler(LLButton* earlier_butto if ( tab_containerp && panelp ) { - tab_containerp->setTabChangeCallback(panelp, clickTabCallback); - tab_containerp->setTabUserData(panelp, this); + tab_containerp->setCommitCallback(boost::bind(&LLGroupMoneyTabEventHandler::clickTabCallback, this, _2)); } sInstanceIDs.addData(mImplementationp->mPanelID, this); @@ -997,11 +996,10 @@ void LLGroupMoneyTabEventHandler::clickLaterCallback(void* data) if ( selfp ) selfp->onClickLater(); } -//static -void LLGroupMoneyTabEventHandler::clickTabCallback(void* data, bool from_click) +void LLGroupMoneyTabEventHandler::clickTabCallback(const LLSD& param) { - LLGroupMoneyTabEventHandler* selfp = (LLGroupMoneyTabEventHandler*) data; - if ( selfp ) selfp->onClickTab(); + if(param.asString() == "group_money_details_tab") + onClickTab(); } // ************************************************** diff --git a/indra/newview/llpanelgrouproles.cpp b/indra/newview/llpanelgrouproles.cpp index cf07b5edb..155ab8dde 100644 --- a/indra/newview/llpanelgrouproles.cpp +++ b/indra/newview/llpanelgrouproles.cpp @@ -147,10 +147,6 @@ BOOL LLPanelGroupRoles::postBuild() { LLPanelGroupSubTab* subtabp = (LLPanelGroupSubTab*) mSubTabContainer->getPanelByIndex(i); - // Add click callbacks to all the tabs. - mSubTabContainer->setTabChangeCallback(subtabp, onClickSubTab); - mSubTabContainer->setTabUserData(subtabp, this); - // Hand the subtab a pointer to this LLPanelGroupRoles, so that it can // look around for the widgets it is interested in. if (!subtabp->postBuildSubTab(this)) return FALSE; @@ -158,6 +154,9 @@ BOOL LLPanelGroupRoles::postBuild() subtabp->addObserver(this); } + // Add click callbacks to all the tabs. + mSubTabContainer->setCommitCallback(boost::bind(&LLPanelGroupRoles::handleClickSubTab,this)); + // Set the current tab to whatever is currently being shown. mCurrentTab = (LLPanelGroupTab*) mSubTabContainer->getCurrentPanel(); if (!mCurrentTab) @@ -198,13 +197,6 @@ BOOL LLPanelGroupRoles::isVisibleByAgent(LLAgent* agentp) } -// static -void LLPanelGroupRoles::onClickSubTab(void* user_data, bool from_click) -{ - LLPanelGroupRoles* self = static_cast(user_data); - self->handleClickSubTab(); -} - void LLPanelGroupRoles::handleClickSubTab() { // If we are already handling a transition, diff --git a/indra/newview/llpanelgrouproles.h b/indra/newview/llpanelgrouproles.h index 3083c2d56..8ceac9b44 100644 --- a/indra/newview/llpanelgrouproles.h +++ b/indra/newview/llpanelgrouproles.h @@ -64,7 +64,6 @@ public: virtual BOOL isVisibleByAgent(LLAgent* agentp); static void* createTab(void* data); - static void onClickSubTab(void*,bool); void handleClickSubTab(); // Checks if the current tab needs to be applied, and tries to switch to the requested tab. diff --git a/indra/newview/llpanelmaininventory.cpp b/indra/newview/llpanelmaininventory.cpp index f37772a37..d2cbb0ca2 100644 --- a/indra/newview/llpanelmaininventory.cpp +++ b/indra/newview/llpanelmaininventory.cpp @@ -215,9 +215,7 @@ BOOL LLInventoryView::postBuild() sActiveViews.put(this); - childSetTabChangeCallback("inventory filter tabs", "All Items", onFilterSelected, this); - childSetTabChangeCallback("inventory filter tabs", "Recent Items", onFilterSelected, this); - childSetTabChangeCallback("inventory filter tabs", "Worn Items", onFilterSelected, this); + getChild("inventory filter tabs")->setCommitCallback(boost::bind(&LLInventoryView::onFilterSelected,this)); childSetAction("Inventory.ResetAll",onResetAll,this); childSetAction("Inventory.ExpandAll",onExpandAll,this); @@ -764,21 +762,19 @@ void LLInventoryView::onCollapseAll(void* userdata) self->mActivePanel->closeAllFolders(); } -//static -void LLInventoryView::onFilterSelected(void* userdata, bool from_click) +void LLInventoryView::onFilterSelected() { - LLInventoryView* self = (LLInventoryView*) userdata; // Find my index - self->mActivePanel = (LLInventoryPanel*)self->childGetVisibleTab("inventory filter tabs"); + mActivePanel = (LLInventoryPanel*)childGetVisibleTab("inventory filter tabs"); - if (!self->mActivePanel) + if (!mActivePanel) { return; } - //self->setFilterSubString(self->mFilterSubString); - LLInventoryFilter* filter = self->mActivePanel->getFilter(); - LLFloaterInventoryFinder *finder = self->getFinder(); + //>setFilterSubString(self->mFilterSubString); + LLInventoryFilter* filter = mActivePanel->getFilter(); + LLFloaterInventoryFinder *finder = getFinder(); if (finder) { finder->changeFilter(filter); @@ -788,8 +784,8 @@ void LLInventoryView::onFilterSelected(void* userdata, bool from_click) // If our filter is active we may be the first thing requiring a fetch so we better start it here. LLInventoryModelBackgroundFetch::instance().start(); } - self->setFilterTextFromFilter(); - self->updateSortControls(); + setFilterTextFromFilter(); + updateSortControls(); } const std::string LLInventoryView::getFilterSubString() diff --git a/indra/newview/llpanelmaininventory.h b/indra/newview/llpanelmaininventory.h index 44f6c7f09..dee764118 100644 --- a/indra/newview/llpanelmaininventory.h +++ b/indra/newview/llpanelmaininventory.h @@ -107,7 +107,7 @@ public: static BOOL checkFoldersByName(void *user_data); - static void onFilterSelected(void* userdata, bool from_click); + void onFilterSelected(); const std::string getFilterSubString(); void setFilterSubString(const std::string& string); diff --git a/indra/newview/llpreview.cpp b/indra/newview/llpreview.cpp index afc2a3c77..aa6905f2b 100644 --- a/indra/newview/llpreview.cpp +++ b/indra/newview/llpreview.cpp @@ -577,7 +577,7 @@ void LLMultiPreview::handleReshape(const LLRect& new_rect, bool by_user) } -void LLMultiPreview::tabOpen(LLFloater* opened_floater, bool from_click) +void LLMultiPreview::tabOpen(LLFloater* opened_floater) { LLPreview* opened_preview = (LLPreview*)opened_floater; if (opened_preview && opened_preview->getAssetStatus() == LLPreview::PREVIEW_ASSET_UNLOADED) diff --git a/indra/newview/llpreview.h b/indra/newview/llpreview.h index ed6bb3087..02184af85 100644 --- a/indra/newview/llpreview.h +++ b/indra/newview/llpreview.h @@ -53,7 +53,7 @@ public: LLMultiPreview(const LLRect& rect); /*virtual*/void open(); /*Flawfinder: ignore*/ - /*virtual*/void tabOpen(LLFloater* opened_floater, bool from_click); + /*virtual*/void tabOpen(LLFloater* opened_floater); /*virtual*/ void handleReshape(const LLRect& new_rect, bool by_user = false); static LLMultiPreview* getAutoOpenInstance(const LLUUID& id); diff --git a/indra/newview/llscrollingpanelparam.cpp b/indra/newview/llscrollingpanelparam.cpp index 5b142c571..88127e68f 100644 --- a/indra/newview/llscrollingpanelparam.cpp +++ b/indra/newview/llscrollingpanelparam.cpp @@ -57,8 +57,8 @@ const S32 PARAM_PANEL_HEIGHT = 2 * BTN_BORDER + LLScrollingPanelParam::PARAM_HIN S32 LLScrollingPanelParam::sUpdateDelayFrames = 0; LLScrollingPanelParam::LLScrollingPanelParam( const std::string& name, - LLViewerJointMesh* mesh, LLViewerVisualParam* param, BOOL allow_modify, bool bVisualHint ) - : LLScrollingPanelParamBase( name, mesh, param, allow_modify, bVisualHint, LLRect( 0, PARAM_PANEL_HEIGHT, PARAM_PANEL_WIDTH, 0 )), + LLViewerJointMesh* mesh, LLViewerVisualParam* param, BOOL allow_modify, LLWearable* wearable, bool bVisualHint ) + : LLScrollingPanelParamBase( name, mesh, param, allow_modify, wearable, bVisualHint, LLRect( 0, PARAM_PANEL_HEIGHT, PARAM_PANEL_WIDTH, 0 )), mLess(NULL), mMore(NULL) { @@ -70,9 +70,9 @@ LLScrollingPanelParam::LLScrollingPanelParam( const std::string& name, F32 min_weight = param->getMinWeight(); F32 max_weight = param->getMaxWeight(); - mHintMin = new LLVisualParamHint( pos_x, pos_y, PARAM_HINT_WIDTH, PARAM_HINT_HEIGHT, mesh, param, min_weight); + mHintMin = new LLVisualParamHint( pos_x, pos_y, PARAM_HINT_WIDTH, PARAM_HINT_HEIGHT, mesh, param, mWearable, min_weight); pos_x += PARAM_HINT_WIDTH + 3 * BTN_BORDER; - mHintMax = new LLVisualParamHint( pos_x, pos_y, PARAM_HINT_WIDTH, PARAM_HINT_HEIGHT, mesh, param, max_weight ); + mHintMax = new LLVisualParamHint( pos_x, pos_y, PARAM_HINT_WIDTH, PARAM_HINT_HEIGHT, mesh, param, mWearable, max_weight ); mHintMin->setAllowsUpdates( FALSE ); mHintMax->setAllowsUpdates( FALSE ); @@ -107,9 +107,7 @@ LLScrollingPanelParam::~LLScrollingPanelParam() void LLScrollingPanelParam::updatePanel(BOOL allow_modify) { - LLWearable* wearable = gAgentWearables.getWearable((LLWearableType::EType)mParam->getWearableType(),0); // TODO: MULTI-WEARABLE - - if(!wearable) + if(!mWearable) { // not editing a wearable just now, no update necessary return; @@ -150,9 +148,7 @@ void LLScrollingPanelParam::setVisible( BOOL visible ) void LLScrollingPanelParam::draw() { - LLWearable* wearable = gAgentWearables.getWearable((LLWearableType::EType)mParam->getWearableType(),0); // TODO: MULTI-WEARABLE - - if( !wearable || gFloaterCustomize->isMinimized() ) + if( !mWearable || gFloaterCustomize->isMinimized() ) { return; } @@ -219,15 +215,14 @@ void LLScrollingPanelParam::onHintMouseDown( bool max ) { LLVisualParamHint* hint = max ? mHintMax : mHintMin; LLViewerVisualParam* param = hint->getVisualParam(); - LLWearable* wearable = gAgentWearables.getWearable((LLWearableType::EType)mParam->getWearableType(),0); // TODO: MULTI-WEARABLE - if(!wearable || !param) + if(!mWearable || !param) { return; } // morph towards this result - F32 current_weight = wearable->getVisualParamWeight( hint->getVisualParam()->getID() ); + F32 current_weight = mWearable->getVisualParamWeight( hint->getVisualParam()->getID() ); // if we have maxed out on this morph, we shouldn't be able to click it if( hint->getVisualParamWeight() != current_weight ) @@ -241,14 +236,13 @@ void LLScrollingPanelParam::onHintHeldDown( bool max ) { LLVisualParamHint* hint = max ? mHintMax : mHintMin; LLViewerVisualParam* param = hint->getVisualParam(); - LLWearable* wearable = gAgentWearables.getWearable((LLWearableType::EType)param->getWearableType(),0); // TODO: MULTI-WEARABLE - if(!wearable || !param) + if(!mWearable || !param) { return; } - F32 current_weight = wearable->getVisualParamWeight( param->getID() ); + F32 current_weight = mWearable->getVisualParamWeight( param->getID() ); if (current_weight != hint->getVisualParamWeight() ) { @@ -275,8 +269,8 @@ void LLScrollingPanelParam::onHintHeldDown( bool max ) if (slider->getMinValue() < new_percent && new_percent < slider->getMaxValue()) { - wearable->setVisualParamWeight(param->getID(), new_weight, FALSE); - wearable->writeToAvatar(); + mWearable->setVisualParamWeight(param->getID(), new_weight, FALSE); + mWearable->writeToAvatar(); gAgentAvatarp->updateVisualParams(); slider->setValue( weightToPercent( new_weight ) ); @@ -297,11 +291,10 @@ void LLScrollingPanelParam::onHintMouseUp( bool max ) { LLViewerVisualParam* param = hint->getVisualParam(); - LLWearable* wearable = gAgentWearables.getWearable((LLWearableType::EType)param->getWearableType(),0); // TODO: MULTI-WEARABLE - if(wearable) + if(mWearable) { // step in direction - F32 current_weight = wearable->getVisualParamWeight( param->getID() ); + F32 current_weight = mWearable->getVisualParamWeight( param->getID() ); F32 range = mHintMax->getVisualParamWeight() - mHintMin->getVisualParamWeight(); //if min, range should be negative. if(!max) @@ -315,8 +308,8 @@ void LLScrollingPanelParam::onHintMouseUp( bool max ) if (slider->getMinValue() < new_percent && new_percent < slider->getMaxValue()) { - wearable->setVisualParamWeight(param->getID(), new_weight, FALSE); - wearable->writeToAvatar(); + mWearable->setVisualParamWeight(param->getID(), new_weight, FALSE); + mWearable->writeToAvatar(); slider->setValue( weightToPercent( new_weight ) ); } } diff --git a/indra/newview/llscrollingpanelparam.h b/indra/newview/llscrollingpanelparam.h index 4b2069574..8c02e5fa6 100644 --- a/indra/newview/llscrollingpanelparam.h +++ b/indra/newview/llscrollingpanelparam.h @@ -40,7 +40,7 @@ class LLJoint; class LLScrollingPanelParam : public LLScrollingPanelParamBase { public: - LLScrollingPanelParam( const std::string& name, LLViewerJointMesh* mesh, LLViewerVisualParam* param, BOOL allow_modify, bool bVisualHint ); + LLScrollingPanelParam( const std::string& name, LLViewerJointMesh* mesh, LLViewerVisualParam* param, BOOL allow_modify, LLWearable* wearable, bool bVisualHint ); virtual ~LLScrollingPanelParam(); virtual void draw(); @@ -69,7 +69,6 @@ public: protected: LLTimer mMouseDownTimer; // timer for how long mouse has been held down on a hint. F32 mLastHeldTime; - BOOL mAllowModify; }; diff --git a/indra/newview/llscrollingpanelparambase.cpp b/indra/newview/llscrollingpanelparambase.cpp index bd8561cf6..0a83ac44a 100644 --- a/indra/newview/llscrollingpanelparambase.cpp +++ b/indra/newview/llscrollingpanelparambase.cpp @@ -41,10 +41,11 @@ #include "llagentwearables.h" LLScrollingPanelParamBase::LLScrollingPanelParamBase( const std::string& name, - LLViewerJointMesh* mesh, LLViewerVisualParam* param, BOOL allow_modify, bool bVisualHint, LLRect rect ) + LLViewerJointMesh* mesh, LLViewerVisualParam* param, BOOL allow_modify, LLWearable* wearable, bool bVisualHint, LLRect rect ) : LLScrollingPanel( name, rect ), mParam(param), - mAllowModify(allow_modify) + mAllowModify(allow_modify), + mWearable(wearable) { LLUICtrlFactory::getInstance()->buildPanel(this, "panel_scrolling_param.xml"); //Set up the slider @@ -87,14 +88,14 @@ LLScrollingPanelParamBase::~LLScrollingPanelParamBase() void LLScrollingPanelParamBase::updatePanel(BOOL allow_modify) { LLViewerVisualParam* param = mParam; - LLWearable* wearable = gAgentWearables.getWearable( (LLWearableType::EType)param->getWearableType(), 0 ); // TODO: MULTI-WEARABLE - if(!wearable) + + if(!mWearable) { // not editing a wearable just now, no update necessary return; } - F32 current_weight = wearable->getVisualParamWeight( param->getID() ); + F32 current_weight = mWearable->getVisualParamWeight( param->getID() ); childSetValue("param slider", weightToPercent( current_weight ) ); mAllowModify = allow_modify; childSetEnabled("param slider", mAllowModify); @@ -107,21 +108,19 @@ void LLScrollingPanelParamBase::onSliderMoved(LLUICtrl* ctrl) return; } - LLWearable* wearable = gAgentWearables.getWearable( (LLWearableType::EType)mParam->getWearableType(), 0 ); // TODO: MULTI-WEARABLE - - if(!wearable) + if(!mWearable) { return; } LLSliderCtrl* slider = (LLSliderCtrl*) ctrl; - F32 current_weight = wearable->getVisualParamWeight(mParam->getID()); + F32 current_weight = mWearable->getVisualParamWeight(mParam->getID()); F32 new_weight = percentToWeight( (F32)slider->getValue().asReal() ); if (current_weight != new_weight ) { - wearable->setVisualParamWeight( mParam->getID(), new_weight, FALSE); - wearable->writeToAvatar(); + mWearable->setVisualParamWeight( mParam->getID(), new_weight, FALSE); + mWearable->writeToAvatar(); gAgentAvatarp->updateVisualParams(); } } diff --git a/indra/newview/llscrollingpanelparambase.h b/indra/newview/llscrollingpanelparambase.h index 9f41882c6..d114f622d 100644 --- a/indra/newview/llscrollingpanelparambase.h +++ b/indra/newview/llscrollingpanelparambase.h @@ -42,7 +42,7 @@ class LLScrollingPanelParamBase : public LLScrollingPanel { public: LLScrollingPanelParamBase( const std::string& name, - LLViewerJointMesh* mesh, LLViewerVisualParam* param, BOOL allow_modify, bool bVisualHint, LLRect rect ); + LLViewerJointMesh* mesh, LLViewerVisualParam* param, BOOL allow_modify, LLWearable* wearable, bool bVisualHint, LLRect rect ); virtual ~LLScrollingPanelParamBase(); virtual void updatePanel(BOOL allow_modify); @@ -56,6 +56,7 @@ public: LLViewerVisualParam* mParam; protected: BOOL mAllowModify; + LLWearable *mWearable; }; #endif diff --git a/indra/newview/lltoolmorph.cpp b/indra/newview/lltoolmorph.cpp index c3954e8a7..f9d880aa0 100644 --- a/indra/newview/lltoolmorph.cpp +++ b/indra/newview/lltoolmorph.cpp @@ -81,6 +81,7 @@ LLVisualParamHint::LLVisualParamHint( S32 width, S32 height, LLViewerJointMesh *mesh, LLViewerVisualParam *param, + LLWearable *wearable, F32 param_weight) : LLViewerDynamicTexture(width, height, 3, LLViewerDynamicTexture::ORDER_MIDDLE, TRUE ), @@ -88,6 +89,7 @@ LLVisualParamHint::LLVisualParamHint( mIsVisible( FALSE ), mJointMesh( mesh ), mVisualParam( param ), + mWearablePtr( wearable ), mVisualParamWeight( param_weight ), mAllowsUpdates( TRUE ), mDelayFrames( 0 ), @@ -153,12 +155,7 @@ BOOL LLVisualParamHint::needsRender() void LLVisualParamHint::preRender(BOOL clear_depth) { mLastParamWeight = mVisualParam->getWeight(); - LLWearable* wearable = gAgentWearables.getWearable((LLWearableType::EType)mVisualParam->getWearableType(),0); // TODO: MULTI-WEARABLE - if(wearable) - { - llinfos << llformat("%#.8lX",wearable) << llendl; - wearable->setVisualParamWeight(mVisualParam->getID(), mVisualParamWeight, FALSE); - } + if(mWearablePtr)mWearablePtr->setVisualParamWeight(mVisualParam->getID(), mVisualParamWeight, FALSE); gAgentAvatarp->setVisualParamWeight(mVisualParam->getID(), mVisualParamWeight, FALSE); gAgentAvatarp->setVisualParamWeight("Blink_Left", 0.f); gAgentAvatarp->setVisualParamWeight("Blink_Right", 0.f); @@ -259,8 +256,7 @@ BOOL LLVisualParamHint::render() gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); } gAgentAvatarp->setVisualParamWeight(mVisualParam->getID(), mLastParamWeight); - LLWearable* wearable = gAgentWearables.getWearable((LLWearableType::EType)mVisualParam->getWearableType(),0); // TODO: MULTI-WEARABLE - if(wearable)wearable->setVisualParamWeight(mVisualParam->getID(), mLastParamWeight, FALSE); + if(mWearablePtr)mWearablePtr->setVisualParamWeight(mVisualParam->getID(), mLastParamWeight, FALSE); gAgentAvatarp->updateVisualParams(); gGL.color4f(1,1,1,1); mGLTexturep->setGLTextureCreated(true); diff --git a/indra/newview/lltoolmorph.h b/indra/newview/lltoolmorph.h index 0fdfd403f..950a3ab11 100644 --- a/indra/newview/lltoolmorph.h +++ b/indra/newview/lltoolmorph.h @@ -62,6 +62,7 @@ public: S32 width, S32 height, LLViewerJointMesh *mesh, LLViewerVisualParam *param, + LLWearable *wearable, F32 param_weight); /*virtual*/ S8 getType() const ; @@ -89,6 +90,7 @@ protected: BOOL mIsVisible; // is this distortion hint visible? LLViewerJointMesh* mJointMesh; // mesh that this distortion applies to LLViewerVisualParam* mVisualParam; // visual param applied by this hint + LLWearable* mWearablePtr; // wearable we're editing F32 mVisualParamWeight; // weight for this visual parameter BOOL mAllowsUpdates; // updates are blocked unless this is true S32 mDelayFrames; // updates are blocked for this many frames diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 900d705a9..cdf4ee57d 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -817,17 +817,6 @@ const LLSD SHClientTagMgr::generateClientTag(const LLVOAvatar* pAvatar) const if(!mClientDefinitions.empty()) { std::map::const_iterator it = mClientDefinitions.find(id); - /*S32 idx = ll_rand(mClientDefinitions.size()-1); - for(;it!=mClientDefinitions.end();++it) - { - if(!idx--) - { - llinfos << "[" << idx << "] Returning " << it->second["name"] << " : " << it->second["id"] << llendl; - return it->second; - } - else - llinfos << "[" << idx << "] Skipping " << it->second["name"] << " : " << it->second["id"] << llendl; - }*/ if(it != mClientDefinitions.end()) { return it->second; diff --git a/indra/newview/llwearable.cpp b/indra/newview/llwearable.cpp index c40351d23..3c7ccbe17 100644 --- a/indra/newview/llwearable.cpp +++ b/indra/newview/llwearable.cpp @@ -763,7 +763,7 @@ void LLWearable::removeFromAvatar( LLWearableType::EType type, BOOL upload_bake if(gAgentCamera.cameraCustomizeAvatar()) { - gFloaterCustomize->setWearable(type, NULL); + gFloaterCustomize->wearablesChanged(type); } gAgentAvatarp->updateVisualParams(); diff --git a/indra/newview/skins/default/xui/en-us/floater_customize.xml b/indra/newview/skins/default/xui/en-us/floater_customize.xml index d77f5e14c..939aff135 100644 --- a/indra/newview/skins/default/xui/en-us/floater_customize.xml +++ b/indra/newview/skins/default/xui/en-us/floater_customize.xml @@ -86,17 +86,17 @@ mouse_opaque="true" name="path" v_pad="0" width="373"> Located in [PATH] - - Put on a new shape by dragging one from your inventory + +Put on a new shape by dragging one from your inventory to your avatar. Alternately, you create a new one from scratch and wear it. You do not have permission to modify this wearable. @@ -106,8 +106,8 @@ scratch and wear it. mouse_opaque="true" name="Item Action Label" v_pad="0" width="100"> Shape: -