From 3d4e04b5569952629f68c52c9309b5364e16136c Mon Sep 17 00:00:00 2001
From: Andrew Meadows <andrew@lindenlab.com>
Date: Wed, 1 Apr 2009 17:11:37 +0000
Subject: [PATCH] QAR-1284 ip-takedown tools simulator work is ready for merge
 svn merge -r115879:116020
 svn+ssh://svn.lindenlab.com/svn/linden/branches/dmcat/dmcat-5 no conflicts

---
 indra/llcommon/lllivefile.cpp           |   9 +
 indra/llcommon/lllivefile.h             |   2 +
 indra/llinventory/llinventory.cpp       |  23 +-
 indra/llinventory/llinventory.h         |  87 +----
 indra/llinventory/llsaleinfo.cpp        |   2 +-
 indra/llinventory/llsaleinfo.h          |   2 +-
 indra/llprimitive/CMakeLists.txt        |   2 +
 indra/llprimitive/llprimitive.cpp       | 411 +++++------------------
 indra/llprimitive/llprimitive.h         |  24 +-
 indra/llprimitive/llprimtexturelist.cpp | 414 ++++++++++++++++++++++++
 indra/llprimitive/llprimtexturelist.h   | 126 ++++++++
 indra/llprimitive/lltextureentry.cpp    | 108 +++++--
 indra/llprimitive/lltextureentry.h      |  14 +-
 13 files changed, 769 insertions(+), 455 deletions(-)
 create mode 100644 indra/llprimitive/llprimtexturelist.cpp
 create mode 100644 indra/llprimitive/llprimtexturelist.h

diff --git a/indra/llcommon/lllivefile.cpp b/indra/llcommon/lllivefile.cpp
index 810ae706a79..b6f458cb3e0 100644
--- a/indra/llcommon/lllivefile.cpp
+++ b/indra/llcommon/lllivefile.cpp
@@ -167,3 +167,12 @@ void LLLiveFile::addToEventTimer()
 	impl.mEventTimer = new LiveFileEventTimer(*this, impl.mRefreshPeriod);
 }
 
+void LLLiveFile::setRefreshPeriod(F32 seconds)
+{
+	if (seconds < 0.f)
+	{
+		seconds = -seconds;
+	}
+	impl.mRefreshPeriod = seconds;
+}
+
diff --git a/indra/llcommon/lllivefile.h b/indra/llcommon/lllivefile.h
index fddf0062299..a3a9cf49abd 100644
--- a/indra/llcommon/lllivefile.h
+++ b/indra/llcommon/lllivefile.h
@@ -52,6 +52,8 @@ class LLLiveFile
 		// Normally, just calling checkAndReload() is enough.  In some cases
 		// though, you may need to let the live file periodically check itself.
 
+	void setRefreshPeriod(F32 seconds);
+
 protected:
 	virtual void loadFile() = 0; // Implement this to load your file if it changed
 
diff --git a/indra/llinventory/llinventory.cpp b/indra/llinventory/llinventory.cpp
index b1cfd686688..4dddd9de3ee 100644
--- a/indra/llinventory/llinventory.cpp
+++ b/indra/llinventory/llinventory.cpp
@@ -333,15 +333,6 @@ void LLInventoryItem::copyItem(const LLInventoryItem* other)
 	mCreationDate = other->mCreationDate;
 }
 
