diff --git a/indra/newview/character/avatar_lad.xml b/indra/newview/character/avatar_lad.xml
index 448e20b38271a60eb22d2551d47c4ae3c8bca3e5..5efd997ab7c86aa7f4fddbcc181e2b0ecd0083b7 100644
--- a/indra/newview/character/avatar_lad.xml
+++ b/indra/newview/character/avatar_lad.xml
@@ -6623,6 +6623,60 @@ render_pass="bump">
        name="head_tattoo">
       <texture
          local_texture="head_tattoo" />
+      <param
+       id="1062"
+       group="1"
+       edit_group="colorpicker_driven"
+       wearable="tattoo"
+       name="tattoo_head_red"
+       value_min="0"
+       value_max="1"
+       value_default="1">
+        <param_color>
+          <value
+           color="0, 0, 0, 255" />
+
+          <value
+           color="255, 0, 0, 255" />
+        </param_color>
+      </param>
+
+      <param
+       id="1063"
+       group="1"
+       edit_group="colorpicker_driven"
+       wearable="tattoo"
+       name="tattoo_head_green"
+       value_min="0"
+       value_max="1"
+       value_default="1">
+        <param_color>
+          <value
+           color="0, 0, 0, 255" />
+
+          <value
+           color="0, 255, 0, 255" />
+        </param_color>
+      </param>
+
+      <param
+       id="1064"
+       group="1"
+       edit_group="colorpicker_driven"
+       wearable="tattoo"
+       name="tattoo_head_blue"
+       value_min="0"
+       value_max="1"
+       value_default="1">
+        <param_color>
+          <value
+           color="0, 0, 0, 255" />
+
+          <value
+           color="0, 0, 255, 255" />
+        </param_color>
+      </param>
+
     </layer>
 
 
@@ -6745,6 +6799,61 @@ render_pass="bump">
      name="upper_tattoo">
       <texture
          local_texture="upper_tattoo" />
+
+      <param
+       id="1065"
+       group="1"
+       edit_group="colorpicker_driven"
+       wearable="tattoo"
+       name="tattoo_upper_red"
+       value_min="0"
+       value_max="1"
+       value_default="1">
+        <param_color>
+          <value
+           color="0, 0, 0, 255" />
+
+          <value
+           color="255, 0, 0, 255" />
+        </param_color>
+      </param>
+
+      <param
+       id="1066"
+       group="1"
+       edit_group="colorpicker_driven"
+       wearable="tattoo"
+       name="tattoo_upper_green"
+       value_min="0"
+       value_max="1"
+       value_default="1">
+        <param_color>
+          <value
+           color="0, 0, 0, 255" />
+
+          <value
+           color="0, 255, 0, 255" />
+        </param_color>
+      </param>
+
+      <param
+       id="1067"
+       group="1"
+       edit_group="colorpicker_driven"
+       wearable="tattoo"
+       name="tattoo_upper_blue"
+       value_min="0"
+       value_max="1"
+       value_default="1">
+        <param_color>
+          <value
+           color="0, 0, 0, 255" />
+
+          <value
+           color="0, 0, 255, 255" />
+        </param_color>
+      </param>
+
     </layer>
 
 
@@ -7942,6 +8051,61 @@ render_pass="bump">
      name="lower_tattoo">
       <texture
        local_texture="lower_tattoo" />
+
+      <param
+       id="1068"
+       group="1"
+       edit_group="colorpicker_driven"
+       wearable="tattoo"
+       name="tattoo_lower_red"
+       value_min="0"
+       value_max="1"
+       value_default="1">
+        <param_color>
+          <value
+           color="0, 0, 0, 255" />
+
+          <value
+           color="255, 0, 0, 255" />
+        </param_color>
+      </param>
+
+      <param
+       id="1069"
+       group="1"
+       edit_group="colorpicker_driven"
+       wearable="tattoo"
+       name="tattoo_lower_green"
+       value_min="0"
+       value_max="1"
+       value_default="1">
+        <param_color>
+          <value
+           color="0, 0, 0, 255" />
+
+          <value
+           color="0, 255, 0, 255" />
+        </param_color>
+      </param>
+
+      <param
+       id="1070"
+       group="1"
+       edit_group="colorpicker_driven"
+       wearable="tattoo"
+       name="tattoo_lower_blue"
+       value_min="0"
+       value_max="1"
+       value_default="1">
+        <param_color>
+          <value
+           color="0, 0, 0, 255" />
+
+          <value
+           color="0, 0, 255, 255" />
+        </param_color>
+      </param>
+
     </layer>
 
     <layer
@@ -11367,6 +11531,106 @@ render_pass="bump">
       </param_driver>
     </param>
       
+    <param
+     id="1071"
+     group="0"
+     wearable="tattoo"
+     edit_group="colorpicker"
+     name="tattoo_red"
+     value_min="0"
+     value_max="1"
+     value_default="1">
+      <param_driver>
+        <driven
+         id="1062"
+         min1="0"
+         max1="1"
+         max2="1"
+         min2="1" />
+
+        <driven
+         id="1065"
+         min1="0"
+         max1="1"
+         max2="1"
+         min2="1" />
+
+        <driven
+         id="1068"
+         min1="0"
+         max1="1"
+         max2="1"
+         min2="1" />
+      </param_driver>
+    </param>
+
+    <param
+     id="1072"
+     group="0"
+     wearable="tattoo"
+     edit_group="colorpicker"
+     name="tattoo_green"
+     value_min="0"
+     value_max="1"
+     value_default="1">
+      <param_driver>
+        <driven
+         id="1063"
+         min1="0"
+         max1="1"
+         max2="1"
+         min2="1" />
+
+        <driven
+         id="1066"
+         min1="0"
+         max1="1"
+         max2="1"
+         min2="1" />
+         
+        <driven
+         id="1069"
+         min1="0"
+         max1="1"
+         max2="1"
+         min2="1" />
+      </param_driver>
+    </param>
+
+    <param
+     id="1073"
+     group="0"
+     wearable="tattoo"
+     edit_group="colorpicker"
+     name="tattoo_blue"
+     value_min="0"
+     value_max="1"
+     value_default="1">
+      <param_driver>
+        <driven
+         id="1064"
+         min1="0"
+         max1="1"
+         max2="1"
+         min2="1" />
+
+        <driven
+         id="1067"
+         min1="0"
+         max1="1"
+         max2="1"
+         min2="1" />
+
+        <driven
+         id="1070"
+         min1="0"
+         max1="1"
+         max2="1"
+         min2="1" />
+
+      </param_driver>
+    </param>
+
 
   </driver_parameters>
 
diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp
index 529ce950e4cb2115ac33a1afd5982701070f1d93..f96a59e97a07e4864e2b7d1d4a8ada47c394feab 100644
--- a/indra/newview/llagent.cpp
+++ b/indra/newview/llagent.cpp
@@ -3583,12 +3583,15 @@ void LLAgent::sendAgentSetAppearance()
 			{
 				// LLWearableType::EType wearable_type = gBakedWearableMap[baked_index][wearable_num];
 				const LLWearableType::EType wearable_type = baked_dict->mWearables[i];
-				// MULTI-WEARABLE: fixed to 0th - extend to everything once messaging works.
-				const LLWearable* wearable = gAgentWearables.getWearable(wearable_type,0);
-				if (wearable)
-				{
-					hash ^= wearable->getAssetID();
-				}
+                                for (U8 wearable_index =0; wearable_index < gAgentWearables.getWearableCount(wearable_type); ++wearable_index)
+                                {
+                                       const LLWearable* wearable = gAgentWearables.getWearable(wearable_type,wearable_index);
+                                       if (wearable)
+                                       {
+                                               // MULTI-WEARABLE: make order-dependent (use MD5 hash)
+						hash ^= wearable->getAssetID();
+                                       }
+                                }
 			}
 			if (hash.notNull())
 			{
diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp
index 3e73bbef158a21c2f41cfc7d1df75cd1c4048628..545c5b845bab1549245c4d1fa4542f04c00f9a20 100644
--- a/indra/newview/llagentwearables.cpp
+++ b/indra/newview/llagentwearables.cpp
@@ -125,7 +125,6 @@ void LLAgentWearables::dump()
 	}
 }
 
-// MULTI-WEARABLE: debugging
 struct LLAgentDumper
 {
 	LLAgentDumper(std::string name):
@@ -191,7 +190,7 @@ LLAgentWearables::sendAgentWearablesUpdateCallback::~sendAgentWearablesUpdateCal
  * @param todo Bitmask of actions to take on completion.
  */
 LLAgentWearables::addWearableToAgentInventoryCallback::addWearableToAgentInventoryCallback(
-	LLPointer<LLRefCount> cb, S32 type, U32 index, LLWearable* wearable, U32 todo) :
+	LLPointer<LLRefCount> cb, LLWearableType::EType type, U32 index, LLWearable* wearable, U32 todo) :
 	mType(type),
 	mIndex(index),	
 	mWearable(wearable),
@@ -240,7 +239,7 @@ void LLAgentWearables::addWearableToAgentInventoryCallback::fire(const LLUUID& i
 	}
 }
 