-// As a constructor alternative, the clone() method works like a
-// copy constructor, but gens a new UUID.
-void LLInventoryItem::cloneItem(LLPointer<LLInventoryItem>& newitem) const
-{
-	newitem = new LLInventoryItem;
-	newitem->copyItem(this);
-	newitem->mUUID.generate();
-}
-
 const LLPermissions& LLInventoryItem::getPermissions() const
 {
 	return mPermissions;
@@ -934,6 +925,12 @@ BOOL LLInventoryItem::exportLegacyStream(std::ostream& output_stream, BOOL inclu
 LLSD LLInventoryItem::asLLSD() const
 {
 	LLSD sd = LLSD();
+	asLLSD(sd);
+	return sd;
+}
+
+void LLInventoryItem::asLLSD( LLSD& sd ) const
+{
 	sd[INV_ITEM_ID_LABEL] = mUUID;
 	sd[INV_PARENT_ID_LABEL] = mParentUUID;
 	sd[INV_PERMISSIONS_LABEL] = ll_create_sd_from_permissions(mPermissions);
@@ -965,11 +962,9 @@ LLSD LLInventoryItem::asLLSD() const
 	sd[INV_NAME_LABEL] = mName;
 	sd[INV_DESC_LABEL] = mDescription;
 	sd[INV_CREATION_DATE_LABEL] = (S32) mCreationDate;
-
-	return sd;
 }
 
-bool LLInventoryItem::fromLLSD(LLSD& sd)
+bool LLInventoryItem::fromLLSD(const LLSD& sd)
 {
 	mInventoryType = LLInventoryType::IT_NONE;
 	mAssetUUID.setNull();
@@ -1419,7 +1414,7 @@ void LLInventoryCategory::packMessage(LLMessageSystem* msg) const
 	msg->addStringFast(_PREHASH_Name, mName);
 }
 
-bool LLInventoryCategory::fromLLSD(LLSD& sd)
+bool LLInventoryCategory::fromLLSD(const LLSD& sd)
 {
     std::string w;
 
@@ -1661,6 +1656,7 @@ LLSD ll_create_sd_from_inventory_item(LLPointer<LLInventoryItem> item)
 	return rv;
 }
 
+/* deprecated, use LLInventoryItem::fromLLSD() instead
 LLPointer<LLInventoryItem> ll_create_item_from_sd(const LLSD& sd_item)
 {
 	LLPointer<LLInventoryItem> rv = new LLInventoryItem;
@@ -1690,6 +1686,7 @@ LLPointer<LLInventoryItem> ll_create_item_from_sd(const LLSD& sd_item)
 	rv->setCreationDate(sd_item[INV_CREATION_DATE_LABEL].asInteger());
 	return rv;
 }
+*/
 
 LLSD ll_create_sd_from_inventory_category(LLPointer<LLInventoryCategory> cat)
 {
diff --git a/indra/llinventory/llinventory.h b/indra/llinventory/llinventory.h
index 937e12dbcf1..53a52cd3248 100644
--- a/indra/llinventory/llinventory.h
+++ b/indra/llinventory/llinventory.h
@@ -89,7 +89,7 @@ class LLInventoryObject : public LLRefCount
 	void copyObject(const LLInventoryObject* other); // LLRefCount requires custom copy
 
 	// accessors
-	const LLUUID& getUUID() const;
+	virtual const LLUUID& getUUID() const;
 	const LLUUID& getParentUUID() const;
 	const std::string& getName() const;
 	LLAssetType::EType getType() const;
@@ -225,10 +225,7 @@ class LLInventoryItem : public LLInventoryObject
 	LLInventoryItem(const LLInventoryItem* other);
 	virtual void copyItem(const LLInventoryItem* other); // LLRefCount requires custom copy
 
-	// As a constructor alternative, the clone() method works like a
-	// copy constructor, but gens a new UUID.
-	// It is up to the caller to delete (unref) the item.
-	virtual void cloneItem(LLPointer<LLInventoryItem>& newitem) const;
+	void generateUUID() { mUUID.generate(); }
 	
 	// accessors
 	const LLPermissions& getPermissions() const;
@@ -276,7 +273,8 @@ class LLInventoryItem : public LLInventoryObject
 	S32 packBinaryBucket(U8* bin_bucket, LLPermissions* perm_override = NULL) const;
 	void unpackBinaryBucket(U8* bin_bucket, S32 bin_bucket_size);
 	LLSD asLLSD() const;
-	bool fromLLSD(LLSD& sd);
+	void asLLSD( LLSD& sd ) const;
+	bool fromLLSD(const LLSD& sd);
 
 };
 
@@ -317,7 +315,7 @@ class LLInventoryCategory : public LLInventoryObject
 	virtual void unpackMessage(LLMessageSystem* msg, const char* block, S32 block_num = 0);
 
 	LLSD asLLSD() const;
-	bool fromLLSD(LLSD& sd);
+	bool fromLLSD(const LLSD& sd);
 
 	// file support
 	virtual BOOL importFile(LLFILE* fp);
@@ -338,85 +336,12 @@ class LLInventoryCategory : public LLInventoryObject
 // Useful bits
 //-----------------------------------------------------------------------------
 
-// This functor tests if an item is transferrable and returns true if
-// it is. Derived from unary_function<> so that the object can be used
-// in stl-compliant adaptable predicates (eg, not1<>). You might want
-// to use this in std::partition() or similar logic.
-struct IsItemTransferable : public std::unary_function<LLInventoryItem*, bool>
-{
-	LLUUID mDestID;
-	IsItemTransferable(const LLUUID& dest_id) : mDestID(dest_id) {}
-	bool operator()(const LLInventoryItem* item) const
-	{
-		return (item->getPermissions().allowTransferTo(mDestID)) ? true:false;
-	}
-};
-
-// This functor is used to set the owner and group of inventory items,
-// for example, in a simple std::for_each() loop. Note that the call
-// to setOwnerAndGroup can fail if authority_id != LLUUID::null.
-struct SetItemOwnerAndGroup
-{
-	LLUUID mAuthorityID;
-	LLUUID mOwnerID;
-	LLUUID mGroupID;
-	SetItemOwnerAndGroup(const LLUUID& authority_id,
-						 const LLUUID& owner_id,
-						 const LLUUID& group_id) :
-		mAuthorityID(authority_id), mOwnerID(owner_id), mGroupID(group_id) {}
-	void operator()(LLInventoryItem* item) const
-	{
-		LLPermissions perm = item->getPermissions();
-		bool is_atomic = (LLAssetType::AT_OBJECT == item->getType()) ? false : true;
-		perm.setOwnerAndGroup(mAuthorityID, mOwnerID, mGroupID, is_atomic);
-		// If no owner id is set, this is equivalent to a deed action.
-		// Clear 'share with group'.
-		if (mOwnerID.isNull())
-		{
-			perm.setMaskGroup(PERM_NONE);
-		}
-		item->setPermissions(perm);
-	}
-};
-
-// This functor is used to unset the share with group, everyone perms, and
-// for sale info for objects being sold through contents.
-struct SetNotForSale
-{
-	LLUUID mAgentID;
-	LLUUID mGroupID;
-	SetNotForSale(const LLUUID& agent_id,
-				  const LLUUID& group_id) :
-			mAgentID(agent_id), mGroupID(group_id) {}
-	void operator()(LLInventoryItem* item) const
-	{
-		// Clear group & everyone permissions.
-		LLPermissions perm = item->getPermissions();
-		perm.setGroupBits(mAgentID, mGroupID, FALSE, PERM_MODIFY | PERM_MOVE | PERM_COPY);
-		perm.setEveryoneBits(mAgentID, mGroupID, FALSE, PERM_MOVE | PERM_COPY);
-		item->setPermissions(perm);
-
-		// Mark group & everyone permissions for overwrite on the next
-		// rez if it is an object.
-		if(LLAssetType::AT_OBJECT == item->getType())
-		{
-			U32 flags = item->getFlags();
-			flags |= LLInventoryItem::II_FLAGS_OBJECT_PERM_OVERWRITE_GROUP;
-			flags |= LLInventoryItem::II_FLAGS_OBJECT_PERM_OVERWRITE_EVERYONE;
-			item->setFlags(flags);
-		}
-
-		// Clear for sale info.
-		item->setSaleInfo(LLSaleInfo::DEFAULT);
-	}
-};
-
 typedef std::list<LLPointer<LLInventoryObject> > InventoryObjectList;
 
 // These functions convert between structured data and an inventroy
 // item, appropriate for serialization.
 LLSD ll_create_sd_from_inventory_item(LLPointer<LLInventoryItem> item);
-LLPointer<LLInventoryItem> ll_create_item_from_sd(const LLSD& sd_item);
+//LLPointer<LLInventoryItem> ll_create_item_from_sd(const LLSD& sd_item);
 LLSD ll_create_sd_from_inventory_category(LLPointer<LLInventoryCategory> cat);
 LLPointer<LLInventoryCategory> ll_create_category_from_sd(const LLSD& sd_cat);
 
diff --git a/indra/llinventory/llsaleinfo.cpp b/indra/llinventory/llsaleinfo.cpp
index 11709bc5934..b7afb28adf9 100644
--- a/indra/llinventory/llsaleinfo.cpp
+++ b/indra/llinventory/llsaleinfo.cpp
@@ -111,7 +111,7 @@ LLSD LLSaleInfo::asLLSD() const
 	return sd;
 }
 
-bool LLSaleInfo::fromLLSD(LLSD& sd, BOOL& has_perm_mask, U32& perm_mask)
+bool LLSaleInfo::fromLLSD(const LLSD& sd, BOOL& has_perm_mask, U32& perm_mask)
 {
 	const char *w;
 
diff --git a/indra/llinventory/llsaleinfo.h b/indra/llinventory/llsaleinfo.h
index 07f440527bf..d546c49fd7e 100644
--- a/indra/llinventory/llsaleinfo.h
+++ b/indra/llinventory/llsaleinfo.h
@@ -98,7 +98,7 @@ class LLSaleInfo
 	BOOL exportLegacyStream(std::ostream& output_stream) const;
 	LLSD asLLSD() const;
 	operator LLSD() const { return asLLSD(); }
-	bool fromLLSD(LLSD& sd, BOOL& has_perm_mask, U32& perm_mask);
+	bool fromLLSD(const LLSD& sd, BOOL& has_perm_mask, U32& perm_mask);
 	BOOL importLegacyStream(std::istream& input_stream, BOOL& has_perm_mask, U32& perm_mask);
 
 	LLXMLNode *exportFileXML() const;
diff --git a/indra/llprimitive/CMakeLists.txt b/indra/llprimitive/CMakeLists.txt
index 5dc4c701a1c..478dd398fff 100644
--- a/indra/llprimitive/CMakeLists.txt
+++ b/indra/llprimitive/CMakeLists.txt
@@ -18,6 +18,7 @@ include_directories(
 set(llprimitive_SOURCE_FILES
     llmaterialtable.cpp
     llprimitive.cpp
+    llprimtexturelist.cpp
     lltextureanim.cpp
     lltextureentry.cpp
     lltreeparams.cpp
@@ -31,6 +32,7 @@ set(llprimitive_HEADER_FILES
     legacy_object_types.h
     llmaterialtable.h
     llprimitive.h
+    llprimtexturelist.h
     lltextureanim.h
     lltextureentry.h
     lltreeparams.h
diff --git a/indra/llprimitive/llprimitive.cpp b/indra/llprimitive/llprimitive.cpp
index 6fc0a559ae4..13facc0d582 100644
--- a/indra/llprimitive/llprimitive.cpp
+++ b/indra/llprimitive/llprimitive.cpp
@@ -44,6 +44,7 @@
 #include "llstring.h"
 #include "lldatapacker.h"
 #include "llsdutil.h"
+#include "llprimtexturelist.h"
 
 /**
  * exported constants
@@ -112,6 +113,7 @@ const F32 FLEXIBLE_OBJECT_DEFAULT_LENGTH = 1.0f;
 const BOOL FLEXIBLE_OBJECT_DEFAULT_USING_COLLISION_SPHERE = FALSE;
 const BOOL FLEXIBLE_OBJECT_DEFAULT_RENDERING_COLLISION_SPHERE = FALSE;
 
+const S32 MAX_FACE_BITS = 9;
 
 const char *SCULPT_DEFAULT_TEXTURE = "be293869-d0d9-0a69-5989-ad27f1946fd4"; // old inverted texture: "7595d345-a24c-e7ef-f0bd-78793792133e";
 
@@ -151,7 +153,8 @@ bool LLPrimitive::cleanupVolumeManager()
 
 //===============================================================
 LLPrimitive::LLPrimitive()
-:	mMiscFlags(0)
+:	mTextureList(),
+	mMiscFlags(0)
 {
 	mPrimitiveCode = 0;
 
@@ -168,20 +171,12 @@ LLPrimitive::LLPrimitive()
 	mAngularVelocity.setVec(0.f,0.f,0.f);
 	
 	mScale.setVec(1.f,1.f,1.f);
-
-	mNumTEs = 0;
-	mTextureList = NULL;
 }
 
 //===============================================================
 LLPrimitive::~LLPrimitive()
 {
-	if (mTextureList)
-	{
-		delete [] mTextureList;
-		mTextureList = NULL;
-	}
-
+	clearTextureList();
 	// Cleanup handled by volume manager
 	if (mVolumep)
 	{
@@ -190,6 +185,10 @@ LLPrimitive::~LLPrimitive()
 	mVolumep = NULL;
 }
 
+void LLPrimitive::clearTextureList()
+{
+}
+
 //===============================================================
 // static
 LLPrimitive *LLPrimitive::createPrimitive(LLPCode p_code)
@@ -213,15 +212,7 @@ LLPrimitive *LLPrimitive::createPrimitive(LLPCode p_code)
 void LLPrimitive::init_primitive(LLPCode p_code)
 {
 	LLMemType m1(LLMemType::MTYPE_PRIMITIVE);
-	if (mNumTEs)
-	{
-		if (mTextureList)
-		{
-			delete [] mTextureList;
-		}
-		mTextureList = new LLTextureEntry[mNumTEs];
-	}
-
+	clearTextureList();
 	mPrimitiveCode = p_code;
 }
 
@@ -231,342 +222,146 @@ void LLPrimitive::setPCode(const U8 p_code)
 }
 
 //===============================================================
-const LLTextureEntry * LLPrimitive::getTE(const U8 te_num) const
+LLTextureEntry* LLPrimitive::getTE(const U8 index) const
 {
-	// if we're asking for a non-existent face, return null
-	if (mNumTEs && (te_num< mNumTEs))
-	{
-		return(&mTextureList[te_num]);
-	}
-	else
-	{	
-		return(NULL);
-	}
+	return mTextureList.getTexture(index);
 }
 
 //===============================================================
 void LLPrimitive::setNumTEs(const U8 num_tes)
 {
-	if (num_tes == mNumTEs)
-	{
-		return;
-	}
-	
-	// Right now, we don't try and preserve entries when the number of faces
-	// changes.
-
-	LLMemType m1(LLMemType::MTYPE_PRIMITIVE);
-	if (num_tes)
-	{
-		LLTextureEntry *new_tes;
-		new_tes = new LLTextureEntry[num_tes];
-		U32 i;
-		for (i = 0; i < num_tes; i++)
-		{
-			if (i < mNumTEs)
-			{
-				new_tes[i] = mTextureList[i];
-			}
-			else if (mNumTEs)
-			{
-				new_tes[i] = mTextureList[mNumTEs - 1];
-			}
-			else
-			{
-				new_tes[i] = LLTextureEntry();
-			}
-		}
-		delete[] mTextureList;
-		mTextureList = new_tes;
-	}
-	else
-	{
-		delete[] mTextureList;
-		mTextureList = NULL;
-	}
-
-
-	mNumTEs = num_tes;
+	mTextureList.setSize(num_tes);
 }
 
 //===============================================================
 void  LLPrimitive::setAllTETextures(const LLUUID &tex_id)
 {
-	U8 i;
-
-	for (i = 0; i < mNumTEs; i++)
-	{
-		mTextureList[i].setID(tex_id);
-	}
+	mTextureList.setAllIDs(tex_id);
 }
 
 //===============================================================
-void LLPrimitive::setTE(const U8 index, const LLTextureEntry &te)
+void LLPrimitive::setTE(const U8 index, const LLTextureEntry& te)
 {
-	mTextureList[index] = te;
+	mTextureList.copyTexture(index, te);
 }
 
-S32  LLPrimitive::setTETexture(const U8 te, const LLUUID &tex_id)
+S32  LLPrimitive::setTETexture(const U8 index, const LLUUID &id)
 {
-    // if we're asking for a non-existent face, return null
-	if (te >= mNumTEs)
-	{
-		llwarns << "setting non-existent te " << te << llendl
-		return 0;
-	}
-
-	return mTextureList[te].setID(tex_id);
+	return mTextureList.setID(index, id);
 }
 
-S32  LLPrimitive::setTEColor(const U8 te, const LLColor4 &color)
+S32  LLPrimitive::setTEColor(const U8 index, const LLColor4 &color)
 {
-    // if we're asking for a non-existent face, return null
-	if (te >= mNumTEs)
-	{
-		llwarns << "setting non-existent te " << te << llendl
-		return 0;
-	}
-
-	return mTextureList[te].setColor(color);
+	return mTextureList.setColor(index, color);
 }
 
-S32  LLPrimitive::setTEColor(const U8 te, const LLColor3 &color)
+S32  LLPrimitive::setTEColor(const U8 index, const LLColor3 &color)
 {
-    // if we're asking for a non-existent face, return null
-	if (te >= mNumTEs)
-	{
-		llwarns << "setting non-existent te " << te << llendl
-		return 0;
-	}
-
-	return mTextureList[te].setColor(color);
+	return mTextureList.setColor(index, color);
 }
 
-S32  LLPrimitive::setTEAlpha(const U8 te, const F32 alpha)
+S32  LLPrimitive::setTEAlpha(const U8 index, const F32 alpha)
 {
-    // if we're asking for a non-existent face, return null
-	if (te >= mNumTEs)
-	{
-		llwarns << "setting non-existent te " << te << llendl
-		return 0;
-	}
-
-	return mTextureList[te].setAlpha(alpha);
+	return mTextureList.setAlpha(index, alpha);
 }
 
 //===============================================================
-S32  LLPrimitive::setTEScale(const U8 te, const F32 s, const F32 t)
+S32  LLPrimitive::setTEScale(const U8 index, const F32 s, const F32 t)
 {
-    // if we're asking for a non-existent face, return null
-	if (te >= mNumTEs)
-	{
-		llwarns << "Setting nonexistent face" << llendl;
-		return 0;
-	}
-
-	return mTextureList[te].setScale(s,t);
+	return mTextureList.setScale(index, s, t);
 }
 
 
 // BUG: slow - done this way because texture entries have some
 // voodoo related to texture coords
-S32 LLPrimitive::setTEScaleS(const U8 te, const F32 s)
+S32 LLPrimitive::setTEScaleS(const U8 index, const F32 s)
 {
-	if (te >= mNumTEs)
-	{
-		llwarns << "Setting nonexistent face" << llendl;
-		return 0;
-	}
-
-	F32 ignore, t;
-	mTextureList[te].getScale(&ignore, &t);
-	return mTextureList[te].setScale(s,t);
+	return mTextureList.setScaleS(index, s);
 }
 
 
 // BUG: slow - done this way because texture entries have some
 // voodoo related to texture coords
-S32 LLPrimitive::setTEScaleT(const U8 te, const F32 t)
+S32 LLPrimitive::setTEScaleT(const U8 index, const F32 t)
 {
-	if (te >= mNumTEs)
-	{
-		llwarns << "Setting nonexistent face" << llendl;
-		return 0;
-	}
-
-	F32 s, ignore;
-	mTextureList[te].getScale(&s, &ignore);
-	return mTextureList[te].setScale(s,t);
+	return mTextureList.setScaleT(index, t);
 }
 
 
 //===============================================================
-S32  LLPrimitive::setTEOffset(const U8 te, const F32 s, const F32 t)
+S32  LLPrimitive::setTEOffset(const U8 index, const F32 s, const F32 t)
 {
-    // if we're asking for a non-existent face, return null
-	if (te >= mNumTEs)
-	{
-		llwarns << "Setting nonexistent face" << llendl;
-		return 0;
-	}
-
-	return mTextureList[te].setOffset(s,t);
+	return mTextureList.setOffset(index, s, t);
 }
 
 
 // BUG: slow - done this way because texture entries have some
 // voodoo related to texture coords
-S32 LLPrimitive::setTEOffsetS(const U8 te, const F32 s)
+S32 LLPrimitive::setTEOffsetS(const U8 index, const F32 s)
 {
-	if (te >= mNumTEs)
-	{
-		llwarns << "Setting nonexistent face" << llendl;
-		return 0;
-	}
-
-	F32 ignore, t;
-	mTextureList[te].getOffset(&ignore, &t);
-	return mTextureList[te].setOffset(s,t);
+	return mTextureList.setOffsetS(index, s);
 }
 
 
 // BUG: slow - done this way because texture entries have some
 // voodoo related to texture coords
-S32 LLPrimitive::setTEOffsetT(const U8 te, const F32 t)
+S32 LLPrimitive::setTEOffsetT(const U8 index, const F32 t)
 {
-	if (te >= mNumTEs)
-	{
-		llwarns << "Setting nonexistent face" << llendl;
-		return 0;
-	}
-
-	F32 s, ignore;
-	mTextureList[te].getOffset(&s, &ignore);
-	return mTextureList[te].setOffset(s,t);
+	return mTextureList.setOffsetT(index, t);
 }
 
 
 //===============================================================
-S32  LLPrimitive::setTERotation(const U8 te, const F32 r)
+S32  LLPrimitive::setTERotation(const U8 index, const F32 r)
 {
-     // if we're asking for a non-existent face, return null
-	if (te >= mNumTEs)
-	{
-		llwarns << "Setting nonexistent face" << llendl;
-		return 0;
-	}
-
-	return mTextureList[te].setRotation(r);
+	return mTextureList.setRotation(index, r);
 }
 
 
 //===============================================================
-S32  LLPrimitive::setTEBumpShinyFullbright(const U8 te, const U8 bump)
+S32  LLPrimitive::setTEBumpShinyFullbright(const U8 index, const U8 bump)
 {
-    // if we're asking for a non-existent face, return null
-	if (te >= mNumTEs)
-	{
-		llwarns << "setting non-existent te " << te << llendl
-		return 0;
-	}
-
-	return mTextureList[te].setBumpShinyFullbright( bump );
+	return mTextureList.setBumpShinyFullbright(index, bump);
 }
 
-S32  LLPrimitive::setTEMediaTexGen(const U8 te, const U8 media)
+S32  LLPrimitive::setTEMediaTexGen(const U8 index, const U8 media)
 {
-    // if we're asking for a non-existent face, return null
-	if (te >= mNumTEs)
-	{
-		llwarns << "setting non-existent te " << te << llendl
-		return 0;
-	}
-
-	return mTextureList[te].setMediaTexGen( media );
+	return mTextureList.setMediaTexGen(index, media);
 }
 
-S32  LLPrimitive::setTEBumpmap(const U8 te, const U8 bump)
+S32  LLPrimitive::setTEBumpmap(const U8 index, const U8 bump)
 {
-    // if we're asking for a non-existent face, return null
-	if (te >= mNumTEs)
-	{
-		llwarns << "setting non-existent te " << te << llendl
-		return 0;
-	}
-
-	return mTextureList[te].setBumpmap( bump );
+	return mTextureList.setBumpMap(index, bump);
 }
 
-S32  LLPrimitive::setTEBumpShiny(const U8 te, const U8 bump_shiny)
+S32  LLPrimitive::setTEBumpShiny(const U8 index, const U8 bump_shiny)
 {
-    // if we're asking for a non-existent face, return null
-	if (te >= mNumTEs)
-	{
-		llwarns << "setting non-existent te " << te << llendl
-		return 0;
-	}
-
-	return mTextureList[te].setBumpShiny( bump_shiny );
+	return mTextureList.setBumpShiny(index, bump_shiny);
 }
 
-S32  LLPrimitive::setTETexGen(const U8 te, const U8 texgen)
+S32  LLPrimitive::setTETexGen(const U8 index, const U8 texgen)
 {
-    // if we're asking for a non-existent face, return null
-	if (te >= mNumTEs)
-	{
-		llwarns << "setting non-existent te " << te << llendl
-		return 0;
-	}
-
-	return mTextureList[te].setTexGen( texgen );
+	return mTextureList.setTexGen(index, texgen);
 }
 
-S32  LLPrimitive::setTEShiny(const U8 te, const U8 shiny)
+S32  LLPrimitive::setTEShiny(const U8 index, const U8 shiny)
 {
-    // if we're asking for a non-existent face, return null
-	if (te >= mNumTEs)
-	{
-		llwarns << "setting non-existent te " << te << llendl
-		return 0;
-	}
-
-	return mTextureList[te].setShiny( shiny );
+	return mTextureList.setShiny(index, shiny);
 }
 
-S32  LLPrimitive::setTEFullbright(const U8 te, const U8 fullbright)
+S32  LLPrimitive::setTEFullbright(const U8 index, const U8 fullbright)
 {
-    // if we're asking for a non-existent face, return null
-	if (te >= mNumTEs)
-	{
-		llwarns << "setting non-existent te " << te << llendl
-		return 0;
-	}
-
-	return mTextureList[te].setFullbright( fullbright );
+	return mTextureList.setFullbright(index, fullbright);
 }
 
-S32  LLPrimitive::setTEMediaFlags(const U8 te, const U8 media_flags)
+S32  LLPrimitive::setTEMediaFlags(const U8 index, const U8 media_flags)
 {
-    // if we're asking for a non-existent face, return null
-	if (te >= mNumTEs)
-	{
-		llwarns << "setting non-existent te " << te << llendl
-		return 0;
-	}
-
-	return mTextureList[te].setMediaFlags( media_flags );
+	return mTextureList.setMediaFlags(index, media_flags);
 }
 
-S32 LLPrimitive::setTEGlow(const U8 te, const F32 glow)
+S32 LLPrimitive::setTEGlow(const U8 index, const F32 glow)
 {
-	// if we're asking for a non-existent face, return null
-	if (te >= mNumTEs)
-	{
-		llwarns << "setting non-existent te " << te << llendl
-			return 0;
-	}
-
-	return mTextureList[te].setGlow( glow );
+	return mTextureList.setGlow(index, glow);
 }
 
 
@@ -878,25 +673,18 @@ std::string LLPrimitive::pCodeToString(const LLPCode pcode)
 void LLPrimitive::copyTEs(const LLPrimitive *primitivep)
 {
 	U32 i;
-	if (primitivep->getNumTEs() != getNumTEs())
+	if (primitivep->getExpectedNumTEs() != getExpectedNumTEs())
+	{
+		llwarns << "Primitives don't have same expected number of TE's" << llendl;
+	}
+	U32 num_tes = llmin(primitivep->getExpectedNumTEs(), getExpectedNumTEs());
+	if (mTextureList.size() < getExpectedNumTEs())
 	{
-		llwarns << "Primitives don't have same number of TE's" << llendl;
+		mTextureList.setSize(getExpectedNumTEs());
 	}
-	U32 num_tes = llmin(primitivep->getNumTEs(), getNumTEs());
 	for (i = 0; i < num_tes; i++)
 	{
-		const LLTextureEntry *tep = primitivep->getTE(i);
-		F32 s, t;
-		setTETexture(i, tep->getID());
-		setTEColor(i, tep->getColor());
-		tep->getScale(&s, &t);
-		setTEScale(i, s, t);
-		tep->getOffset(&s, &t);
-		setTEOffset(i, s, t);
-		setTERotation(i, tep->getRotation());
-		setTEBumpShinyFullbright(i, tep->getBumpShinyFullbright());
-		setTEMediaTexGen(i, tep->getMediaTexGen());
-		setTEGlow(i, tep->getGlow());
+		mTextureList.copyTexture(i, *(primitivep->getTE(i)));
 	}
 }
 
@@ -962,12 +750,12 @@ BOOL LLPrimitive::setVolume(const LLVolumeParams &volume_params, const S32 detai
 	sVolumeManager->unrefVolume(mVolumep);
 	mVolumep = volumep;
 	
-	U32 new_face_mask = mVolumep->mFaceMask;	
+	U32 new_face_mask = mVolumep->mFaceMask;
 	if (old_face_mask != new_face_mask) 
 	{
 		setNumTEs(mVolumep->getNumFaces());
-	}	
-	
+	}
+
 	return TRUE;
 }
 
@@ -984,50 +772,6 @@ BOOL LLPrimitive::setMaterial(U8 material)
 	}
 }
 
-void LLPrimitive::setTEArrays(const U8 size,
-							  const LLUUID* image_ids,
-							  const F32* scale_s,
-							  const F32* scale_t)
-{
-	S32 cur_size = size;
-	if (cur_size > getNumTEs())
-	{
-		llwarns << "Trying to set more TEs than exist!" << llendl;
-		cur_size = getNumTEs();
-	}
-
-	S32 i;
-	// Copy over image information
-	for (i = 0; i < cur_size; i++)
-	{
-		// This is very BAD!!!!!!
-		if (image_ids != NULL)
-		{
-			setTETexture(i,image_ids[i]);
-		}
-		if (scale_s && scale_t)
-		{
-			setTEScale(i, scale_s[i], scale_t[i]);
-		}
- 	}
-
-	if (i < getNumTEs())
-	{
-		cur_size--;
-		for (i=i; i < getNumTEs(); i++)		// the i=i removes a gcc warning
-		{
-			if (image_ids != NULL)
-			{
-				setTETexture(i, image_ids[cur_size]);
-			}
-			if (scale_s && scale_t)
-			{
-				setTEScale(i, scale_s[cur_size], scale_t[cur_size]);
-			}
-		}
-	}
-}
-
 const F32 LL_MAX_SCALE_S = 100.0f;
 const F32 LL_MAX_SCALE_T = 100.0f;
 S32 LLPrimitive::packTEField(U8 *cur_ptr, U8 *data_ptr, U8 data_size, U8 last_face_index, EMsgVariableType type) const
@@ -1489,11 +1233,24 @@ S32 LLPrimitive::unpackTEMessage(LLDataPacker &dp)
 	return retval;
 }
 
-void LLPrimitive::setTextureList(LLTextureEntry *listp)
+U8	LLPrimitive::getExpectedNumTEs() const
+{
+	U8 expected_face_count = 0;
+	if (mVolumep)
+	{
+		expected_face_count = mVolumep->getNumFaces();
+	}
+	return expected_face_count;
+}
+
+void LLPrimitive::copyTextureList(const LLPrimTextureList& other_list)
+{
+	mTextureList.copy(other_list);
+}
+
+void LLPrimitive::takeTextureList(LLPrimTextureList& other_list)
 {
-	LLTextureEntry* old_texture_list = mTextureList;
-	mTextureList = listp;
- 	delete[] old_texture_list;
+	mTextureList.take(other_list);
 }
 
 //============================================================================
diff --git a/indra/llprimitive/llprimitive.h b/indra/llprimitive/llprimitive.h
index cc86f5b7472..c25df0a40f5 100644
--- a/indra/llprimitive/llprimitive.h
+++ b/indra/llprimitive/llprimitive.h
@@ -40,6 +40,7 @@
 #include "llmemory.h"
 #include "llvolume.h"
 #include "lltextureentry.h"
+#include "llprimtexturelist.h"
 
 // Moved to stdtypes.h --JC
 // typedef U8 LLPCode;
@@ -295,6 +296,8 @@ class LLPrimitive : public LLXform
 	LLPrimitive();
 	virtual ~LLPrimitive();
 
+	void clearTextureList();
+
 	static LLPrimitive *createPrimitive(LLPCode p_code);
 	void init_primitive(LLPCode p_code);
 
@@ -305,11 +308,11 @@ class LLPrimitive : public LLXform
 
 	// Modify texture entry properties
 	inline BOOL validTE(const U8 te_num) const;
-	const LLTextureEntry *getTE(const U8 te_num) const;
+	LLTextureEntry* getTE(const U8 te_num) const;
 
 	virtual void setNumTEs(const U8 num_tes);
 	virtual void setAllTETextures(const LLUUID &tex_id);
-	virtual void setTE(const U8 index, const LLTextureEntry &te);
+	virtual void setTE(const U8 index, const LLTextureEntry& te);
 	virtual S32 setTEColor(const U8 te, const LLColor4 &color);
 	virtual S32 setTEColor(const U8 te, const LLColor3 &color);
 	virtual S32 setTEAlpha(const U8 te, const F32 alpha);
@@ -332,10 +335,6 @@ class LLPrimitive : public LLXform
 	virtual S32 setTEGlow(const U8 te, const F32 glow);
 	virtual BOOL setMaterial(const U8 material); // returns TRUE if material changed
 
-	void setTEArrays(const U8 size,
-					  const LLUUID* image_ids,
-					  const F32* scale_s,
-					  const F32* scale_t);
 	void copyTEs(const LLPrimitive *primitive);
 	S32 packTEField(U8 *cur_ptr, U8 *data_ptr, U8 data_size, U8 last_face_index, EMsgVariableType type) const;
 	S32 unpackTEField(U8 *cur_ptr, U8 *buffer_end, U8 *data_ptr, U8 data_size, U8 face_count, EMsgVariableType type);
@@ -383,14 +382,21 @@ class LLPrimitive : public LLXform
 	const LLVector3&	getAngularVelocity() const	{ return mAngularVelocity; }
 	const LLVector3&	getVelocity() const			{ return mVelocity; }
 	const LLVector3&	getAcceleration() const		{ return mAcceleration; }
-	U8					getNumTEs() const			{ return mNumTEs; }
+	U8					getNumTEs() const			{ return mTextureList.size(); }
+	U8					getExpectedNumTEs() const;
 
 	U8					getMaterial() const			{ return mMaterial; }
 	
 	void				setVolumeType(const U8 code);
 	U8					getVolumeType();
 
-	void setTextureList(LLTextureEntry *listp);
+	// clears existing textures
+	// copies the contents of other_list into mEntryList
+	void copyTextureList(const LLPrimTextureList& other_list);
+
+	// clears existing textures
+	// takes the contents of other_list and clears other_list
+	void takeTextureList(LLPrimTextureList& other_list);
 
 	inline BOOL	isAvatar() const;
 	inline BOOL	isSittingAvatar() const;
@@ -415,7 +421,7 @@ class LLPrimitive : public LLXform
 	LLVector3			mAcceleration;		// are we under constant acceleration?
 	LLVector3			mAngularVelocity;	// angular velocity
 	LLPointer<LLVolume> mVolumep;
-	LLTextureEntry		*mTextureList;		// list of texture GUIDs, scales, offsets
+	LLPrimTextureList	mTextureList;		// list of texture GUIDs, scales, offsets
 	U8					mMaterial;			// Material code
 	U8					mNumTEs;			// # of faces on the primitve	
 	U32 				mMiscFlags;			// home for misc bools
diff --git a/indra/llprimitive/llprimtexturelist.cpp b/indra/llprimitive/llprimtexturelist.cpp
new file mode 100644
index 00000000000..c9632ebdad8
--- /dev/null
+++ b/indra/llprimitive/llprimtexturelist.cpp
@@ -0,0 +1,414 @@
+/** 
+ * @file lltexturelist.cpp
+ * @brief LLPrimTextureList (virtual) base class
+ *
+ * $LicenseInfo:firstyear=2008&license=viewergpl$
+ * 
+ * Copyright (c) 2008-2007, Linden Research, Inc.
+ * 
+ * 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
+ * 
+ * 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
+ * 
+ * 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.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+
+#include "llprimtexturelist.h"
+#include "lltextureentry.h"
+#include "llmemtype.h"
+
+// static 
+//int (TMyClass::*pt2Member)(float, char, char) = NULL;                // C++
+LLTextureEntry* (*LLPrimTextureList::sNewTextureEntryCallback)() = &(LLTextureEntry::newTextureEntry);
+
+// static
+void LLPrimTextureList::setNewTextureEntryCallback( LLTextureEntry* (*callback)() )
+{
+	if (callback)
+	{
+		LLPrimTextureList::sNewTextureEntryCallback = callback;
+	}
+	else
+	{
+		LLPrimTextureList::sNewTextureEntryCallback = &(LLTextureEntry::newTextureEntry);
+	}
+}
+
+// static 
+// call this to get a new texture entry
+LLTextureEntry* LLPrimTextureList::newTextureEntry()
+{
+	return (*sNewTextureEntryCallback)();
+}
+
+LLPrimTextureList::LLPrimTextureList()
+{
+}
+
+// virtual 
+LLPrimTextureList::~LLPrimTextureList()
+{
+	clear();
+}
+
+void LLPrimTextureList::clear()
+{
+	texture_list_t::iterator itr = mEntryList.begin();
+	while (itr != mEntryList.end())
+	{
+		delete (*itr);
+		(*itr) = NULL;
+		++itr;
+	}
+	mEntryList.clear();
+}
+
+
+// clears current entries
+// copies contents of other_list
+// this is somewhat expensive, so it must be called explicitly
+void LLPrimTextureList::copy(const LLPrimTextureList& other_list)
+{
+	// compare the sizes
+	S32 this_size = mEntryList.size();
+	S32 other_size = other_list.mEntryList.size();
+
+	if (this_size > other_size)
+	{
+		// remove the extra entries
+		for (S32 index = this_size; index > other_size; --index)
+		{
+			delete mEntryList[index-1];
+		}
+		mEntryList.resize(other_size);
+		this_size = other_size;
+	}
+
+	S32 index = 0;
+	// copy for the entries that already exist
+	for ( ; index < this_size; ++index)
+	{
+		delete mEntryList[index];
+		mEntryList[index] = other_list.getTexture(index)->newCopy();
+	}
+
+	// add new entires if needed
+	for ( ; index < other_size; ++index)
+	{
+		mEntryList.push_back( other_list.getTexture(index)->newCopy() );
+	}
+}
+
+// clears current copies
+// takes contents of other_list
+// clears other_list
+void LLPrimTextureList::take(LLPrimTextureList& other_list)
+{
+	clear();
+	mEntryList = other_list.mEntryList;
+	other_list.mEntryList.clear();
+}
+
+// virtual 
+// copies LLTextureEntry 'te'
+// returns TEM_CHANGE_TEXTURE if successful, otherwise TEM_CHANGE_NONE
+S32 LLPrimTextureList::copyTexture(const U8 index, const LLTextureEntry& te)
+{
+	if (S32(index) >= mEntryList.size())
+	{
+		// TODO -- assert here
+		S32 current_size = mEntryList.size();
+		llerrs << "index = " << S32(index) << "  current_size = " << current_size << llendl;
+		return TEM_CHANGE_NONE;
+	}
+
+	// we're changing an existing entry
+	llassert(mEntryList[index]);
+	delete (mEntryList[index]);
+	if  (&te)
+	{
+		mEntryList[index] = te.newCopy();
+	}
+	else
+	{
+		mEntryList[index] = LLPrimTextureList::newTextureEntry();
+	}
+	return TEM_CHANGE_TEXTURE;
+}
+
+// virtual 
+// takes ownership of LLTextureEntry* 'te'
+// returns TEM_CHANGE_TEXTURE if successful, otherwise TEM_CHANGE_NONE
+// IMPORTANT! -- if you use this function you must check the return value
+S32 LLPrimTextureList::takeTexture(const U8 index, LLTextureEntry* te)
+{
+	if (S32(index) >= mEntryList.size())
+	{
+		return TEM_CHANGE_NONE;
+	}
+
+	// we're changing an existing entry
+	llassert(mEntryList[index]);
+	delete (mEntryList[index]);
+	mEntryList[index] = te;
+	return TEM_CHANGE_TEXTURE;
+}
+
+// returns pointer to texture at 'index' slot
+LLTextureEntry* LLPrimTextureList::getTexture(const U8 index) const
+{
+	if (index < mEntryList.size())
+	{
+		return mEntryList[index];
+	}
+	return NULL;
+}
+
+//virtual 
+//S32 setTE(const U8 index, const LLTextureEntry& te) = 0;
+
+S32 LLPrimTextureList::setID(const U8 index, const LLUUID& id)
+{
+	if (index < mEntryList.size())
+	{
+		return mEntryList[index]->setID(id);
+	}
+	return TEM_CHANGE_NONE;
+}
+
+S32 LLPrimTextureList::setColor(const U8 index, const LLColor3& color)
+{
+	if (index < mEntryList.size())
+	{
+		return mEntryList[index]->setColor(color);
+	}
+	return TEM_CHANGE_NONE;
+}
+
+S32 LLPrimTextureList::setColor(const U8 index, const LLColor4& color)
+{
+	if (index < mEntryList.size())
+	{
+		return mEntryList[index]->setColor(color);
+	}
+	return TEM_CHANGE_NONE;
+}
+
+S32 LLPrimTextureList::setAlpha(const U8 index, const F32 alpha)
+{
+	if (index < mEntryList.size())
+	{
+		return mEntryList[index]->setAlpha(alpha);
+	}
+	return TEM_CHANGE_NONE;
+}
+
+S32 LLPrimTextureList::setScale(const U8 index, const F32 s, const F32 t)
+{
+	if (index < mEntryList.size())
+	{
+		return mEntryList[index]->setScale(s, t);
+	}
+	return TEM_CHANGE_NONE;
+}
+
+S32 LLPrimTextureList::setScaleS(const U8 index, const F32 s)
+{
+	if (index < mEntryList.size())
+	{
+		return mEntryList[index]->setScaleS(s);
+	}
+	return TEM_CHANGE_NONE;
+}
+
+S32 LLPrimTextureList::setScaleT(const U8 index, const F32 t)
+{
+	if (index < mEntryList.size())
+	{
+		return mEntryList[index]->setScaleT(t);
+	}
+	return TEM_CHANGE_NONE;
+}
+
+S32 LLPrimTextureList::setOffset(const U8 index, const F32 s, const F32 t)
+{
+	if (index < mEntryList.size())
+	{
+		return mEntryList[index]->setOffset(s, t);
+	}
+	return TEM_CHANGE_NONE;
+}
+
+S32 LLPrimTextureList::setOffsetS(const U8 index, const F32 s)
+{
+	if (index < mEntryList.size())
+	{
+		return mEntryList[index]->setOffsetS(s);
+	}
+	return TEM_CHANGE_NONE;
+}
+
+S32 LLPrimTextureList::setOffsetT(const U8 index, const F32 t)
+{
+	if (index < mEntryList.size())
+	{
+		return mEntryList[index]->setOffsetT(t);
+	}
+	return TEM_CHANGE_NONE;
+}
+
+S32 LLPrimTextureList::setRotation(const U8 index, const F32 r)
+{
+	if (index < mEntryList.size())
+	{
+		return mEntryList[index]->setRotation(r);
+	}
+	return TEM_CHANGE_NONE;
+}
+
+S32 LLPrimTextureList::setBumpShinyFullbright(const U8 index, const U8 bump)
+{
+	if (index < mEntryList.size())
+	{
+		return mEntryList[index]->setBumpShinyFullbright(bump);
+	}
+	return TEM_CHANGE_NONE;
+}
+
+S32 LLPrimTextureList::setMediaTexGen(const U8 index, const U8 media)
+{
+	if (index < mEntryList.size())
+	{
+		return mEntryList[index]->setMediaTexGen(media);
+	}
+	return TEM_CHANGE_NONE;
+}
+
+S32 LLPrimTextureList::setBumpMap(const U8 index, const U8 bump)
+{
+	if (index < mEntryList.size())
+	{
+		return mEntryList[index]->setBumpmap(bump);
+	}
+	return TEM_CHANGE_NONE;
+}
+
+S32 LLPrimTextureList::setBumpShiny(const U8 index, const U8 bump_shiny)
+{
+	if (index < mEntryList.size())
+	{
+		return mEntryList[index]->setBumpShiny(bump_shiny);
+	}
+	return TEM_CHANGE_NONE;
+}
+
+S32 LLPrimTextureList::setTexGen(const U8 index, const U8 texgen)
+{
+	if (index < mEntryList.size())
+	{
+		return mEntryList[index]->setTexGen(texgen);
+	}
+	return TEM_CHANGE_NONE;
+}
+
+S32 LLPrimTextureList::setShiny(const U8 index, const U8 shiny)
+{
+	if (index < mEntryList.size())
+	{
+		return mEntryList[index]->setShiny(shiny);
+	}
+	return TEM_CHANGE_NONE;
+}
+
+S32 LLPrimTextureList::setFullbright(const U8 index, const U8 fullbright)
+{
+	if (index < mEntryList.size())
+	{
+		return mEntryList[index]->setFullbright(fullbright);
+	}
+	return TEM_CHANGE_NONE;
+}
+
+S32 LLPrimTextureList::setMediaFlags(const U8 index, const U8 media_flags)
+{
+	if (index < mEntryList.size())
+	{
+		return mEntryList[index]->setMediaFlags(media_flags);
+	}
+	return TEM_CHANGE_NONE;
+}
+
+S32 LLPrimTextureList::setGlow(const U8 index, const F32 glow)
+{
+	if (index < mEntryList.size())
+	{
+		return mEntryList[index]->setGlow(glow);
+	}
+	return TEM_CHANGE_NONE;
+}
+
+S32 LLPrimTextureList::size() const
+{
+	return mEntryList.size();
+}
+
+// sets the size of the mEntryList container
+void LLPrimTextureList::setSize(S32 new_size)
+{
+	LLMemType m1(LLMemType::MTYPE_PRIMITIVE);
+	if (new_size < 0)
+	{
+		new_size = 0;
+	}
+
+	S32 current_size = mEntryList.size();
+
+	if (new_size > current_size)
+	{
+		mEntryList.resize(new_size);
+		for (S32 index = current_size; index < new_size; ++index)
+		{
+			LLTextureEntry* new_entry = LLPrimTextureList::newTextureEntry();
+			mEntryList[index] = new_entry;
+		}
+	}
+	else if (new_size < current_size)
+	{
+		for (S32 index = current_size-1; index >= new_size; --index)
+		{
+			delete mEntryList[index];
+		}
+		mEntryList.resize(new_size);
+	}
+}
+
+
+void LLPrimTextureList::setAllIDs(const LLUUID& id)
+{
+	texture_list_t::iterator itr = mEntryList.begin();
+	while (itr != mEntryList.end())
+	{
+		(*itr)->setID(id);
+		++itr;
+	}
+}
+
+
diff --git a/indra/llprimitive/llprimtexturelist.h b/indra/llprimitive/llprimtexturelist.h
new file mode 100644
index 00000000000..61285bd1bf6
--- /dev/null
+++ b/indra/llprimitive/llprimtexturelist.h
@@ -0,0 +1,126 @@
+/** 
+ * @file llprimtexturelist.h
+ * @brief LLPrimTextureList (virtual) base class
+ *
+ * $LicenseInfo:firstyear=2008&license=viewergpl$
+ * 
+ * Copyright (c) 2008-2007, Linden Research, Inc.
+ * 
+ * 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
+ * 
+ * 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
+ * 
+ * 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.
+ * 
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLPRIMTEXTURELIST_H
+#define LL_LLPRIMTEXTURELIST_H
+
+#include <vector>
+#include "lluuid.h"
+#include "v3color.h"
+#include "v4color.h"
+
+
+class LLTextureEntry;
+
+// this is a list of LLTextureEntry*'s because in practice the list's elements
+// are of some derived class: LLFooTextureEntry
+typedef std::vector<LLTextureEntry*> texture_list_t;
+
+class LLPrimTextureList
+{
+public:
+	// the LLPrimTextureList needs to know what type of LLTextureEntry 
+	// to generate when it needs a new one, so we may need to set a 
+	// callback for generating it, (or else use the base class default: 
+	// static LLPrimTextureEntry::newTextureEntry() )
+	//typedef LLTextureEntry* (__stdcall *NewTextureEntryFunction)();
+	//static NewTextureEntryFunction sNewTextureEntryCallback;
+	static LLTextureEntry* newTextureEntry();
+	static void setNewTextureEntryCallback( LLTextureEntry* (*callback)() );
+	static LLTextureEntry* (*sNewTextureEntryCallback)(); 
+
+	LLPrimTextureList();
+	virtual ~LLPrimTextureList();
+
+	void clear();
+
+	// clears current entries
+	// copies contents of other_list
+	// this is somewhat expensive, so it must be called explicitly
+	void copy(const LLPrimTextureList& other_list);
+
+	// clears current copies
+	// takes contents of other_list
+	// clears other_list
+	void take(LLPrimTextureList& other_list);
+
+	// copies LLTextureEntry 'te'
+	// returns TEM_CHANGE_TEXTURE if successful, otherwise TEM_CHANGE_NONE
+	S32 copyTexture(const U8 index, const LLTextureEntry& te);
+
+	// takes ownership of LLTextureEntry* 'te'
+	// returns TEM_CHANGE_TEXTURE if successful, otherwise TEM_CHANGE_NONE
+	// IMPORTANT! -- if you use this function you must check the return value
+	S32 takeTexture(const U8 index, LLTextureEntry* te);
+
+//	// copies contents of 'entry' and stores it in 'index' slot
+//	void copyTexture(const U8 index, const LLTextureEntry* entry);
+
+	// returns pointer to texture at 'index' slot
+	LLTextureEntry* getTexture(const U8 index) const;
+
+	S32 setID(const U8 index, const LLUUID& id);
+	S32 setColor(const U8 index, const LLColor3& color);
+	S32 setColor(const U8 index, const LLColor4& color);
+	S32 setAlpha(const U8 index, const F32 alpha);
+	S32 setScale(const U8 index, const F32 s, const F32 t);
+	S32 setScaleS(const U8 index, const F32 s);
+	S32 setScaleT(const U8 index, const F32 t);
+	S32 setOffset(const U8 index, const F32 s, const F32 t);
+	S32 setOffsetS(const U8 index, const F32 s);
+	S32 setOffsetT(const U8 index, const F32 t);
+	S32 setRotation(const U8 index, const F32 r);
+	S32 setBumpShinyFullbright(const U8 index, const U8 bump);
+	S32 setMediaTexGen(const U8 index, const U8 media);
+	S32 setBumpMap(const U8 index, const U8 bump);
+	S32 setBumpShiny(const U8 index, const U8 bump_shiny);
+	S32 setTexGen(const U8 index, const U8 texgen);
+	S32 setShiny(const U8 index, const U8 shiny);
+	S32 setFullbright(const U8 index, const U8 t);
+	S32 setMediaFlags(const U8 index, const U8 media_flags);
+	S32 setGlow(const U8 index, const F32 glow);
+
+	S32 size() const;
+
+//	void forceResize(S32 new_size);
+	void setSize(S32 new_size);
+
+	void setAllIDs(const LLUUID& id);
+protected:
+	texture_list_t mEntryList;
+private:
+	LLPrimTextureList(const LLPrimTextureList& other_list)
+	{
+		// private so that it can't be used
+	}
+};
+
+#endif
diff --git a/indra/llprimitive/lltextureentry.cpp b/indra/llprimitive/lltextureentry.cpp
index 14b45443d15..3bcd831142a 100644
--- a/indra/llprimitive/lltextureentry.cpp
+++ b/indra/llprimitive/lltextureentry.cpp
@@ -39,6 +39,12 @@ const U8 DEFAULT_BUMP_CODE = 0;  // no bump or shininess
 
 const LLTextureEntry LLTextureEntry::null;
 
+// static 
+LLTextureEntry* LLTextureEntry::newTextureEntry()
+{
+	return new LLTextureEntry();
+}
+
 //===============================================================
 LLTextureEntry::LLTextureEntry()
 {
@@ -136,20 +142,23 @@ bool LLTextureEntry::operator==(const LLTextureEntry &rhs) const
 LLSD LLTextureEntry::asLLSD() const
 {
 	LLSD sd;
+	asLLSD(sd);
+	return sd;
+}
 
-	sd["imageid"] = getID();
-	sd["colors"] = ll_sd_from_color4(getColor());
+void LLTextureEntry::asLLSD(LLSD& sd) const
+{
+	sd["imageid"] = mID;
+	sd["colors"] = ll_sd_from_color4(mColor);
 	sd["scales"] = mScaleS;
 	sd["scalet"] = mScaleT;
 	sd["offsets"] = mOffsetS;
 	sd["offsett"] = mOffsetT;
-	sd["imagerot"] = getRotation();
+	sd["imagerot"] = mRotation;
 	sd["bump"] = getBumpShiny();
 	sd["fullbright"] = getFullbright();
-	sd["media_flags"] = getMediaTexGen();
-	sd["glow"] = getGlow();
-	
-	return sd;
+	sd["media_flags"] = mMediaFlags;
+	sd["glow"] = mGlow;
 }
 
 bool LLTextureEntry::fromLLSD(LLSD& sd)
@@ -208,6 +217,19 @@ bool LLTextureEntry::fromLLSD(LLSD& sd)
 	return false;
 }
 
+// virtual 
+// override this method for each derived class
+LLTextureEntry* LLTextureEntry::newBlank() const
+{
+	return new LLTextureEntry();
+}
+
+// virtual 
+LLTextureEntry* LLTextureEntry::newCopy() const
+{
+	return new LLTextureEntry(*this);
+}
+
 S32 LLTextureEntry::setID(const LLUUID &tex_id)
 {
 	if (mID != tex_id)
@@ -215,7 +237,7 @@ S32 LLTextureEntry::setID(const LLUUID &tex_id)
 		mID = tex_id;
 		return TEM_CHANGE_TEXTURE;
 	}
-	return 0;
+	return TEM_CHANGE_NONE;
 }
 
 S32 LLTextureEntry::setScale(F32 s, F32 t)
@@ -233,6 +255,28 @@ S32 LLTextureEntry::setScale(F32 s, F32 t)
 	return retval;
 }
 
+S32 LLTextureEntry::setScaleS(F32 s)
+{
+	S32 retval = TEM_CHANGE_NONE;
+	if (mScaleS != s)
+	{
+		mScaleS = s;
+		retval = TEM_CHANGE_TEXTURE;
+	}
+	return retval;
+}
+
+S32 LLTextureEntry::setScaleT(F32 t)
+{
+	S32 retval = TEM_CHANGE_NONE;
+	if (mScaleT != t)
+	{
+		mScaleT = t;
+		retval = TEM_CHANGE_TEXTURE;
+	}
+	return retval;
+}
+
 S32 LLTextureEntry::setColor(const LLColor4 &color)
 {
 	if (mColor != color)
@@ -240,7 +284,7 @@ S32 LLTextureEntry::setColor(const LLColor4 &color)
 		mColor = color;
 		return TEM_CHANGE_COLOR;
 	}
-	return 0;
+	return TEM_CHANGE_NONE;
 }
 
 S32 LLTextureEntry::setColor(const LLColor3 &color)
@@ -251,7 +295,7 @@ S32 LLTextureEntry::setColor(const LLColor3 &color)
 		mColor.setVec(color);
 		return TEM_CHANGE_COLOR;
 	}
-	return 0;
+	return TEM_CHANGE_NONE;
 }
 
 S32 LLTextureEntry::setAlpha(const F32 alpha)
@@ -261,7 +305,7 @@ S32 LLTextureEntry::setAlpha(const F32 alpha)
 		mColor.mV[VW] = alpha;
 		return TEM_CHANGE_COLOR;
 	}
-	return 0;
+	return TEM_CHANGE_NONE;
 }
 
 S32 LLTextureEntry::setOffset(F32 s, F32 t)
@@ -279,6 +323,28 @@ S32 LLTextureEntry::setOffset(F32 s, F32 t)
 	return retval;
 }
 
+S32 LLTextureEntry::setOffsetS(F32 s)
+{
+	S32 retval = 0;
+	if (mOffsetS != s)
+	{
+		mOffsetS = s;
+		retval = TEM_CHANGE_TEXTURE;
+	}
+	return retval;
+}
+
+S32 LLTextureEntry::setOffsetT(F32 t)
+{
+	S32 retval = 0;
+	if (mOffsetT != t)
+	{
+		mOffsetT = t;
+		retval = TEM_CHANGE_TEXTURE;
+	}
+	return retval;
+}
+
 S32 LLTextureEntry::setRotation(F32 theta)
 {
 	if (mRotation != theta)
@@ -286,7 +352,7 @@ S32 LLTextureEntry::setRotation(F32 theta)
 		mRotation = theta;
 		return TEM_CHANGE_TEXTURE;
 	}
-	return 0;
+	return TEM_CHANGE_NONE;
 }
 
 S32 LLTextureEntry::setBumpShinyFullbright(U8 bump)
@@ -296,7 +362,7 @@ S32 LLTextureEntry::setBumpShinyFullbright(U8 bump)
 		mBump = bump;
 		return TEM_CHANGE_TEXTURE;
 	}
-	return 0;
+	return TEM_CHANGE_NONE;
 }
 
 S32 LLTextureEntry::setMediaTexGen(U8 media)
@@ -306,7 +372,7 @@ S32 LLTextureEntry::setMediaTexGen(U8 media)
 		mMediaFlags = media;
 		return TEM_CHANGE_TEXTURE;
 	}
-	return 0;
+	return TEM_CHANGE_NONE;
 }
 
 S32 LLTextureEntry::setBumpmap(U8 bump)
@@ -318,7 +384,7 @@ S32 LLTextureEntry::setBumpmap(U8 bump)
 		mBump |= bump;
 		return TEM_CHANGE_TEXTURE;
 	}
-	return 0;
+	return TEM_CHANGE_NONE;
 }
 
 S32 LLTextureEntry::setFullbright(U8 fullbright)
@@ -330,7 +396,7 @@ S32 LLTextureEntry::setFullbright(U8 fullbright)
 		mBump |= fullbright << TEM_FULLBRIGHT_SHIFT;
 		return TEM_CHANGE_TEXTURE;
 	}
-	return 0;
+	return TEM_CHANGE_NONE;
 }
 
 S32 LLTextureEntry::setShiny(U8 shiny)
@@ -342,7 +408,7 @@ S32 LLTextureEntry::setShiny(U8 shiny)
 		mBump |= shiny << TEM_SHINY_SHIFT;
 		return TEM_CHANGE_TEXTURE;
 	}
-	return 0;
+	return TEM_CHANGE_NONE;
 }
 
 S32 LLTextureEntry::setBumpShiny(U8 bump_shiny)
@@ -354,7 +420,7 @@ S32 LLTextureEntry::setBumpShiny(U8 bump_shiny)
 		mBump |= bump_shiny;
 		return TEM_CHANGE_TEXTURE;
 	}
-	return 0;
+	return TEM_CHANGE_NONE;
 }
 
 S32 LLTextureEntry::setMediaFlags(U8 media_flags)
@@ -366,7 +432,7 @@ S32 LLTextureEntry::setMediaFlags(U8 media_flags)
 		mMediaFlags |= media_flags;
 		return TEM_CHANGE_TEXTURE;
 	}
-	return 0;
+	return TEM_CHANGE_NONE;
 }
 
 S32 LLTextureEntry::setTexGen(U8 tex_gen)
@@ -378,7 +444,7 @@ S32 LLTextureEntry::setTexGen(U8 tex_gen)
 		mMediaFlags |= tex_gen;
 		return TEM_CHANGE_TEXTURE;
 	}
-	return 0;
+	return TEM_CHANGE_NONE;
 }
 
 S32 LLTextureEntry::setGlow(F32 glow)
@@ -388,5 +454,5 @@ S32 LLTextureEntry::setGlow(F32 glow)
 		mGlow = glow;
 		return TEM_CHANGE_TEXTURE;
 	}
-	return 0;
+	return TEM_CHANGE_NONE;
 }
diff --git a/indra/llprimitive/lltextureentry.h b/indra/llprimitive/lltextureentry.h
index c562545fc4f..84870e93e6c 100644
--- a/indra/llprimitive/lltextureentry.h
+++ b/indra/llprimitive/lltextureentry.h
@@ -37,6 +37,7 @@
 #include "v4color.h"
 #include "llsd.h"
 
+const S32 TEM_CHANGE_NONE = 0x0;
 const S32 TEM_CHANGE_COLOR = 0x1;
 const S32 TEM_CHANGE_TEXTURE = 0x2;
 const S32 TEM_INVALID = 0x4;
@@ -68,6 +69,7 @@ const S32 TEM_TEX_GEN_SHIFT		= 1;
 class LLTextureEntry
 {
 public:	
+	static LLTextureEntry* newTextureEntry();
 
 	typedef enum e_texgen
 	{
@@ -82,15 +84,19 @@ class LLTextureEntry
 	LLTextureEntry(const LLTextureEntry &rhs);
 
 	LLTextureEntry &operator=(const LLTextureEntry &rhs);
-    ~LLTextureEntry();
+    virtual ~LLTextureEntry();
 
 	bool operator==(const LLTextureEntry &rhs) const;
 	bool operator!=(const LLTextureEntry &rhs) const;
 
 	LLSD asLLSD() const;
+	void asLLSD(LLSD& sd) const;
 	operator LLSD() const { return asLLSD(); }
 	bool fromLLSD(LLSD& sd);
 
+	virtual LLTextureEntry* newBlank() const;
+	virtual LLTextureEntry* newCopy() const;
+
 	void init(const LLUUID& tex_id, F32 scale_s, F32 scale_t, F32 offset_s, F32 offset_t, F32 rotation, U8 bump);
 
 	// These return a TEM_ flag from above to indicate if something changed.
@@ -99,7 +105,11 @@ class LLTextureEntry
 	S32  setColor(const LLColor3 &color);
 	S32  setAlpha(const F32 alpha);
 	S32  setScale(F32 s, F32 t);
+	S32  setScaleS(F32 s);
+	S32  setScaleT(F32 t);
 	S32  setOffset(F32 s, F32 t);
+	S32  setOffsetS(F32 s);
+	S32  setOffsetT(F32 t);
 	S32  setRotation(F32 theta);
 
 	S32  setBumpmap(U8 bump);
@@ -113,7 +123,7 @@ class LLTextureEntry
 	S32  setMediaTexGen(U8 media);
     S32  setGlow(F32 glow);
 	
-	const LLUUID &getID() const { return mID; }
+	virtual const LLUUID &getID() const { return mID; }
 	const LLColor4 &getColor() const { return mColor; }
 	void getScale(F32 *s, F32 *t) const { *s = mScaleS; *t = mScaleT; }
 	void getOffset(F32 *s, F32 *t) const { *s = mOffsetS; *t = mOffsetT; }
-- 
GitLab