-void LLAgentWearables::addWearabletoAgentInventoryDone(const S32 type,
+void LLAgentWearables::addWearabletoAgentInventoryDone(const LLWearableType::EType type,
 													   const U32 index,
 													   const LLUUID& item_id,
 													   LLWearable* wearable)
@@ -250,7 +249,7 @@ void LLAgentWearables::addWearabletoAgentInventoryDone(const S32 type,
 	if (item_id.isNull())
 		return;
 
-	LLUUID old_item_id = getWearableItemID((LLWearableType::EType)type,index);
+	LLUUID old_item_id = getWearableItemID(type,index);
 
 	if (wearable)
 	{
@@ -259,11 +258,11 @@ void LLAgentWearables::addWearabletoAgentInventoryDone(const S32 type,
 		if (old_item_id.notNull())
 		{	
 			gInventory.addChangedMask(LLInventoryObserver::LABEL, old_item_id);
-			setWearable((LLWearableType::EType)type,index,wearable);
+			setWearable(type,index,wearable);
 		}
 		else
 		{
-			pushWearable((LLWearableType::EType)type,wearable);
+			pushWearable(type,wearable);
 		}
 	}
 
@@ -285,13 +284,12 @@ void LLAgentWearables::addWearabletoAgentInventoryDone(const S32 type,
 
 void LLAgentWearables::sendAgentWearablesUpdate()
 {
-	// MULTI-WEARABLE: call i "type" or something.
 	// First make sure that we have inventory items for each wearable
 	for (S32 type=0; type < LLWearableType::WT_COUNT; ++type)
 	{
-		for (U32 j=0; j < getWearableCount((LLWearableType::EType)type); ++j)
+		for (U32 index=0; index < getWearableCount((LLWearableType::EType)type); ++index)
 		{
-			LLWearable* wearable = getWearable((LLWearableType::EType)type,j);
+			LLWearable* wearable = getWearable((LLWearableType::EType)type,index);
 			if (wearable)
 			{
 				if (wearable->getItemID().isNull())
@@ -299,8 +297,8 @@ void LLAgentWearables::sendAgentWearablesUpdate()
 					LLPointer<LLInventoryCallback> cb =
 						new addWearableToAgentInventoryCallback(
 							LLPointer<LLRefCount>(NULL),
-							type,
-							j,
+							(LLWearableType::EType)type,
+							index,
 							wearable,
 							addWearableToAgentInventoryCallback::CALL_NONE);
 					addWearableToAgentInventory(cb, wearable);
@@ -325,7 +323,7 @@ void LLAgentWearables::sendAgentWearablesUpdate()
 	gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
 
 	lldebugs << "sendAgentWearablesUpdate()" << llendl;
-	// MULTI-WEARABLE: update for multi-wearables after server-side support is in.
+	// MULTI-WEARABLE: DEPRECATED: HACK: index to 0- server database tables don't support concept of multiwearables.
 	for (S32 type=0; type < LLWearableType::WT_COUNT; ++type)
 	{
 		gMessageSystem->nextBlockFast(_PREHASH_WearableData);
@@ -333,7 +331,6 @@ void LLAgentWearables::sendAgentWearablesUpdate()
 		U8 type_u8 = (U8)type;
 		gMessageSystem->addU8Fast(_PREHASH_WearableType, type_u8);
 
-		// MULTI-WEARABLE: TODO: hacked index to 0, needs to loop over all once messages support this.
 		LLWearable* wearable = getWearable((LLWearableType::EType)type, 0);
 		if (wearable)
 		{
@@ -405,7 +402,7 @@ void LLAgentWearables::saveWearable(const LLWearableType::EType type, const U32
 			LLPointer<LLInventoryCallback> cb =
 				new addWearableToAgentInventoryCallback(
 					LLPointer<LLRefCount>(NULL),
-					(S32)type,
+					type,
 					index,
 					new_wearable,
 					todo);
@@ -871,7 +868,7 @@ BOOL LLAgentWearables::isWearingItem(const LLUUID& item_id) const
 	return FALSE;
 }
 
-// MULTI-WEARABLE: update for multiple
+// MULTI-WEARABLE: DEPRECATED (see backwards compatibility)
 // static
 // ! BACKWARDS COMPATIBILITY ! When we stop supporting viewer1.23, we can assume
 // that viewers have a Current Outfit Folder and won't need this message, and thus
@@ -909,7 +906,7 @@ void LLAgentWearables::processAgentInitialWearablesUpdate(LLMessageSystem* mesgs
 		
 		//lldebugs << "processAgentInitialWearablesUpdate()" << llendl;
 		// Add wearables
-		// MULTI-WEARABLE: TODO: update once messages change.  Currently use results to populate the zeroth element.
+		// MULTI-WEARABLE: DEPRECATED: Message only supports one wearable per type, will be ignored in future.
 		gAgentWearables.mItemsAwaitingWearableUpdate.clear();
 		for (S32 i=0; i < num_wearables; i++)
 		{
@@ -939,10 +936,10 @@ void LLAgentWearables::processAgentInitialWearablesUpdate(LLMessageSystem* mesgs
 					continue;
 				}
 				
-				// MULTI-WEARABLE: TODO: update once messages change.  Currently use results to populate the zeroth element.
+				// MULTI-WEARABLE: DEPRECATED: this message only supports one wearable per type. Should be ignored in future versions
 				
 				// Store initial wearables data until we know whether we have the current outfit folder or need to use the data.
-				LLInitialWearablesFetch::InitialWearableData wearable_data(type, item_id, asset_id); // MULTI-WEARABLE: update
+				LLInitialWearablesFetch::InitialWearableData wearable_data(type, item_id, asset_id);
 				outfit->add(wearable_data);
 			}
 			
@@ -977,7 +974,6 @@ void LLAgentWearables::recoverMissingWearable(const LLWearableType::EType type,
 	lldebugs << "Wearable " << LLWearableType::getTypeLabel(type) << " could not be downloaded.  Replaced inventory item with default wearable." << llendl;
 	LLWearable* new_wearable = LLWearableList::instance().createNewWearable(type);
 
-	S32 type_s32 = (S32) type;
 	setWearable(type,index,new_wearable);
 	//new_wearable->writeToAvatar(TRUE);
 
@@ -988,7 +984,7 @@ void LLAgentWearables::recoverMissingWearable(const LLWearableType::EType type,
 	LLPointer<LLInventoryCallback> cb =
 		new addWearableToAgentInventoryCallback(
 			LLPointer<LLRefCount>(NULL),
-			type_s32,
+			type,
 			index,
 			new_wearable,
 			addWearableToAgentInventoryCallback::CALL_RECOVERDONE);
@@ -1172,158 +1168,6 @@ void LLAgentWearables::createStandardWearablesAllDone()
 	gAgentAvatarp->onFirstTEMessageReceived();
 }
 
-// MULTI-WEARABLE: Properly handle multiwearables later.
-void LLAgentWearables::getAllWearablesArray(LLDynamicArray<S32>& wearables)
-{
-	for( S32 i = 0; i < LLWearableType::WT_COUNT; ++i )
-	{
-		if (getWearableCount((LLWearableType::EType) i) !=  0)
-		{
-			wearables.push_back(i);
-		}
-	}
-}
-
-// Note:	wearables_to_include should be a list of LLWearableType::EType types
-//			attachments_to_include should be a list of attachment points
-void LLAgentWearables::makeNewOutfit(const std::string& new_folder_name,
-									 const LLDynamicArray<S32>& wearables_to_include,
-									 const LLDynamicArray<S32>& attachments_to_include,
-									 BOOL rename_clothing)
-{
-	if (!isAgentAvatarValid()) return;
-
-	// First, make a folder in the Clothes directory.
-	LLUUID folder_id = gInventory.createNewCategory(
-		gInventory.findCategoryUUIDForType(LLFolderType::FT_CLOTHING),
-		LLFolderType::FT_NONE,
-		new_folder_name);
-
-	bool found_first_item = false;
-
-	///////////////////
-	// Wearables
-
-	if (wearables_to_include.count())
-	{
-		// Then, iterate though each of the wearables and save copies of them in the folder.
-		S32 i;
-		S32 count = wearables_to_include.count();
-		LLDynamicArray<LLUUID> delete_items;
-		LLPointer<LLRefCount> cbdone = NULL;
-		for (i = 0; i < count; ++i)
-		{
-			const S32 type = wearables_to_include[i];
-			for (U32 j=0; j<getWearableCount((LLWearableType::EType)i); j++)
-			{
-				LLWearable* old_wearable = getWearable((LLWearableType::EType)type, j);
-				if (old_wearable)
-				{
-					std::string new_name;
-					LLWearable* new_wearable;
-					new_wearable = LLWearableList::instance().createCopy(old_wearable);
-					if (rename_clothing)
-					{
-						new_name = new_folder_name;
-						new_name.append(" ");
-						new_name.append(old_wearable->getTypeLabel());
-						LLStringUtil::truncate(new_name, DB_INV_ITEM_NAME_STR_LEN);
-						new_wearable->setName(new_name);
-					}
-
-					LLViewerInventoryItem* item = gInventory.getItem(getWearableItemID((LLWearableType::EType)type,j));
-					S32 todo = addWearableToAgentInventoryCallback::CALL_NONE;
-					if (!found_first_item)
-					{
-						found_first_item = true;
-						/* set the focus to the first item */
-						todo |= addWearableToAgentInventoryCallback::CALL_MAKENEWOUTFITDONE;
-						/* send the agent wearables update when done */
-						cbdone = new sendAgentWearablesUpdateCallback;
-					}
-					LLPointer<LLInventoryCallback> cb =
-						new addWearableToAgentInventoryCallback(
-							cbdone,
-							type,
-							j,
-							new_wearable,
-							todo);
-					llassert(item);
-					if (item)
-					{
-						if (isWearableCopyable((LLWearableType::EType)type, j))
-						{
-							copy_inventory_item(
-									    gAgent.getID(),
-									    item->getPermissions().getOwner(),
-									    item->getUUID(),
-									    folder_id,
-									    new_name,
-									    cb);
-						}
-						else
-						{
-							move_inventory_item(
-									    gAgent.getID(),
-									    gAgent.getSessionID(),
-									    item->getUUID(),
-									    folder_id,
-									    new_name,
-									    cb);
-						}
-					}
-				}
-			}
-		}
-		gInventory.notifyObservers();
-	}
-
-
-	///////////////////
-	// Attachments
-
-	if (attachments_to_include.count())
-	{
-		BOOL msg_started = FALSE;
-		LLMessageSystem* msg = gMessageSystem;
-		for (S32 i = 0; i < attachments_to_include.count(); i++)
-		{
-			S32 attachment_pt = attachments_to_include[i];
-			LLViewerJointAttachment* attachment = get_if_there(gAgentAvatarp->mAttachmentPoints, attachment_pt, (LLViewerJointAttachment*)NULL);
-			if (!attachment) continue;
-			for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
-				 attachment_iter != attachment->mAttachedObjects.end();
-				 ++attachment_iter)
-			{
-				LLViewerObject *attached_object = (*attachment_iter);
-				if(!attached_object) continue;
-				const LLUUID& item_id = (*attachment_iter)->getItemID();
-				if(item_id.isNull()) continue;
-				LLInventoryItem* item = gInventory.getItem(item_id);
-				if(!item) continue;
-				if(!msg_started)
-				{
-					msg_started = TRUE;
-					msg->newMessage("CreateNewOutfitAttachments");
-					msg->nextBlock("AgentData");
-					msg->addUUID("AgentID", gAgent.getID());
-					msg->addUUID("SessionID", gAgent.getSessionID());
-					msg->nextBlock("HeaderData");
-					msg->addUUID("NewFolderID", folder_id);
-				}
-				msg->nextBlock("ObjectData");
-				msg->addUUID("OldItemID", item_id);
-				msg->addUUID("OldFolderID", item->getParentUUID());
-			}
-		}
-
-		if (msg_started)
-		{
-			gAgent.sendReliableMessage();
-		}
-
-	} 
-}
 
 class LLShowCreatedOutfit: public LLInventoryCallback
 {
@@ -2010,7 +1854,7 @@ BOOL LLAgentWearables::areWearablesLoaded() const
 	return mWearablesLoaded;
 }
 
-// MULTI-WEARABLE: update for multiple indices.
+// MULTI-WEARABLE: DEPRECATED: item pending count relies on old messages that don't support multi-wearables. do not trust to be accurate
 void LLAgentWearables::updateWearablesLoaded()
 {
 	mWearablesLoaded = (itemUpdatePendingCount()==0);
diff --git a/indra/newview/llagentwearables.h b/indra/newview/llagentwearables.h
index def16e4e85216b4e89b633f15537e57803648d26..27453b5b2516379807803f03e2c11a26a0c212f0 100644
--- a/indra/newview/llagentwearables.h
+++ b/indra/newview/llagentwearables.h
@@ -62,7 +62,6 @@ class LLAgentWearables
 	void			cleanup();
 	void			dump();
 protected:
-	// MULTI-WEARABLE: assuming one per type.  Type is called index - rename.
 	void			createStandardWearablesDone(S32 type, U32 index/* = 0*/);
 	void			createStandardWearablesAllDone();
 	
@@ -93,7 +92,6 @@ class LLAgentWearables
 	const LLWearable*	getWearableFromItemID(const LLUUID& item_id) const;
 	LLWearable*	getWearableFromAssetID(const LLUUID& asset_id);
 	LLInventoryItem*	getWearableInventoryItem(LLWearableType::EType type, U32 index /*= 0*/);
-	// MULTI-WEARABLE: assuming one per type.
 	static BOOL			selfHasWearable(LLWearableType::EType type);
 	LLWearable*			getWearable(const LLWearableType::EType type, U32 index /*= 0*/); 
 	const LLWearable* 	getWearable(const LLWearableType::EType type, U32 index /*= 0*/) const;
@@ -128,7 +126,7 @@ class LLAgentWearables
 												LLWearable* wearable, 
 												const LLUUID& category_id = LLUUID::null,
 												BOOL notify = TRUE);
-	void 			addWearabletoAgentInventoryDone(const S32 type,
+	void 			addWearabletoAgentInventoryDone(const LLWearableType::EType type,
 													const U32 index,
 													const LLUUID& item_id,
 													LLWearable* wearable);
@@ -163,15 +161,6 @@ class LLAgentWearables
 	// Outfits
 	//--------------------------------------------------------------------
 public:
-	void 			getAllWearablesArray(LLDynamicArray<S32>& wearables);
-	
-	// Note:	wearables_to_include should be a list of LLWearableType::EType types
-	//			attachments_to_include should be a list of attachment points
-	void			makeNewOutfit(const std::string& new_folder_name,
-								  const LLDynamicArray<S32>& wearables_to_include,
-								  const LLDynamicArray<S32>& attachments_to_include,
-								  BOOL rename_clothing);
-
 	
 	// Should only be called if we *know* we've never done so before, since users may
 	// not want the Library outfits to stay in their quick outfit selector and can delete them.
@@ -184,7 +173,6 @@ class LLAgentWearables
 	// Save Wearables
 	//--------------------------------------------------------------------
 public:	
-    // MULTI-WEARABLE: assumes one per type.
 	void			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);
 	void			saveAllWearables();
@@ -249,7 +237,7 @@ class LLAgentWearables
 	class addWearableToAgentInventoryCallback : public LLInventoryCallback
 	{
 	public:
-		enum EType
+		enum ETodo
 		{
 			CALL_NONE = 0,
 			CALL_UPDATE = 1,
@@ -259,16 +247,14 @@ class LLAgentWearables
 			CALL_WEARITEM = 16
 		};
 
-		// MULTI-WEARABLE: index is an LLWearableType::EType - more confusing usage.
-		// MULTI-WEARABLE: need to have type and index args both?
 		addWearableToAgentInventoryCallback(LLPointer<LLRefCount> cb,
-											S32 type,
+											LLWearableType::EType type,
 											U32 index,
 											LLWearable* wearable,
 											U32 todo = CALL_NONE);
 		virtual void fire(const LLUUID& inv_item);
 	private:
-		S32 mType;
+		LLWearableType::EType mType;
 		U32 mIndex;
 		LLWearable* mWearable;
 		U32 mTodo;
diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp
index 4aef72ab0b0c7c1fb51824d55bea6a6ab5f18c10..7d39ba30f0a7f77e3701e48ad88714a47fd1ba36 100644
--- a/indra/newview/llappearancemgr.cpp
+++ b/indra/newview/llappearancemgr.cpp
@@ -1469,14 +1469,21 @@ void LLAppearanceMgr::addCOFItemLink(const LLInventoryItem *item, bool do_update
 	{
 		// Are these links to the same object?
 		const LLViewerInventoryItem* inv_item = item_array.get(i).get();
+		const LLWearableType::EType wearable_type = inv_item->getWearableType();
+
+		const bool is_body_part =    (wearable_type == LLWearableType::WT_SHAPE) 
+								  || (wearable_type == LLWearableType::WT_HAIR) 
+								  || (wearable_type == LLWearableType::WT_EYES)
+								  || (wearable_type == LLWearableType::WT_SKIN);
+
 		if (inv_item->getLinkedUUID() == vitem->getLinkedUUID())
 		{
 			linked_already = true;
 		}
-		// Are these links to different items of the same wearable
+		// Are these links to different items of the same body part
 		// type? If so, new item will replace old.
-		// MULTI-WEARABLES: revisit if more than one per type is allowed.
-		else if (FALSE/*areMatchingWearables(vitem,inv_item)*/)
+		// TODO: MULTI-WEARABLE: check for wearable limit for clothing types
+		else if (is_body_part)
 		{
 			if (inv_item->getIsLinkType())
 			{
diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp
index b9b4fa8b0313c079d31d9d97988c0210b089e5e1..ab7eeae3e846f1981658f649a7c7115a443dc230 100644
--- a/indra/newview/llinventorybridge.cpp
+++ b/indra/newview/llinventorybridge.cpp
@@ -4980,18 +4980,20 @@ void LLWearableBridge::removeAllClothesFromAvatar()
 		if (itype == LLWearableType::WT_SHAPE || itype == LLWearableType::WT_SKIN || itype == LLWearableType::WT_HAIR || itype == LLWearableType::WT_EYES)
 			continue;
 
-		// MULTI-WEARABLES: fixed to index 0
-		LLViewerInventoryItem *item = dynamic_cast<LLViewerInventoryItem*>(
-			gAgentWearables.getWearableInventoryItem((LLWearableType::EType)itype, 0));
-		if (!item)
-			continue;
-		const LLUUID &item_id = gInventory.getLinkedItemID(item->getUUID());
-		const LLWearable *wearable = gAgentWearables.getWearableFromItemID(item_id);
-		if (!wearable)
-			continue;
-
-		// Find and remove this item from the COF.
-		LLAppearanceMgr::instance().removeCOFItemLinks(item_id,false);
+		for (S32 index = gAgentWearables.getWearableCount(itype)-1; index >= 0 ; --index)
+		{
+			LLViewerInventoryItem *item = dynamic_cast<LLViewerInventoryItem*>(
+				gAgentWearables.getWearableInventoryItem((LLWearableType::EType)itype, index));
+			if (!item)
+				continue;
+			const LLUUID &item_id = gInventory.getLinkedItemID(item->getUUID());
+			const LLWearable *wearable = gAgentWearables.getWearableFromItemID(item_id);
+			if (!wearable)
+				continue;
+	
+			// Find and remove this item from the COF.
+			LLAppearanceMgr::instance().removeCOFItemLinks(item_id,false);
+		}
 	}
 	gInventory.notifyObservers();
 
diff --git a/indra/newview/llpaneleditwearable.cpp b/indra/newview/llpaneleditwearable.cpp
index 5ad68ea4db7d7cf3ccd4402fbe5fa9eefe951c96..f8dbc91036141b49200b0b3ddf7c0a177c1aba52 100644
--- a/indra/newview/llpaneleditwearable.cpp
+++ b/indra/newview/llpaneleditwearable.cpp
@@ -227,7 +227,7 @@ LLEditWearableDictionary::Wearables::Wearables()
 	addEntry(LLWearableType::WT_UNDERPANTS, new WearableEntry(LLWearableType::WT_UNDERPANTS,"edit_underpants_title","underpants_desc_text",1,1,1, TEX_LOWER_UNDERPANTS, TEX_LOWER_UNDERPANTS, SUBPART_UNDERPANTS));
 	addEntry(LLWearableType::WT_SKIRT, 		new WearableEntry(LLWearableType::WT_SKIRT,"edit_skirt_title","skirt_desc_text",1,1,1, TEX_SKIRT, TEX_SKIRT, SUBPART_SKIRT));
 	addEntry(LLWearableType::WT_ALPHA, 		new WearableEntry(LLWearableType::WT_ALPHA,"edit_alpha_title","alpha_desc_text",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","tattoo_desc_text",0,3,1, TEX_LOWER_TATTOO, TEX_UPPER_TATTOO, TEX_HEAD_TATTOO, SUBPART_TATTOO));
+	addEntry(LLWearableType::WT_TATTOO, 	new WearableEntry(LLWearableType::WT_TATTOO,"edit_tattoo_title","tattoo_desc_text",1,3,1, TEX_HEAD_TATTOO, TEX_LOWER_TATTOO, TEX_UPPER_TATTOO, TEX_HEAD_TATTOO, SUBPART_TATTOO));
 }
 
 LLEditWearableDictionary::WearableEntry::WearableEntry(LLWearableType::EType type,
@@ -331,6 +331,7 @@ LLEditWearableDictionary::ColorSwatchCtrls::ColorSwatchCtrls()
 	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()
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index c245650d5136f85bdcfba00f892b9b33be2cb330..729424353f12929af8d21b4ed7c8c33d4f163343 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -292,8 +292,8 @@ void handle_toggle_pg(void*);
 void handle_dump_attachments(void *);
 void handle_dump_avatar_local_textures(void*);
 void handle_debug_avatar_textures(void*);
-void handle_grab_texture(void*);
-BOOL enable_grab_texture(void*);
+void handle_grab_baked_texture(void*);
+BOOL enable_grab_baked_texture(void*);
 void handle_dump_region_object_cache(void*);
 
 BOOL enable_save_into_inventory(void*);
@@ -1460,28 +1460,28 @@ class LLAdvancedGrabBakedTexture : public view_listener_t
 		std::string texture_type = userdata.asString();
 		if ("iris" == texture_type)
 		{
-			handle_grab_texture( (void*)TEX_EYES_BAKED );
+			handle_grab_baked_texture( (void*)BAKED_EYES );
 		}
 		else if ("head" == texture_type)
 		{
-			handle_grab_texture( (void*)TEX_HEAD_BAKED );
+			handle_grab_baked_texture( (void*)BAKED_HEAD );
 		}
 		else if ("upper" == texture_type)
 		{
-			handle_grab_texture( (void*)TEX_UPPER_BAKED );
+			handle_grab_baked_texture( (void*)BAKED_UPPER );
 		}
 		else if ("lower" == texture_type)
 		{
-			handle_grab_texture( (void*)TEX_SKIRT_BAKED );
+			handle_grab_baked_texture( (void*)BAKED_LOWER );
 		}
 		else if ("skirt" == texture_type)
 		{
-			handle_grab_texture( (void*)TEX_SKIRT_BAKED );
+			handle_grab_baked_texture( (void*)BAKED_SKIRT );
 		}
 		else if ("hair" == texture_type)
 		{
-			handle_grab_texture( (void*)TEX_HAIR_BAKED );
-}
+			handle_grab_baked_texture( (void*)BAKED_HAIR );
+		}
 
 		return true;
 	}
@@ -1496,23 +1496,27 @@ class LLAdvancedEnableGrabBakedTexture : public view_listener_t
 
 		if ("iris" == texture_type)
 		{
-			new_value = enable_grab_texture( (void*)TEX_EYES_BAKED );
+			new_value = enable_grab_baked_texture( (void*)BAKED_EYES );
 		}
 		else if ("head" == texture_type)
 		{
-			new_value = enable_grab_texture( (void*)TEX_HEAD_BAKED );
+			new_value = enable_grab_baked_texture( (void*)BAKED_HEAD );
 		}
 		else if ("upper" == texture_type)
 		{
-			new_value = enable_grab_texture( (void*)TEX_UPPER_BAKED );
+			new_value = enable_grab_baked_texture( (void*)BAKED_UPPER );
 		}
 		else if ("lower" == texture_type)
 		{
-			new_value = enable_grab_texture( (void*)TEX_LOWER_BAKED );
+			new_value = enable_grab_baked_texture( (void*)BAKED_LOWER );
 		}
 		else if ("skirt" == texture_type)
 		{
-			new_value = enable_grab_texture( (void*)TEX_SKIRT_BAKED );
+			new_value = enable_grab_baked_texture( (void*)BAKED_SKIRT );
+		}
+		else if ("hair" == texture_type)
+		{
+			new_value = enable_grab_baked_texture( (void*)BAKED_HAIR );
 		}
 	
 		return new_value;
@@ -6933,27 +6937,20 @@ void handle_debug_avatar_textures(void*)
 	}
 }
 
-void handle_grab_texture(void* data)
+void handle_grab_baked_texture(void* data)
 {
-	ETextureIndex tex_index = (ETextureIndex)((intptr_t)data);
+	EBakedTextureIndex baked_tex_index = (EBakedTextureIndex)((intptr_t)data);
 	if (!isAgentAvatarValid()) return;
 
-	// MULTI-WEARABLE: change to support an index
-	const LLUUID& asset_id = gAgentAvatarp->grabLocalTexture(tex_index, 0);
+	const LLUUID& asset_id = gAgentAvatarp->grabBakedTexture(baked_tex_index);
 	LL_INFOS("texture") << "Adding baked texture " << asset_id << " to inventory." << llendl;
 	LLAssetType::EType asset_type = LLAssetType::AT_TEXTURE;
 	LLInventoryType::EType inv_type = LLInventoryType::IT_TEXTURE;
 	const LLUUID folder_id = gInventory.findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(asset_type));
 	if(folder_id.notNull())
 	{
-		std::string name = "Unknown";
-		const LLVOAvatarDictionary::TextureEntry *texture_dict = LLVOAvatarDictionary::getInstance()->getTexture(tex_index);
-		if (texture_dict->mIsBakedTexture)
-		{
-			EBakedTextureIndex baked_index = texture_dict->mBakedTextureIndex;
-			name = "Baked " + LLVOAvatarDictionary::getInstance()->getBakedTexture(baked_index)->mNameCapitalized;
-		}
-		name += " Texture";
+		std::string name;
+		name = "Baked " + LLVOAvatarDictionary::getInstance()->getBakedTexture(baked_tex_index)->mNameCapitalized + " Texture";
 
 		LLUUID item_id;
 		item_id.generate();
@@ -7006,13 +7003,12 @@ void handle_grab_texture(void* data)
 	}
 }
 
-BOOL enable_grab_texture(void* data)
+BOOL enable_grab_baked_texture(void* data)
 {
-	ETextureIndex index = (ETextureIndex)((intptr_t)data);
+	EBakedTextureIndex index = (EBakedTextureIndex)((intptr_t)data);
 	if (isAgentAvatarValid())
 	{
-		// MULTI-WEARABLE:
-		return gAgentAvatarp->canGrabLocalTexture(index,0);
+		return gAgentAvatarp->canGrabBakedTexture(index);
 	}
 	return FALSE;
 }
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index 0f4623c67893cdc8d3eb58f23f490f9ae9542527..4371396629107c96de20109802411521f7449c26 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -4886,7 +4886,7 @@ BOOL LLVOAvatar::loadAvatar()
 	}
 
 	// Uncomment to enable avatar_lad.xml debugging. 
-/*	std::ofstream file;
+	std::ofstream file;
 	file.open("avatar_lad.log");
 	for( LLViewerVisualParam* param = (LLViewerVisualParam*) getFirstVisualParam(); 
 	param;
@@ -4896,7 +4896,7 @@ BOOL LLVOAvatar::loadAvatar()
 		file << std::endl;
 	}
 
-	file.close();*/
+	file.close();
 	
 	return TRUE;
 }
@@ -6355,6 +6355,14 @@ BOOL LLVOAvatar::teToColorParams( ETextureIndex te, U32 *param_name )
 			param_name[2] = 923; //"skirt_blue";
 			break;
 
+		case TEX_HEAD_TATTOO:
+		case TEX_LOWER_TATTOO:
+		case TEX_UPPER_TATTOO:
+			param_name[0] = 1071; //"tattoo_red";
+			param_name[1] = 1072; //"tattoo_green";
+			param_name[2] = 1073; //"tattoo_blue";
+			break;	
+
 		default:
 			llassert(0);
 			return FALSE;
diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp
index da99b212f0731cc8d01ba6269d4e62b2b748d53d..c82de73f2512c0a195078d0a43651df26e8eaf93 100644
--- a/indra/newview/llvoavatarself.cpp
+++ b/indra/newview/llvoavatarself.cpp
@@ -1801,21 +1801,31 @@ void LLVOAvatarSelf::bakedTextureUpload(EBakedTextureIndex index, BOOL finished)
 	mBakedTextureTimes[index][done] = mDebugSelfLoadTimer.getElapsedTimeF32();
 }
 
-const LLUUID& LLVOAvatarSelf::grabLocalTexture(ETextureIndex type, U32 index) const
+const LLUUID& LLVOAvatarSelf::grabBakedTexture(EBakedTextureIndex baked_index) const
 {
-	if (canGrabLocalTexture(type, index))
+	if (canGrabBakedTexture(baked_index))
 	{
-		return getTEImage( type )->getID();
+		ETextureIndex tex_index = LLVOAvatarDictionary::bakedToLocalTextureIndex(baked_index);
+		if (tex_index == TEX_NUM_INDICES)
+		{
+			return LLUUID::null;
+		}
+		return getTEImage( tex_index )->getID();
 	}
 	return LLUUID::null;
 }
 
-BOOL LLVOAvatarSelf::canGrabLocalTexture(ETextureIndex type, U32 index) const
+BOOL LLVOAvatarSelf::canGrabBakedTexture(EBakedTextureIndex baked_index) const
 {
+	ETextureIndex tex_index = LLVOAvatarDictionary::bakedToLocalTextureIndex(baked_index);
+	if (tex_index == TEX_NUM_INDICES)
+	{
+		return FALSE;
+	}
 	// Check if the texture hasn't been baked yet.
-	if (!isTextureDefined(type, index))
+	if (!isTextureDefined(tex_index, 0))
 	{
-		lldebugs << "getTEImage( " << (U32) type << ", " << index << " )->getID() == IMG_DEFAULT_AVATAR" << llendl;
+		lldebugs << "getTEImage( " << (U32) tex_index << " )->getID() == IMG_DEFAULT_AVATAR" << llendl;
 		return FALSE;
 	}
 
@@ -1825,13 +1835,7 @@ BOOL LLVOAvatarSelf::canGrabLocalTexture(ETextureIndex type, U32 index) const
 	// Check permissions of textures that show up in the
 	// baked texture.  We don't want people copying people's
 	// work via baked textures.
-	/* switch(type)
-		case TEX_EYES_BAKED:
-			textures.push_back(TEX_EYES_IRIS); */
-	const LLVOAvatarDictionary::TextureEntry *texture_dict = LLVOAvatarDictionary::getInstance()->getTexture(type);
-	if (!texture_dict->mIsUsedByBakedTexture) return FALSE;
 
-	const EBakedTextureIndex baked_index = texture_dict->mBakedTextureIndex;
 	const LLVOAvatarDictionary::BakedEntry *baked_dict = LLVOAvatarDictionary::getInstance()->getBakedTexture(baked_index);
 	for (texture_vec_t::const_iterator iter = baked_dict->mLocalTextures.begin();
 		 iter != baked_dict->mLocalTextures.end();
diff --git a/indra/newview/llvoavatarself.h b/indra/newview/llvoavatarself.h
index 32a180be5dd41a5d7b4b88afbc334aad08774376..666219f3aaca3bc6255f4d542c3d66ae07253f0a 100644
--- a/indra/newview/llvoavatarself.h
+++ b/indra/newview/llvoavatarself.h
@@ -190,8 +190,6 @@ class LLVOAvatarSelf :
 	LLViewerFetchedTexture*	getLocalTextureGL(LLVOAvatarDefines::ETextureIndex type, U32 index) const;
 	const LLUUID&		getLocalTextureID(LLVOAvatarDefines::ETextureIndex type, U32 index) const;
 	void				setLocalTextureTE(U8 te, LLViewerTexture* image, U32 index);
-	const LLUUID&		grabLocalTexture(LLVOAvatarDefines::ETextureIndex type, U32 index) const;
-	BOOL				canGrabLocalTexture(LLVOAvatarDefines::ETextureIndex type, U32 index) const;
 	/*virtual*/ void	setLocalTexture(LLVOAvatarDefines::ETextureIndex type, LLViewerTexture* tex, BOOL baked_version_exits, U32 index);
 protected:
 	/*virtual*/ void	setBakedReady(LLVOAvatarDefines::ETextureIndex type, BOOL baked_version_exists, U32 index);
@@ -241,6 +239,10 @@ class LLVOAvatarSelf :
 	void				setupComposites();
 	void				updateComposites();
 
+	const LLUUID&		grabBakedTexture(LLVOAvatarDefines::EBakedTextureIndex baked_index) const;
+	BOOL				canGrabBakedTexture(LLVOAvatarDefines::EBakedTextureIndex baked_index) const;
+
+
 	//--------------------------------------------------------------------
 	// Scratch textures (used for compositing)
 	//--------------------------------------------------------------------
diff --git a/indra/newview/skins/default/xui/en/panel_edit_tattoo.xml b/indra/newview/skins/default/xui/en/panel_edit_tattoo.xml
index ed990eb0956468d35d1a9b91b809a032b401802d..6d02dd41de5593095bede6f093a52d75ef4cb477 100644
--- a/indra/newview/skins/default/xui/en/panel_edit_tattoo.xml
+++ b/indra/newview/skins/default/xui/en/panel_edit_tattoo.xml
@@ -57,6 +57,20 @@
         tool_tip="Click to choose a picture"
         top_pad="10"
         width="94" />
+       <color_swatch
+        can_apply_immediately="true"
+        follows="left|top"
+        height="80"
+        label="Color/Tint"
+        layout="topleft"
+        left_pad="20"
+        name="Color/Tint"
+        tool_tip="Click to open color picker"
+        top="10"
+        width="64" >
+         <color_swatch.commit_callback
+             function="ColorSwatch.Commit" />
+       </color_swatch>
 	 </panel>
 </panel>