diff --git a/indra/llcommon/llbase32.cpp b/indra/llcommon/llbase32.cpp
index 711ba63ea233b855e296dae3cfdcc2bcc7bf16f6..96e4d76f3b792d5954f11f77a75d2288cefd972b 100644
--- a/indra/llcommon/llbase32.cpp
+++ b/indra/llcommon/llbase32.cpp
@@ -6,6 +6,12 @@
  * Based on code from bitter
  * http://ghostwhitecrab.com/bitter/
  *
+ * Some parts of this file are:
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+/**
  * Copyright (c) 2006 Christian Biere <christianbiere@gmx.de>
  * All rights reserved.
  *
@@ -192,6 +198,8 @@ base32_decode(char *dst, size_t size, const void *data, size_t len)
 */
 
 
+// The following is
+// Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
 // static
 std::string LLBase32::encode(const U8* input, size_t input_size)
 {
@@ -207,8 +215,8 @@ std::string LLBase32::encode(const U8* input, size_t input_size)
 
 		size_t encoded = base32_encode(&output[0], output_size, input, input_size);
 
-		llinfos << "encoded " << encoded << " into buffer of size " << output_size
-			<< llendl;
+		llinfos << "encoded " << encoded << " into buffer of size "
+			<< output_size << llendl;
 	}
 	return output;
 }
diff --git a/indra/llcommon/llchat.h b/indra/llcommon/llchat.h
index 88867b2081e38466e01f64d89be25cc27cb742f0..61bdc819079aa66f675292f680f5e5c38041d7e1 100644
--- a/indra/llcommon/llchat.h
+++ b/indra/llcommon/llchat.h
@@ -29,7 +29,8 @@ typedef enum e_chat_type
 	CHAT_TYPE_SHOUT = 2,
 	CHAT_TYPE_START = 4,
 	CHAT_TYPE_STOP = 5,
-	CHAT_TYPE_DEBUG_MSG = 6
+	CHAT_TYPE_DEBUG_MSG = 6,
+	CHAT_TYPE_REGION = 7
 } EChatType;
 
 typedef enum e_chat_audible_level
diff --git a/indra/llcommon/lllslconstants.h b/indra/llcommon/lllslconstants.h
index bd14e8ce04d395693593a6d5e3edb9e853490430..87234a463cadc69d8e9651c8c1376a61711a4591 100644
--- a/indra/llcommon/lllslconstants.h
+++ b/indra/llcommon/lllslconstants.h
@@ -55,6 +55,7 @@ const S32 LSL_PRIM_TYPE_SPHERE	= 3;
 const S32 LSL_PRIM_TYPE_TORUS	= 4;
 const S32 LSL_PRIM_TYPE_TUBE	= 5;
 const S32 LSL_PRIM_TYPE_RING	= 6;
+const S32 LSL_PRIM_TYPE_SCULPT  = 7;
 
 const S32 LSL_PRIM_HOLE_DEFAULT = 0x00;
 const S32 LSL_PRIM_HOLE_CIRCLE	= 0x10;
@@ -97,6 +98,11 @@ const S32 LSL_PRIM_BUMP_STUCCO		= 15;
 const S32 LSL_PRIM_BUMP_SUCTION		= 16;
 const S32 LSL_PRIM_BUMP_WEAVE		= 17;
 
+const S32 LSL_PRIM_SCULPT_TYPE_SPHERE   = 1;
+const S32 LSL_PRIM_SCULPT_TYPE_TORUS    = 2;
+const S32 LSL_PRIM_SCULPT_TYPE_PLANE    = 3;
+const S32 LSL_PRIM_SCULPT_TYPE_CYLINDER = 4;
+
 const S32 LSL_ALL_SIDES				= -1;
 const S32 LSL_LINK_ROOT				= 1;
 const S32 LSL_LINK_FIRST_CHILD		= 2;
diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp
index 20d07064e391ba1596fdb050ef1f0d16636e4a89..c779a8b714671bbb4c9c173ef5c96a1a1c0bc36b 100644
--- a/indra/llmath/llvolume.cpp
+++ b/indra/llmath/llvolume.cpp
@@ -434,9 +434,18 @@ LLProfile::Face* LLProfile::addHole(BOOL flat, F32 sides, F32 offset, F32 box_ho
 	return face;
 }
 
-BOOL LLProfile::generate(BOOL path_open,F32 detail, S32 split)
+
+F32 next_power_of_two(F32 value)
 {
-	if (!mDirty)
+	S32 power = (S32)llceil((F32)log((double)value)/(F32)log(2.0));
+	return pow(2.0f, power);
+}
+
+
+
+BOOL LLProfile::generate(BOOL path_open,F32 detail, S32 split, BOOL is_sculpted)
+{
+	if ((!mDirty) && (!is_sculpted))
 	{
 		return FALSE;
 	}
@@ -572,10 +581,14 @@ BOOL LLProfile::generate(BOOL path_open,F32 detail, S32 split)
 					circle_detail = llceil(circle_detail / 4.0f) * 4.0f;
 				}
 			}
+
+			S32 sides = (S32)circle_detail;
+
+			if (is_sculpted)
+				sides = (S32)next_power_of_two((F32)sides);
+			
+			genNGon(sides);
 			
-			//llinfos << "(CIRCLE) detail: " << detail << "; genNGon(" 
-			//		<< llfloor(circle_detail) << ")" << llendl;
-			genNGon(llfloor(circle_detail));
 			if (path_open)
 			{
 				addCap (LL_FACE_PATH_BEGIN);
@@ -824,7 +837,7 @@ BOOL LLProfileParams::importLegacyStream(std::istream& input_stream)
 		}
 		else
 		{
-			llwarns << "unknown keyword " << keyword << " in profile import" << llendl;
+ 		llwarns << "unknown keyword " << keyword << " in profile import" << llendl;
 		}
 	}
 
@@ -1054,9 +1067,9 @@ const LLVector2 LLPathParams::getEndScale() const
 	return end_scale;
 }
 
-BOOL LLPath::generate(F32 detail, S32 split)
+BOOL LLPath::generate(F32 detail, S32 split, BOOL is_sculpted)
 {
-	if (!mDirty)
+	if ((!mDirty) && (!is_sculpted))
 	{
 		return FALSE;
 	}
@@ -1111,7 +1124,13 @@ BOOL LLPath::generate(F32 detail, S32 split)
 		{
 			// Increase the detail as the revolutions and twist increase.
 			F32 twist_mag = fabs(mParams.getTwistBegin() - mParams.getTwist());
-			genNGon(llfloor(llfloor((MIN_DETAIL_FACES * detail + twist_mag * 3.5f * (detail-0.5f))) * mParams.getRevolutions()));
+
+			S32 sides = (S32)llfloor(llfloor((MIN_DETAIL_FACES * detail + twist_mag * 3.5f * (detail-0.5f))) * mParams.getRevolutions());
+
+			if (is_sculpted)
+				sides = (S32)next_power_of_two((F32)sides);
+			
+			genNGon(sides);
 		}
 		break;
 
@@ -1174,7 +1193,7 @@ BOOL LLPath::generate(F32 detail, S32 split)
 	return TRUE;
 }
 
-BOOL LLDynamicPath::generate(F32 detail, S32 split)
+BOOL LLDynamicPath::generate(F32 detail, S32 split, BOOL is_sculpted)
 {
 	mOpen = TRUE; // Draw end caps
 	if (getPathLength() == 0)
@@ -1535,13 +1554,15 @@ LLProfile::~LLProfile()
 }
 
 
-S32 LLVolume::mNumMeshPoints = 0;
+S32 LLVolume::sNumMeshPoints = 0;
 
 LLVolume::LLVolume(const LLVolumeParams &params, const F32 detail, const BOOL generate_single_face, const BOOL is_unique) : mParams(params)
 {
 	mUnique = is_unique;
 	mFaceMask = 0x0;
 	mDetail = detail;
+	mSculptLevel = -2;
+	
 	// set defaults
 	if (mParams.getPathParams().getCurveType() == LL_PCODE_PATH_FLEXIBLE)
 	{
@@ -1558,7 +1579,10 @@ LLVolume::LLVolume(const LLVolumeParams &params, const F32 detail, const BOOL ge
 	mGenerateSingleFace = generate_single_face;
 
 	generate();
-	createVolumeFaces();
+	if (mParams.getSculptID().isNull())
+	{
+		createVolumeFaces();
+	}
 }
 
 void LLVolume::regen()
@@ -1569,7 +1593,7 @@ void LLVolume::regen()
 
 LLVolume::~LLVolume()
 {
-	mNumMeshPoints -= mMesh.size();
+	sNumMeshPoints -= mMesh.size();
 	delete mPathp;
 	delete mProfilep;
 	delete[] mVolumeFaces;
@@ -1620,9 +1644,9 @@ BOOL LLVolume::generate()
 
 	if (regenPath || regenProf ) 
 	{
-		mNumMeshPoints -= mMesh.size();
+		sNumMeshPoints -= mMesh.size();
 		mMesh.resize(mProfilep->mProfile.size() * mPathp->mPath.size());
-		mNumMeshPoints += mMesh.size();
+		sNumMeshPoints += mMesh.size();
 
 		S32 s = 0, t=0;
 		S32 sizeS = mPathp->mPath.size();
@@ -1752,6 +1776,128 @@ void LLVolume::createVolumeFaces()
 }
 
 
+// sculpt replaces generate() for sculpted surfaces
+void LLVolume::sculpt(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data, S32 sculpt_level)
+{
+	BOOL data_is_empty = FALSE;
+
+	if (sculpt_width == 0 || sculpt_height == 0 || sculpt_data == NULL)
+	{
+		sculpt_level = -1;
+		data_is_empty = TRUE;
+	}
+
+	mPathp->generate(mDetail, 0, TRUE);
+	mProfilep->generate(mPathp->isOpen(), mDetail, 0, TRUE);
+
+	
+	S32 sizeS = mPathp->mPath.size();
+	S32 sizeT = mProfilep->mProfile.size();
+
+	sNumMeshPoints -= mMesh.size();
+	mMesh.resize(sizeS * sizeT);
+	sNumMeshPoints += mMesh.size();
+
+	S32 vertex_change = 0;
+	// first test to see if image has enough variation to create geometry
+	if (!data_is_empty)
+	{
+		S32 last_index = 0;
+		for (S32 s = 0; s < sizeS; s++)
+			for (S32 t = 0; t < sizeT; t++)
+			{
+				U32 x = (U32) ((F32)s/(sizeS-1) * (F32) sculpt_width);
+				U32 y = (U32) ((F32)t/(sizeT-1) * (F32) sculpt_height);
+
+				if (y == sculpt_height)  // clamp to bottom row
+					y = sculpt_height - 1;
+
+				if (x == sculpt_width)   // stitch sides
+					x = 0;
+
+				if ((y == 0) || (y == sculpt_height-1))  // stitch top and bottom
+					x = sculpt_width / 2;
+
+				U32 index = (x + y * sculpt_width) * sculpt_components;
+
+				if (fabs((F32)(sculpt_data[index] - sculpt_data[last_index])) +
+					fabs((F32)(sculpt_data[index+1] - sculpt_data[last_index+1])) +
+					fabs((F32)(sculpt_data[index+2] - sculpt_data[last_index+2])) > 256 * 0.02)
+					vertex_change++;
+
+				last_index = index;
+			}
+	}
+
+	
+	if ((F32)vertex_change / sizeS / sizeT < 0.05) // less than 5%
+		data_is_empty = TRUE;
+	
+	
+	//generate vertex positions
+	// Run along the path.
+	S32 s = 0, t = 0;
+	S32 line = 0;
+	while (s < sizeS)
+	{
+		t = 0;
+		// Run along the profile.
+		while (t < sizeT)
+		{
+			S32 i = t + line;
+			Point& pt = mMesh[i];
+
+			U32 x = (U32) ((F32)t/(sizeT-1) * (F32) sculpt_width);
+			U32 y = (U32) ((F32)s/(sizeS-1) * (F32) sculpt_height);
+
+			if (y == sculpt_height)  // clamp to bottom row
+				y = sculpt_height - 1;
+
+			if (x == sculpt_width)   // stitch sides
+				x = 0;
+
+			if ((y == 0) || (y == sculpt_height-1))  // stitch top and bottom
+				x = sculpt_width / 2;
+			
+
+			if (data_is_empty) // if empty, make a sphere
+			{
+				F32 u = (F32)s/(sizeS-1);
+				F32 v = (F32)t/(sizeT-1);
+
+				const F32 RADIUS = (F32) 0.3;
+				
+				pt.mPos.mV[0] = (F32)(sin(F_PI * v) * cos(2.0 * F_PI * u) * RADIUS);
+				pt.mPos.mV[1] = (F32)(sin(F_PI * v) * sin(2.0 * F_PI * u) * RADIUS);
+				pt.mPos.mV[2] = (F32)(cos(F_PI * v) * RADIUS);
+			}
+			
+			else
+			{
+				U32 index = (x + y * sculpt_width) * sculpt_components;
+				pt.mPos.mV[0] = sculpt_data[index  ] / 256.f - 0.5f;
+				pt.mPos.mV[1] = sculpt_data[index+1] / 256.f - 0.5f;
+				pt.mPos.mV[2] = sculpt_data[index+2] / 256.f - 0.5f;
+			}
+
+			t++;
+		}
+		line += sizeT;
+		s++;
+	}
+
+	for (S32 i = 0; i < (S32)mProfilep->mFaces.size(); i++)
+	{
+		mFaceMask |= mProfilep->mFaces[i].mFaceID;
+	}
+
+	mSculptLevel = sculpt_level;
+	createVolumeFaces();
+}
+
+
+
+
 BOOL LLVolume::isCap(S32 face)
 {
 	return mProfilep->mFaces[face].mCap; 
@@ -1765,14 +1911,18 @@ BOOL LLVolume::isFlat(S32 face)
 
 bool LLVolumeParams::operator==(const LLVolumeParams &params) const
 {
-	return (getPathParams() == params.getPathParams()) &&
-		(getProfileParams() == params.getProfileParams());
+	return ( (getPathParams() == params.getPathParams()) &&
+			 (getProfileParams() == params.getProfileParams()) &&
+			 (mSculptID == params.mSculptID) &&
+			 (mSculptType == params.mSculptType) );
 }
 
 bool LLVolumeParams::operator!=(const LLVolumeParams &params) const
 {
-	return (getPathParams() != params.getPathParams()) ||
-		(getProfileParams() != params.getProfileParams());
+	return ( (getPathParams() != params.getPathParams()) ||
+			 (getProfileParams() != params.getProfileParams()) ||
+			 (mSculptID != params.mSculptID) ||
+			 (mSculptType != params.mSculptType) );
 }
 
 bool LLVolumeParams::operator<(const LLVolumeParams &params) const
@@ -1781,16 +1931,29 @@ bool LLVolumeParams::operator<(const LLVolumeParams &params) const
 	{
 		return getPathParams() < params.getPathParams();
 	}
-	else
+	
+	if (getProfileParams() != params.getProfileParams())
 	{
 		return getProfileParams() < params.getProfileParams();
 	}
+	
+	if (mSculptID != params.mSculptID)
+	{
+		return mSculptID < params.mSculptID;
+	}
+
+
+	return mSculptType < params.mSculptType;
+
+
 }
 
 void LLVolumeParams::copyParams(const LLVolumeParams &params)
 {
 	mProfileParams.copyParams(params.mProfileParams);
 	mPathParams.copyParams(params.mPathParams);
+	mSculptID = params.getSculptID();
+	mSculptType = params.getSculptType();
 }
 
 // Less restricitve approx 0 for volumes
@@ -2050,6 +2213,13 @@ bool LLVolumeParams::setSkew(const F32 skew_value)
 	return valid;
 }
 
+bool LLVolumeParams::setSculptID(const LLUUID sculpt_id, U8 sculpt_type)
+{
+	mSculptID = sculpt_id;
+	mSculptType = sculpt_type;
+	return true;
+}
+
 bool LLVolumeParams::setType(U8 profile, U8 path)
 {
 	bool result = true;
@@ -2809,7 +2979,7 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices,
 	segments.clear();
 
 	//for each face
-	for (S32 i = 0; i < getNumFaces(); i++) {
+	for (S32 i = 0; i < getNumVolumeFaces(); i++) {
 		LLVolumeFace face = this->getVolumeFace(i);
 	
 		if (face.mTypeMask & (LLVolumeFace::CAP_MASK)) {
@@ -4416,6 +4586,9 @@ BOOL LLVolumeFace::createSide()
 		}
 	}
 
+	BOOL s_bottom_converges = ((mVertices[0].mPosition - mVertices[mNumS*(mNumT-2)].mPosition).magVecSquared() < 0.000001f);
+	BOOL s_top_converges = ((mVertices[mNumS-1].mPosition - mVertices[mNumS*(mNumT-2)+mNumS-1].mPosition).magVecSquared() < 0.000001f);
+	
 	if (mVolumep->getPath().isOpen() == FALSE) { //wrap normals on T
 		for (S32 i = 0; i < mNumS; i++) {
 			LLVector3 norm = mVertices[i].mNormal + mVertices[mNumS*(mNumT-1)+i].mNormal;
@@ -4424,30 +4597,73 @@ BOOL LLVolumeFace::createSide()
 		}
 	}
 
-	if (mVolumep->getProfile().isOpen() == FALSE) { //wrap normals on S
-		for (S32 i = 0; i < mNumT; i++) {
-			LLVector3 norm = mVertices[mNumS*i].mNormal + mVertices[mNumS*i+mNumS-1].mNormal;
-			mVertices[mNumS * i].mNormal = norm;
-			mVertices[mNumS * i+mNumS-1].mNormal = norm;
+	if ((mVolumep->getProfile().isOpen() == FALSE) &&
+		!(s_bottom_converges))
+		{ //wrap normals on S
+			for (S32 i = 0; i < mNumT; i++) {
+				LLVector3 norm = mVertices[mNumS*i].mNormal + mVertices[mNumS*i+mNumS-1].mNormal;
+				mVertices[mNumS * i].mNormal = norm;
+				mVertices[mNumS * i+mNumS-1].mNormal = norm;
+			}
 		}
-	}
 	
-	if (mVolumep->getPathType() == LL_PCODE_PATH_CIRCLE && ((mVolumep->getProfileType() & LL_PCODE_PROFILE_MASK) == LL_PCODE_PROFILE_CIRCLE_HALF)) {
-		if ((mVertices[0].mPosition - mVertices[mNumS*(mNumT-2)].mPosition).magVecSquared() < 0.000001f) 
+	if (mVolumep->getPathType() == LL_PCODE_PATH_CIRCLE &&
+		((mVolumep->getProfileType() & LL_PCODE_PROFILE_MASK) == LL_PCODE_PROFILE_CIRCLE_HALF))
+	{
+		if (s_bottom_converges)
 		{ //all lower S have same normal
 			for (S32 i = 0; i < mNumT; i++) {
 				mVertices[mNumS*i].mNormal = LLVector3(1,0,0);
 			}
 		}
 
-		if ((mVertices[mNumS-1].mPosition - mVertices[mNumS*(mNumT-2)+mNumS-1].mPosition).magVecSquared() < 0.000001f) 
-		{ //all upper T have same normal
+		if (s_top_converges)
+		{ //all upper S have same normal
 			for (S32 i = 0; i < mNumT; i++) {
 				mVertices[mNumS*i+mNumS-1].mNormal = LLVector3(-1,0,0);
 			}
 		}
 	}
 
+	U8 sculpt_type = mVolumep->getParams().getSculptType();
+	
+	if (sculpt_type == LL_SCULPT_TYPE_SPHERE)
+	{
+		// average normals for north pole
+		
+		LLVector3 average(0.0, 0.0, 0.0);
+		for (S32 i = 0; i < mNumS; i++)
+		{
+			average += mVertices[i].mNormal;
+		}
+
+		// set average
+		for (S32 i = 0; i < mNumS; i++)
+		{
+			mVertices[i].mNormal = average;
+		}
+	}
+
+	
+	if (sculpt_type == LL_SCULPT_TYPE_SPHERE)
+	{
+		// average normals for south pole
+		
+		LLVector3 average(0.0, 0.0, 0.0);
+		for (S32 i = 0; i < mNumS; i++)
+		{
+			average += mVertices[i + mNumS * (mNumT - 1)].mNormal;
+		}
+
+		// set average
+		for (S32 i = 0; i < mNumS; i++)
+		{
+			mVertices[i + mNumS * (mNumT - 1)].mNormal = average;
+		}
+	}
+
+
+
 	//normalize normals and binormals here so the meshes that reference
 	//this volume data don't have to
 	for (U32 i = 0; i < mVertices.size(); i++) 
diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h
index 22742e09da664046024548fa41961bfd99a02c26..3ce3058887b4bcb6c42ab41199b93b00718e45d9 100644
--- a/indra/llmath/llvolume.h
+++ b/indra/llmath/llvolume.h
@@ -149,6 +149,16 @@ const LLFaceID	LL_FACE_OUTER_SIDE_3	= 0x1 << 8;
 
 //============================================================================
 
+// sculpt types
+
+const U8 LL_SCULPT_TYPE_NONE      = 0;
+const U8 LL_SCULPT_TYPE_SPHERE    = 1;
+const U8 LL_SCULPT_TYPE_TORUS     = 2;
+const U8 LL_SCULPT_TYPE_PLAIN     = 3;
+const U8 LL_SCULPT_TYPE_CYLINDER  = 4;
+
+
+
 class LLProfileParams
 {
 public:
@@ -492,8 +502,9 @@ class LLVolumeParams
 	{
 	}
 
-	LLVolumeParams(LLProfileParams &profile, LLPathParams &path)
-		: mProfileParams(profile), mPathParams(path)
+	LLVolumeParams(LLProfileParams &profile, LLPathParams &path,
+				   LLUUID sculpt_id = LLUUID::null, U8 sculpt_type = LL_SCULPT_TYPE_NONE)
+		: mProfileParams(profile), mPathParams(path), mSculptID(sculpt_id), mSculptType(sculpt_type)
 	{
 	}
 
@@ -544,6 +555,7 @@ class LLVolumeParams
 	bool setRevolutions(const F32 revolutions);	// 1 to 4
 	bool setRadiusOffset(const F32 radius_offset);
 	bool setSkew(const F32 skew);
+	bool setSculptID(const LLUUID sculpt_id, U8 sculpt_type);
 
 	static bool validate(U8 prof_curve, F32 prof_begin, F32 prof_end, F32 hollow,
 		U8 path_curve, F32 path_begin, F32 path_end,
@@ -571,6 +583,8 @@ class LLVolumeParams
 	const F32&  getTaperY() const		{ return mPathParams.getTaperY();		}
 	const F32&  getRevolutions() const	{ return mPathParams.getRevolutions();	}
 	const F32&  getSkew() const			{ return mPathParams.getSkew();			}
+	const LLUUID& getSculptID() const	{ return mSculptID;						}
+	const U8& getSculptType() const     { return mSculptType;                   }
 
 	BOOL isConvex() const;
 
@@ -593,6 +607,8 @@ class LLVolumeParams
 protected:
 	LLProfileParams mProfileParams;
 	LLPathParams	mPathParams;
+	LLUUID mSculptID;
+	U8 mSculptType;
 };
 
 
@@ -615,7 +631,7 @@ class LLProfile
 	BOOL isFlat(S32 face) const							{ return (mFaces[face].mCount == 2); }
 	BOOL isOpen() const									{ return mOpen; }
 	void setDirty()										{ mDirty     = TRUE; }
-	BOOL generate(BOOL path_open, F32 detail = 1.0f, S32 split = 0);
+	BOOL generate(BOOL path_open, F32 detail = 1.0f, S32 split = 0, BOOL is_sculpted = FALSE);
 	BOOL isConcave() const								{ return mConcave; }
 public:
 	const LLProfileParams &mParams;
@@ -684,7 +700,7 @@ class LLPath
 	virtual ~LLPath();
 
 	void genNGon(S32 sides, F32 offset=0.0f, F32 end_scale = 1.f, F32 twist_scale = 1.f);
-	virtual BOOL generate(F32 detail=1.0f, S32 split = 0);
+	virtual BOOL generate(F32 detail=1.0f, S32 split = 0, BOOL is_sculpted = FALSE);
 
 	BOOL isOpen() const						{ return mOpen; }
 	F32 getStep() const						{ return mStep; }
@@ -711,7 +727,7 @@ class LLDynamicPath : public LLPath
 {
 public:
 	LLDynamicPath(const LLPathParams &params) : LLPath(params) { }
-	BOOL generate(F32 detail=1.0f, S32 split = 0);
+	BOOL generate(F32 detail=1.0f, S32 split = 0, BOOL is_sculpted = FALSE);
 };
 
 // Yet another "face" class - caches volume-specific, but not instance-specific data for faces)
@@ -801,7 +817,7 @@ class LLVolume : public LLRefCount
 	U8 getProfileType()	const								{ return mProfilep->mParams.getCurveType(); }
 	U8 getPathType() const									{ return mPathp->mParams.getCurveType(); }
 	S32	getNumFaces() const									{ return (S32)mProfilep->mFaces.size(); }
-
+	S32 getNumVolumeFaces() const							{ return mNumVolumeFaces; }
 	const F32 getDetail() const								{ return mDetail; }
 	const LLVolumeParams & getParams() const				{ return mParams; }
 	LLVolumeParams getCopyOfParams() const					{ return mParams; }
@@ -819,6 +835,11 @@ class LLVolume : public LLRefCount
 	BOOL isFlat(S32 face);
 	BOOL isUnique() const									{ return mUnique; }
 
+	S32 getSculptLevel() const                              { return mSculptLevel; }
+	void setSculptLevel(S32 level)                          { mSculptLevel = level; }
+
+	U8 getSculptType() const                                { return mSculptType; }
+	
 	S32 *getTriangleIndices(U32 &num_indices) const;
 	void generateSilhouetteVertices(std::vector<LLVector3> &vertices, std::vector<LLVector3> &normals, std::vector<S32> &segments, const LLVector3& view_vec,
 											  const LLMatrix4& mat,
@@ -843,7 +864,7 @@ class LLVolume : public LLRefCount
 	LLFaceID generateFaceMask();
 
 	BOOL isFaceMaskValid(LLFaceID face_mask);
-	static S32 mNumMeshPoints;
+	static S32 sNumMeshPoints;
 
 	friend std::ostream& operator<<(std::ostream &s, const LLVolume &volume);
 	friend std::ostream& operator<<(std::ostream &s, const LLVolume *volumep);		// HACK to bypass Windoze confusion over 
@@ -852,14 +873,19 @@ class LLVolume : public LLRefCount
 
 	U32					mFaceMask;			// bit array of which faces exist in this volume
 	LLVector3			mLODScaleBias;		// vector for biasing LOD based on scale
-
+	
+	void sculpt(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data, S32 sculpt_level);
+	
 protected:
 	BOOL generate();
 	void createVolumeFaces();
 
-protected:
+ protected:
 	BOOL mUnique;
 	F32 mDetail;
+	S32 mSculptLevel;
+	U8  mSculptType;
+	
 	LLVolumeParams mParams;
 	LLPath *mPathp;
 	LLProfile *mProfilep;
diff --git a/indra/llmessage/message_prehash.cpp b/indra/llmessage/message_prehash.cpp
index 9d7e60369015005eb2059186e8209f090a8209d3..e153114d1d9b5875bb76de8e9dbe5a975f09a06d 100644
--- a/indra/llmessage/message_prehash.cpp
+++ b/indra/llmessage/message_prehash.cpp
@@ -534,8 +534,8 @@ char * _PREHASH_ReturnIDs;
 char * _PREHASH_Date;
 char * _PREHASH_AgentWearablesUpdate;
 char * _PREHASH_AgentDataUpdate;
-char * _PREHASH_Hash;
 char * _PREHASH_GroupDataUpdate;
+char * _PREHASH_Hash;
 char * _PREHASH_AgentGroupDataUpdate;
 char * _PREHASH_Left;
 char * _PREHASH_Mask;
@@ -663,7 +663,6 @@ char * _PREHASH_CreateNewOutfitAttachments;
 char * _PREHASH_RegionHandle;
 char * _PREHASH_TeleportProgress;
 char * _PREHASH_AgentQuitCopy;
-char * _PREHASH_ToViewer;
 char * _PREHASH_AvatarInterestsUpdate;
 char * _PREHASH_GroupNoticeID;
 char * _PREHASH_ParcelName;
@@ -722,6 +721,7 @@ char * _PREHASH_LogoutReply;
 char * _PREHASH_FeatureDisabled;
 char * _PREHASH_ObjectLocalID;
 char * _PREHASH_Dropped;
+char * _PREHASH_PhysicalAvatarEventList;
 char * _PREHASH_WebProfilesDisabled;
 char * _PREHASH_Destination;
 char * _PREHASH_MasterID;
@@ -995,7 +995,6 @@ char * _PREHASH_TrackAgentSession;
 char * _PREHASH_CacheMissType;
 char * _PREHASH_VFileID;
 char * _PREHASH_GroupInsigniaID;
-char * _PREHASH_FromID;
 char * _PREHASH_Online;
 char * _PREHASH_KickFlags;
 char * _PREHASH_CovenantID;
@@ -1179,7 +1178,6 @@ char * _PREHASH_EventData;
 char * _PREHASH_Final;
 char * _PREHASH_TelehubPos;
 char * _PREHASH_ReportAutosaveCrash;
-char * _PREHASH_Reset;
 char * _PREHASH_CreateTrustedCircuit;
 char * _PREHASH_DenyTrustedCircuit;
 char * _PREHASH_RequestTrustedCircuit;
@@ -1362,7 +1360,6 @@ char * _PREHASH_SimulatorPublicHostBlock;
 char * _PREHASH_HeaderData;
 char * _PREHASH_RequestMultipleObjects;
 char * _PREHASH_RetrieveInstantMessages;
-char * _PREHASH_DequeueInstantMessages;
 char * _PREHASH_OpenCircuit;
 char * _PREHASH_SecureSessionID;
 char * _PREHASH_CrossedRegion;
@@ -2000,8 +1997,8 @@ void init_prehash_data()
 	_PREHASH_Date = gMessageStringTable.getString("Date");
 	_PREHASH_AgentWearablesUpdate = gMessageStringTable.getString("AgentWearablesUpdate");
 	_PREHASH_AgentDataUpdate = gMessageStringTable.getString("AgentDataUpdate");
-	_PREHASH_Hash = gMessageStringTable.getString("Hash");
 	_PREHASH_GroupDataUpdate = gMessageStringTable.getString("GroupDataUpdate");
+	_PREHASH_Hash = gMessageStringTable.getString("Hash");
 	_PREHASH_AgentGroupDataUpdate = gMessageStringTable.getString("AgentGroupDataUpdate");
 	_PREHASH_Left = gMessageStringTable.getString("Left");
 	_PREHASH_Mask = gMessageStringTable.getString("Mask");
@@ -2129,7 +2126,6 @@ void init_prehash_data()
 	_PREHASH_RegionHandle = gMessageStringTable.getString("RegionHandle");
 	_PREHASH_TeleportProgress = gMessageStringTable.getString("TeleportProgress");
 	_PREHASH_AgentQuitCopy = gMessageStringTable.getString("AgentQuitCopy");
-	_PREHASH_ToViewer = gMessageStringTable.getString("ToViewer");
 	_PREHASH_AvatarInterestsUpdate = gMessageStringTable.getString("AvatarInterestsUpdate");
 	_PREHASH_GroupNoticeID = gMessageStringTable.getString("GroupNoticeID");
 	_PREHASH_ParcelName = gMessageStringTable.getString("ParcelName");
@@ -2188,6 +2184,7 @@ void init_prehash_data()
 	_PREHASH_FeatureDisabled = gMessageStringTable.getString("FeatureDisabled");
 	_PREHASH_ObjectLocalID = gMessageStringTable.getString("ObjectLocalID");
 	_PREHASH_Dropped = gMessageStringTable.getString("Dropped");
+	_PREHASH_PhysicalAvatarEventList = gMessageStringTable.getString("PhysicalAvatarEventList");
 	_PREHASH_WebProfilesDisabled = gMessageStringTable.getString("WebProfilesDisabled");
 	_PREHASH_Destination = gMessageStringTable.getString("Destination");
 	_PREHASH_MasterID = gMessageStringTable.getString("MasterID");
@@ -2461,7 +2458,6 @@ void init_prehash_data()
 	_PREHASH_CacheMissType = gMessageStringTable.getString("CacheMissType");
 	_PREHASH_VFileID = gMessageStringTable.getString("VFileID");
 	_PREHASH_GroupInsigniaID = gMessageStringTable.getString("GroupInsigniaID");
-	_PREHASH_FromID = gMessageStringTable.getString("FromID");
 	_PREHASH_Online = gMessageStringTable.getString("Online");
 	_PREHASH_KickFlags = gMessageStringTable.getString("KickFlags");
 	_PREHASH_CovenantID = gMessageStringTable.getString("CovenantID");
@@ -2645,7 +2641,6 @@ void init_prehash_data()
 	_PREHASH_Final = gMessageStringTable.getString("Final");
 	_PREHASH_TelehubPos = gMessageStringTable.getString("TelehubPos");
 	_PREHASH_ReportAutosaveCrash = gMessageStringTable.getString("ReportAutosaveCrash");
-	_PREHASH_Reset = gMessageStringTable.getString("Reset");
 	_PREHASH_CreateTrustedCircuit = gMessageStringTable.getString("CreateTrustedCircuit");
 	_PREHASH_DenyTrustedCircuit = gMessageStringTable.getString("DenyTrustedCircuit");
 	_PREHASH_RequestTrustedCircuit = gMessageStringTable.getString("RequestTrustedCircuit");
@@ -2828,7 +2823,6 @@ void init_prehash_data()
 	_PREHASH_HeaderData = gMessageStringTable.getString("HeaderData");
 	_PREHASH_RequestMultipleObjects = gMessageStringTable.getString("RequestMultipleObjects");
 	_PREHASH_RetrieveInstantMessages = gMessageStringTable.getString("RetrieveInstantMessages");
-	_PREHASH_DequeueInstantMessages = gMessageStringTable.getString("DequeueInstantMessages");
 	_PREHASH_OpenCircuit = gMessageStringTable.getString("OpenCircuit");
 	_PREHASH_SecureSessionID = gMessageStringTable.getString("SecureSessionID");
 	_PREHASH_CrossedRegion = gMessageStringTable.getString("CrossedRegion");
diff --git a/indra/llmessage/message_prehash.h b/indra/llmessage/message_prehash.h
index 19b9881ddeff58e5cf146e430eec9d05c03d502e..209b399ce8710bed0a8a86ceb38b1790b308fbc5 100644
--- a/indra/llmessage/message_prehash.h
+++ b/indra/llmessage/message_prehash.h
@@ -534,8 +534,8 @@ extern char * _PREHASH_ReturnIDs;
 extern char * _PREHASH_Date;
 extern char * _PREHASH_AgentWearablesUpdate;
 extern char * _PREHASH_AgentDataUpdate;
-extern char * _PREHASH_Hash;
 extern char * _PREHASH_GroupDataUpdate;
+extern char * _PREHASH_Hash;
 extern char * _PREHASH_AgentGroupDataUpdate;
 extern char * _PREHASH_Left;
 extern char * _PREHASH_Mask;
@@ -663,7 +663,6 @@ extern char * _PREHASH_CreateNewOutfitAttachments;
 extern char * _PREHASH_RegionHandle;
 extern char * _PREHASH_TeleportProgress;
 extern char * _PREHASH_AgentQuitCopy;
-extern char * _PREHASH_ToViewer;
 extern char * _PREHASH_AvatarInterestsUpdate;
 extern char * _PREHASH_GroupNoticeID;
 extern char * _PREHASH_ParcelName;
@@ -722,6 +721,7 @@ extern char * _PREHASH_LogoutReply;
 extern char * _PREHASH_FeatureDisabled;
 extern char * _PREHASH_ObjectLocalID;
 extern char * _PREHASH_Dropped;
+extern char * _PREHASH_PhysicalAvatarEventList;
 extern char * _PREHASH_WebProfilesDisabled;
 extern char * _PREHASH_Destination;
 extern char * _PREHASH_MasterID;
@@ -995,7 +995,6 @@ extern char * _PREHASH_TrackAgentSession;
 extern char * _PREHASH_CacheMissType;
 extern char * _PREHASH_VFileID;
 extern char * _PREHASH_GroupInsigniaID;
-extern char * _PREHASH_FromID;
 extern char * _PREHASH_Online;
 extern char * _PREHASH_KickFlags;
 extern char * _PREHASH_CovenantID;
@@ -1179,7 +1178,6 @@ extern char * _PREHASH_EventData;
 extern char * _PREHASH_Final;
 extern char * _PREHASH_TelehubPos;
 extern char * _PREHASH_ReportAutosaveCrash;
-extern char * _PREHASH_Reset;
 extern char * _PREHASH_CreateTrustedCircuit;
 extern char * _PREHASH_DenyTrustedCircuit;
 extern char * _PREHASH_RequestTrustedCircuit;
@@ -1362,7 +1360,6 @@ extern char * _PREHASH_SimulatorPublicHostBlock;
 extern char * _PREHASH_HeaderData;
 extern char * _PREHASH_RequestMultipleObjects;
 extern char * _PREHASH_RetrieveInstantMessages;
-extern char * _PREHASH_DequeueInstantMessages;
 extern char * _PREHASH_OpenCircuit;
 extern char * _PREHASH_SecureSessionID;
 extern char * _PREHASH_CrossedRegion;
diff --git a/indra/llprimitive/llprimitive.cpp b/indra/llprimitive/llprimitive.cpp
index 13719d0a6237b86e6a7ca70a72ad6e88260a0fc2..7e44d15db228c7911b1e454f8f5a91218a0f52eb 100644
--- a/indra/llprimitive/llprimitive.cpp
+++ b/indra/llprimitive/llprimitive.cpp
@@ -87,6 +87,9 @@ const BOOL FLEXIBLE_OBJECT_DEFAULT_USING_COLLISION_SPHERE = FALSE;
 const BOOL FLEXIBLE_OBJECT_DEFAULT_RENDERING_COLLISION_SPHERE = FALSE;
 
 
+const char *SCULPT_DEFAULT_TEXTURE = "be293869-d0d9-0a69-5989-ad27f1946fd4"; // old inverted texture: "7595d345-a24c-e7ef-f0bd-78793792133e";
+
+
 //===============================================================
 LLPrimitive::LLPrimitive()
 {
@@ -491,6 +494,18 @@ S32  LLPrimitive::setTEMediaFlags(const U8 te, const U8 media_flags)
 	return mTextureList[te].setMediaFlags( media_flags );
 }
 
+S32 LLPrimitive::setTEGlow(const U8 te, 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 );
+}
+
 
 LLPCode LLPrimitive::legacyToPCode(const U8 legacy)
 {
@@ -1272,7 +1287,8 @@ BOOL LLPrimitive::packTEMessage(LLMessageSystem *mesgsys) const
 	S16    image_rot[MAX_TES];
 	U8	   bump[MAX_TES];
 	U8	   media_flags[MAX_TES];
-
+    U8     glow[MAX_TES];
+	
 	const U32 MAX_TE_BUFFER = 4096;
 	U8 packed_buffer[MAX_TE_BUFFER];
 	U8 *cur_ptr = packed_buffer;
@@ -1308,7 +1324,7 @@ BOOL LLPrimitive::packTEMessage(LLMessageSystem *mesgsys) const
 			image_rot[face_index] = (S16) llround(((fmod(te->mRotation, F_TWO_PI)/F_TWO_PI) * (F32)0x7FFF));
 			bump[face_index] = te->getBumpShinyFullbright();
 			media_flags[face_index] = te->getMediaTexGen();
-//			llinfos << "BUMP pack [" << (S32)face_index << "]=" << (S32) bump[face_index] << llendl;
+			glow[face_index] = (U8) llround((llclamp(te->getGlow(), 0.0f, 1.0f) * (F32)0xFF));
 		}
 
 		cur_ptr += packTEField(cur_ptr, (U8 *)image_ids, sizeof(LLUUID),last_face_index, MVT_LLUUID);
@@ -1328,6 +1344,8 @@ BOOL LLPrimitive::packTEMessage(LLMessageSystem *mesgsys) const
 		cur_ptr += packTEField(cur_ptr, (U8 *)bump, 1 ,last_face_index, MVT_U8);
 		*cur_ptr++ = 0;
 		cur_ptr += packTEField(cur_ptr, (U8 *)media_flags, 1 ,last_face_index, MVT_U8);
+		*cur_ptr++ = 0;
+		cur_ptr += packTEField(cur_ptr, (U8 *)glow, 1 ,last_face_index, MVT_U8);
 	}
    	mesgsys->addBinaryDataFast(_PREHASH_TextureEntry, packed_buffer, (S32)(cur_ptr - packed_buffer));
 
@@ -1348,7 +1366,8 @@ BOOL LLPrimitive::packTEMessage(LLDataPacker &dp) const
 	S16    image_rot[MAX_TES];
 	U8	   bump[MAX_TES];
 	U8	   media_flags[MAX_TES];
-
+    U8     glow[MAX_TES];
+	
 	const U32 MAX_TE_BUFFER = 4096;
 	U8 packed_buffer[MAX_TE_BUFFER];
 	U8 *cur_ptr = packed_buffer;
@@ -1384,8 +1403,7 @@ BOOL LLPrimitive::packTEMessage(LLDataPacker &dp) const
 			image_rot[face_index] = (S16) llround(((fmod(te->mRotation, F_TWO_PI)/F_TWO_PI) * (F32)0x7FFF));
 			bump[face_index] = te->getBumpShinyFullbright();
 			media_flags[face_index] = te->getMediaTexGen();
-
-//			llinfos << "BUMP pack   (Datapacker) [" << (S32)face_index << "]=" << (S32) bump[face_index] << llendl;
+            glow[face_index] = (U8) llround((llclamp(te->getGlow(), 0.0f, 1.0f) * (F32)0xFF));
 		}
 
 		cur_ptr += packTEField(cur_ptr, (U8 *)image_ids, sizeof(LLUUID),last_face_index, MVT_LLUUID);
@@ -1405,6 +1423,8 @@ BOOL LLPrimitive::packTEMessage(LLDataPacker &dp) const
 		cur_ptr += packTEField(cur_ptr, (U8 *)bump, 1 ,last_face_index, MVT_U8);
 		*cur_ptr++ = 0;
 		cur_ptr += packTEField(cur_ptr, (U8 *)media_flags, 1 ,last_face_index, MVT_U8);
+		*cur_ptr++ = 0;
+		cur_ptr += packTEField(cur_ptr, (U8 *)glow, 1 ,last_face_index, MVT_U8);
 	}
 
 	dp.packBinaryData(packed_buffer, (S32)(cur_ptr - packed_buffer), "TextureEntry");
@@ -1433,7 +1453,8 @@ S32 LLPrimitive::unpackTEMessage(LLMessageSystem *mesgsys, char *block_name, con
 	S16    image_rot[MAX_TES];
 	U8	   bump[MAX_TES];
 	U8	   media_flags[MAX_TES];
-
+    U8     glow[MAX_TES];
+	
 	const U32 MAX_TE_BUFFER = 4096;
 	U8 packed_buffer[MAX_TE_BUFFER];
 	U8 *cur_ptr = packed_buffer;
@@ -1483,7 +1504,9 @@ S32 LLPrimitive::unpackTEMessage(LLMessageSystem *mesgsys, char *block_name, con
 	cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)bump, 1, face_count, MVT_U8);
 	cur_ptr++;
 	cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)media_flags, 1, face_count, MVT_U8);
-
+	cur_ptr++;
+	cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)glow, 1, face_count, MVT_U8);
+	
 	LLColor4 color;
 	LLColor4U coloru;
 	for (U32 i = 0; i < face_count; i++)
@@ -1494,6 +1517,7 @@ S32 LLPrimitive::unpackTEMessage(LLMessageSystem *mesgsys, char *block_name, con
 		retval |= setTERotation(i, ((F32)image_rot[i]/ (F32)0x7FFF) * F_TWO_PI);
 		retval |= setTEBumpShinyFullbright(i, bump[i]);
 		retval |= setTEMediaTexGen(i, media_flags[i]);
+		retval |= setTEGlow(i, (F32)glow[i] / (F32)0xFF);
 		coloru = LLColor4U(colors + 4*i);
 
 		// Note:  This is an optimization to send common colors (1.f, 1.f, 1.f, 1.f)
@@ -1528,6 +1552,7 @@ S32 LLPrimitive::unpackTEMessage(LLDataPacker &dp)
 	S16    image_rot[MAX_TES];
 	U8	   bump[MAX_TES];
 	U8	   media_flags[MAX_TES];
+    U8     glow[MAX_TES];
 
 	const U32 MAX_TE_BUFFER = 4096;
 	U8 packed_buffer[MAX_TE_BUFFER];
@@ -1568,10 +1593,11 @@ S32 LLPrimitive::unpackTEMessage(LLDataPacker &dp)
 	cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)bump, 1, face_count, MVT_U8);
 	cur_ptr++;
 	cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)media_flags, 1, face_count, MVT_U8);
+	cur_ptr++;
+	cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)glow, 1, face_count, MVT_U8);
 
 	for (i = 0; i < face_count; i++)
 	{
-//		llinfos << "BUMP unpack (Datapacker) [" << i << "]=" << S32(bump[i]) <<llendl;
 		memcpy(image_ids[i].mData,&image_data[i*16],16);	/* Flawfinder: ignore */ 	
 	}
 	
@@ -1585,6 +1611,7 @@ S32 LLPrimitive::unpackTEMessage(LLDataPacker &dp)
 		retval |= setTERotation(i, ((F32)image_rot[i]/ (F32)0x7FFF) * F_TWO_PI);
 		retval |= setTEBumpShinyFullbright(i, bump[i]);
 		retval |= setTEMediaTexGen(i, media_flags[i]);
+		retval |= setTEGlow(i, (F32)glow[i] / (F32)0xFF);
 		coloru = LLColor4U(colors + 4*i);
 
 		// Note:  This is an optimization to send common colors (1.f, 1.f, 1.f, 1.f)
@@ -1621,6 +1648,8 @@ BOOL LLNetworkData::isValid(U16 param_type, U32 size)
 		return (size == 16);
 	case PARAMS_LIGHT:
 		return (size == 16);
+	case PARAMS_SCULPT:
+		return (size == 17);
 	}
 	
 	return FALSE;
@@ -1776,3 +1805,55 @@ void LLFlexibleObjectData::copy(const LLNetworkData& data)
 	//mUsingCollisionSphere = flex_data->mUsingCollisionSphere;
 	//mRenderingCollisionSphere = flex_data->mRenderingCollisionSphere;
 }
+
+
+//============================================================================
+
+LLSculptParams::LLSculptParams()
+{
+	mType = PARAMS_SCULPT;
+	mSculptTexture.set(SCULPT_DEFAULT_TEXTURE);
+	mSculptType = LL_SCULPT_TYPE_SPHERE;
+}
+
+BOOL LLSculptParams::pack(LLDataPacker &dp) const
+{
+	dp.packUUID(mSculptTexture, "texture");
+	dp.packU8(mSculptType, "type");
+	
+	return TRUE;
+}
+
+BOOL LLSculptParams::unpack(LLDataPacker &dp)
+{
+	dp.unpackUUID(mSculptTexture, "texture");
+	dp.unpackU8(mSculptType, "type");
+	
+	return TRUE;
+}
+
+bool LLSculptParams::operator==(const LLNetworkData& data) const
+{
+	if (data.mType != PARAMS_SCULPT)
+	{
+		return false;
+	}
+	
+	const LLSculptParams *param = (const LLSculptParams*)&data;
+	if ( (param->mSculptTexture != mSculptTexture) ||
+		 (param->mSculptType != mSculptType) )
+		 
+	{
+		return false;
+	}
+	
+	return true;
+}
+
+void LLSculptParams::copy(const LLNetworkData& data)
+{
+	const LLSculptParams *param = (LLSculptParams*)&data;
+	mSculptTexture = param->mSculptTexture;
+	mSculptType = param->mSculptType;
+}
+
diff --git a/indra/llprimitive/llprimitive.h b/indra/llprimitive/llprimitive.h
index 90871fd319513c1539580c90534fd50391d78692..ab1fc4f719e22300bcf1fcb3419eddf59ed61068 100644
--- a/indra/llprimitive/llprimitive.h
+++ b/indra/llprimitive/llprimitive.h
@@ -68,6 +68,7 @@ extern const F32 OBJECT_REV_MIN;
 extern const F32 OBJECT_REV_MAX;
 extern const F32 OBJECT_REV_INC;
 
+extern const char *SCULPT_DEFAULT_TEXTURE;
 
 //============================================================================
 
@@ -79,7 +80,8 @@ class LLNetworkData
 	enum
 	{
 		PARAMS_FLEXIBLE = 0x10,
-		PARAMS_LIGHT = 0x20
+		PARAMS_LIGHT    = 0x20,
+		PARAMS_SCULPT   = 0x30
 	};
 	
 public:
@@ -206,6 +208,29 @@ class LLFlexibleObjectData : public LLNetworkData
 	void copy(const LLNetworkData& data);
 };// end of attributes structure
 
+
+
+class LLSculptParams : public LLNetworkData
+{
+protected:
+	LLUUID mSculptTexture;
+	U8 mSculptType;
+	
+public:
+	LLSculptParams();
+	/*virtual*/ BOOL pack(LLDataPacker &dp) const;
+	/*virtual*/ BOOL unpack(LLDataPacker &dp);
+	/*virtual*/ bool operator==(const LLNetworkData& data) const;
+	/*virtual*/ void copy(const LLNetworkData& data);
+
+	void setSculptTexture(const LLUUID& id) { mSculptTexture = id; }
+	LLUUID getSculptTexture()               { return mSculptTexture; }
+	void setSculptType(U8 type)             { mSculptType = type; }
+	U8 getSculptType()                      { return mSculptType; }
+};
+
+
+
 class LLPrimitive : public LLXform
 {
 public:
@@ -246,6 +271,7 @@ class LLPrimitive : public LLXform
 	virtual S32 setTEShiny(const U8 te, const U8 shiny);
 	virtual S32 setTEFullbright(const U8 te, const U8 fullbright);
 	virtual S32 setTEMediaFlags(const U8 te, const U8 flags);
+	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,
diff --git a/indra/llprimitive/lltextureentry.cpp b/indra/llprimitive/lltextureentry.cpp
index 86952dfdb57dc1e7035e52fcfa0481d55f53e3f5..85ff779ba2e939d30f36cd5c3536adc813554651 100644
--- a/indra/llprimitive/lltextureentry.cpp
+++ b/indra/llprimitive/lltextureentry.cpp
@@ -37,6 +37,7 @@ LLTextureEntry::LLTextureEntry(const LLTextureEntry &rhs)
 	mColor = rhs.mColor;
 	mBump = rhs.mBump;
 	mMediaFlags = rhs.mMediaFlags;
+	mGlow = rhs.mGlow;
 }
 
 LLTextureEntry &LLTextureEntry::operator=(const LLTextureEntry &rhs)
@@ -52,6 +53,7 @@ LLTextureEntry &LLTextureEntry::operator=(const LLTextureEntry &rhs)
 		mColor = rhs.mColor;
 		mBump = rhs.mBump;
 		mMediaFlags = rhs.mMediaFlags;
+		mGlow = rhs.mGlow;
 	}
 
 	return *this;
@@ -68,7 +70,8 @@ void LLTextureEntry::init(const LLUUID& tex_id, F32 scale_s, F32 scale_t, F32 of
 	mRotation = rotation;
 	mBump = bump;
 	mMediaFlags = 0x0;
-
+    mGlow = 0;
+	
 	setColor(LLColor4(1.f, 1.f, 1.f, 1.f));
 }
 
@@ -346,3 +349,13 @@ S32 LLTextureEntry::setTexGen(U8 tex_gen)
 	return 0;
 }
 
+S32 LLTextureEntry::setGlow(F32 glow)
+{
+	if (mGlow != glow)
+	{
+		mGlow = glow;
+		return TEM_CHANGE_TEXTURE;
+	}
+	return 0;
+}
+
diff --git a/indra/llprimitive/lltextureentry.h b/indra/llprimitive/lltextureentry.h
index b9558a159afc26aa495607d2afe1637623890b42..f8cdd3bee16a37f47d0bc2fd8228c0c4a036a175 100644
--- a/indra/llprimitive/lltextureentry.h
+++ b/indra/llprimitive/lltextureentry.h
@@ -87,7 +87,8 @@ class LLTextureEntry
 	S32  setMediaFlags(U8 media_flags);
 	S32	 setTexGen(U8 texGen);
 	S32  setMediaTexGen(U8 media);
-
+    S32  setGlow(F32 glow);
+	
 	const LLUUID &getID() const { return mID; }
 	const LLColor4 &getColor() const { return mColor; }
 	void getScale(F32 *s, F32 *t) const { *s = mScaleS; *t = mScaleT; }
@@ -104,7 +105,8 @@ class LLTextureEntry
 	U8	 getMediaFlags() const { return mMediaFlags & TEM_MEDIA_MASK; }
 	U8	 getTexGen() const	{ return mMediaFlags & TEM_TEX_GEN_MASK; }
 	U8	 getMediaTexGen() const { return mMediaFlags; }
-
+    F32  getGlow() const { return mGlow; }
+	
 	// Media flags
 	enum { MF_NONE = 0x0, MF_WEB_PAGE = 0x1 };
 
@@ -121,6 +123,8 @@ class LLTextureEntry
 	LLColor4			mColor;
 	U8					mBump;					// Bump map, shiny, and fullbright
 	U8					mMediaFlags;			// replace with web page, movie, etc.
+	F32                 mGlow;
+	
 };
 
 #endif
diff --git a/indra/lscript/lscript_compile/indra.l b/indra/lscript/lscript_compile/indra.l
index e93cc6082dd729fb4f84851b4f6bf7d4eaf6c0fa..08c2683665e095b9fd40791a5232241aa90cbbf9 100644
--- a/indra/lscript/lscript_compile/indra.l
+++ b/indra/lscript/lscript_compile/indra.l
@@ -4,7 +4,7 @@ L			[a-zA-Z_]
 H			[a-fA-F0-9]
 E			[Ee][+-]?{D}+
 FS			(f|F)
-%e 9000
+%e 10000
 %n 4000
 %p 5000
 
@@ -434,6 +434,7 @@ extern "C" { int yyerror(const char *fmt, ...); }
 "PRIM_TYPE_TORUS"		{ count(); yylval.ival = LSL_PRIM_TYPE_TORUS; return(INTEGER_CONSTANT); }
 "PRIM_TYPE_TUBE"		{ count(); yylval.ival = LSL_PRIM_TYPE_TUBE; return(INTEGER_CONSTANT); }
 "PRIM_TYPE_RING"		{ count(); yylval.ival = LSL_PRIM_TYPE_RING; return(INTEGER_CONSTANT); }
+"PRIM_TYPE_SCULPT"		{ count(); yylval.ival = LSL_PRIM_TYPE_SCULPT; return(INTEGER_CONSTANT); }
 
 "PRIM_HOLE_DEFAULT"		{ count(); yylval.ival = LSL_PRIM_HOLE_DEFAULT; return(INTEGER_CONSTANT); }
 "PRIM_HOLE_CIRCLE"		{ count(); yylval.ival = LSL_PRIM_HOLE_CIRCLE; return(INTEGER_CONSTANT); }
@@ -476,6 +477,11 @@ extern "C" { int yyerror(const char *fmt, ...); }
 "PRIM_TEXGEN_DEFAULT"	{ count(); yylval.ival = LSL_PRIM_TEXGEN_DEFAULT; return(INTEGER_CONSTANT); }
 "PRIM_TEXGEN_PLANAR"	{ count(); yylval.ival = LSL_PRIM_TEXGEN_PLANAR; return(INTEGER_CONSTANT); }
 
+"PRIM_SCULPT_TYPE_SPHERE"	{ count(); yylval.ival = LSL_PRIM_SCULPT_TYPE_SPHERE; return(INTEGER_CONSTANT); }
+"PRIM_SCULPT_TYPE_TORUS"	{ count(); yylval.ival = LSL_PRIM_SCULPT_TYPE_TORUS; return(INTEGER_CONSTANT); }
+"PRIM_SCULPT_TYPE_PLANE"	{ count(); yylval.ival = LSL_PRIM_SCULPT_TYPE_PLANE; return(INTEGER_CONSTANT); }
+"PRIM_SCULPT_TYPE_CYLINDER"	{ count(); yylval.ival = LSL_PRIM_SCULPT_TYPE_CYLINDER; return(INTEGER_CONSTANT); }
+
 "MASK_BASE"				{ count(); yylval.ival = 0; return(INTEGER_CONSTANT); }
 "MASK_OWNER"			{ count(); yylval.ival = 1; return(INTEGER_CONSTANT); }
 "MASK_GROUP"			{ count(); yylval.ival = 2; return(INTEGER_CONSTANT); }
diff --git a/indra/lscript/lscript_library/lscript_library.cpp b/indra/lscript/lscript_library/lscript_library.cpp
index fda6d0e3f3335115433b14af4a484545389b7fb9..46717594debb4303023d4ff595fe359bd2ed2b0c 100644
--- a/indra/lscript/lscript_library/lscript_library.cpp
+++ b/indra/lscript/lscript_library/lscript_library.cpp
@@ -404,6 +404,7 @@ void LLScriptLibrary::init()
 
 	
 	addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llStringTrim", "s", "si", "string llStringTrim(string src, integer trim_type)\nTrim leading and/or trailing spaces from a string.\nUses trim_type of STRING_TRIM, STRING_TRIM_HEAD or STRING_TRIM_TAIL."));
+	addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llRegionSay", NULL, "is", "llRegionSay(integer channel, string msg)\nbroadcasts msg to entire region on channel (not 0.)"));
 
 	// energy, sleep, dummy_func, name, return type, parameters, help text, gods-only
 
diff --git a/indra/newview/English.lproj/InfoPlist.strings b/indra/newview/English.lproj/InfoPlist.strings
index 9142437ac5fc8af24315103715aa0a76b98506c2..8fae01fbdc5755d5655a3add9a0327241ebb409d 100644
--- a/indra/newview/English.lproj/InfoPlist.strings
+++ b/indra/newview/English.lproj/InfoPlist.strings
@@ -1,5 +1,5 @@
 /* Localized versions of Info.plist keys */
 
 CFBundleName = "Second Life";
-CFBundleShortVersionString = "Second Life version 1.15.2.0";
-CFBundleGetInfoString = "Second Life version 1.15.2.0, Copyright 2004-2007 Linden Research, Inc.";
+CFBundleShortVersionString = "Second Life version 1.16.0.5";
+CFBundleGetInfoString = "Second Life version 1.16.0.5, Copyright 2004-2007 Linden Research, Inc.";
diff --git a/indra/newview/Info-SecondLife.plist b/indra/newview/Info-SecondLife.plist
index a0ee123a6a15787f8e8f3746377992df4bb179d3..764b1520f07fdd83727a65466d12f9f41958a049 100644
--- a/indra/newview/Info-SecondLife.plist
+++ b/indra/newview/Info-SecondLife.plist
@@ -32,7 +32,7 @@
 		</dict>
 	</array>
 	<key>CFBundleVersion</key>
-	<string>1.15.2.0</string>
+	<string>1.16.0.5</string>
 	<key>CSResourcesFileMapped</key>
 	<true/>
 </dict>
diff --git a/indra/newview/app_settings/keywords.ini b/indra/newview/app_settings/keywords.ini
index c2a2ce2755d513b1b318f1f484104bbad3a5349a..c7f84268046a68d857f9c432bccbc5889a4c7d67 100644
--- a/indra/newview/app_settings/keywords.ini
+++ b/indra/newview/app_settings/keywords.ini
@@ -346,6 +346,7 @@ PRIM_TYPE_SPHERE	Followed by integer hole shape, vector cut, float hollow, vecto
 PRIM_TYPE_TORUS		Followed by integer hole shape, vector cut, float hollow, vector twist,:vector hole size, vector top shear, vector advanced cut, vector taper,:float revolutions, float radius offset, and float skew
 PRIM_TYPE_TUBE		Followed by integer hole shape, vector cut, float hollow, vector twist,:vector hole size, vector top shear, vector advanced cut, vector taper,:float revolutions, float radius offset, and float skew
 PRIM_TYPE_RING		Followed by integer hole shape, vector cut, float hollow, vector twist,:vector hole size, vector top shear, vector advanced cut, vector taper,:float revolutions, float radius offset, and float skew
+PRIM_TYPE_SCULPT	Followed by a key or string texture uuid.
 
 PRIM_HOLE_DEFAULT	Sets hole type to match the prim type.
 PRIM_HOLE_SQUARE	Sets hole type to square.
@@ -388,6 +389,11 @@ PRIM_BUMP_WEAVE			Weave bump map
 PRIM_TEXGEN_DEFAULT		Default texture mapping
 PRIM_TEXGEN_PLANAR		Planar texture mapping
 
+PRIM_SCULPT_TYPE_SPHERE		Stitch edges in a sphere-like way
+PRIM_SCULPT_TYPE_TORUS		Stitch edges in a torus-like way
+PRIM_SCULPT_TYPE_PLANE		Do not stitch edges
+PRIM_SCULPT_TYPE_CYLINDER	Stitch edges in a cylinder-like way
+
 MASK_BASE				Base permissions
 MASK_OWNER				Owner permissions
 MASK_GROUP				Group permissions
diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp
index 9fa5244c39040edec6d6b2601c322e90dad5c655..c6155197f6d891a1d796922e73d5c956a3875d29 100644
--- a/indra/newview/llagent.cpp
+++ b/indra/newview/llagent.cpp
@@ -4917,6 +4917,8 @@ void LLAgent::sendAnimationRequests(LLDynamicArray<LLUUID> &anim_ids, EAnimReque
 		num_valid_anims++;
 	}
 
+	msg->nextBlockFast(_PREHASH_PhysicalAvatarEventList);
+	msg->addBinaryDataFast(_PREHASH_TypeData, NULL, 0);
 	if (num_valid_anims)
 	{
 		sendReliableMessage();
@@ -4940,6 +4942,8 @@ void LLAgent::sendAnimationRequest(const LLUUID &anim_id, EAnimRequest request)
 	msg->addUUIDFast(_PREHASH_AnimID, (anim_id) );
 	msg->addBOOLFast(_PREHASH_StartAnim, (request == ANIM_REQUEST_START) ? TRUE : FALSE);
 
+	msg->nextBlockFast(_PREHASH_PhysicalAvatarEventList);
+	msg->addBinaryDataFast(_PREHASH_TypeData, NULL, 0);
 	sendReliableMessage();
 }
 
diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp
index b96ffa46fe91dadc660ee67bb6445a85f119b776..044ae33cccf8dfe537992db3704bdeb15826fbab 100644
--- a/indra/newview/llface.cpp
+++ b/indra/newview/llface.cpp
@@ -706,8 +706,6 @@ BOOL LLFace::genVolumeBBoxes(const LLVolume &volume, S32 f,
 {
 	LLMemType mt1(LLMemType::MTYPE_DRAWABLE);
 
-	const LLVolumeFace &face = volume.getVolumeFace(f);
-	
 	//get bounding box
 	if (mDrawablep->isState(LLDrawable::REBUILD_VOLUME | LLDrawable::REBUILD_POSITION))
 	{
@@ -718,9 +716,18 @@ BOOL LLFace::genVolumeBBoxes(const LLVolume &volume, S32 f,
 		}
 
 		LLVector3 min,max;
-			
-		min = face.mExtents[0];
-		max = face.mExtents[1];
+	
+		if (f >= volume.getNumVolumeFaces())
+		{
+			min = LLVector3(-1,-1,-1);
+			max = LLVector3(1,1,1);
+		}
+		else
+		{
+			const LLVolumeFace &face = volume.getVolumeFace(f);
+			min = face.mExtents[0];
+			max = face.mExtents[1];
+		}
 
 		//min, max are in volume space, convert to drawable render space
 		LLVector3 center = ((min + max) * 0.5f)*mat_vert;
@@ -884,6 +891,10 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 					full_rebuild = TRUE;
 				}
 			}
+			else
+			{
+				full_rebuild = TRUE;
+			}
 		}
 		else
 		{
diff --git a/indra/newview/llfloaterimagepreview.cpp b/indra/newview/llfloaterimagepreview.cpp
index f10abc44664bf4305e1817c4d6c7ec2e98fa54c5..4f7ef34fe144b21bf6dd02e5519cc9fff78597ad 100644
--- a/indra/newview/llfloaterimagepreview.cpp
+++ b/indra/newview/llfloaterimagepreview.cpp
@@ -82,10 +82,14 @@ BOOL LLFloaterImagePreview::postBuild()
 	{
 		mAvatarPreview = new LLImagePreviewAvatar(256, 256);
 		mAvatarPreview->setPreviewTarget("mPelvis", "mUpperBodyMesh0", mRawImagep, 2.f, FALSE);
+
+		mSculptedPreview = new LLImagePreviewSculpted(256, 256);
+		mSculptedPreview->setPreviewTarget(mRawImagep, 2.0f);
 	}
 	else
 	{
 		mAvatarPreview = NULL;
+		mSculptedPreview = NULL;
 		childShow("bad_image_text");
 		childDisable("clothing_type_combo");
 		childDisable("ok_btn");
@@ -101,6 +105,8 @@ LLFloaterImagePreview::~LLFloaterImagePreview()
 {
 	mRawImagep = NULL;
 	delete mAvatarPreview;
+	delete mSculptedPreview;
+	
 	if (mGLName)
 	{
 		glDeleteTextures(1, &mGLName );
@@ -115,7 +121,7 @@ void	LLFloaterImagePreview::onPreviewTypeCommit(LLUICtrl* ctrl, void* userdata)
 {
 	LLFloaterImagePreview *fp =(LLFloaterImagePreview *)userdata;
 	
-	if (!fp->mAvatarPreview)
+	if (!fp->mAvatarPreview || !fp->mSculptedPreview)
 	{
 		return;
 	}
@@ -156,10 +162,15 @@ void	LLFloaterImagePreview::onPreviewTypeCommit(LLUICtrl* ctrl, void* userdata)
 	case 8:
 		fp->mAvatarPreview->setPreviewTarget("mKneeLeft", "mSkirtMesh0", fp->mRawImagep, 1.3f, FALSE);
 		break;
+	case 9:
+		fp->mSculptedPreview->setPreviewTarget(fp->mRawImagep, 2.0f);
+		break;
 	default:
 		break;
 	}
+	
 	fp->mAvatarPreview->refresh();
+	fp->mSculptedPreview->refresh();
 }
 
 //-----------------------------------------------------------------------------
@@ -173,7 +184,11 @@ void LLFloaterImagePreview::draw()
 	if (mRawImagep.notNull())
 	{
 		LLCtrlSelectionInterface* iface = childGetSelectionInterface("clothing_type_combo");
-		if (iface && iface->getFirstSelectedIndex() <= 0)
+		U32 selected = 0;
+		if (iface)
+			selected = iface->getFirstSelectedIndex();
+		
+		if (selected <= 0)
 		{
 			gl_rect_2d_checkerboard(mPreviewRect);
 			LLGLDisable gls_alpha(GL_ALPHA_TEST);
@@ -210,6 +225,7 @@ void LLFloaterImagePreview::draw()
 				if (mAvatarPreview)
 				{
 					mAvatarPreview->setTexture(mGLName);
+					mSculptedPreview->setTexture(mGLName);
 				}
 			}
 
@@ -233,10 +249,14 @@ void LLFloaterImagePreview::draw()
 		}
 		else
 		{
-			if (mAvatarPreview)
+			if ((mAvatarPreview) && (mSculptedPreview))
 			{
 				glColor3f(1.f, 1.f, 1.f);
-				mAvatarPreview->bindTexture();
+
+				if (selected == 9)
+					mSculptedPreview->bindTexture();
+				else
+					mAvatarPreview->bindTexture();
 
 				glBegin( GL_QUADS );
 				{
@@ -251,12 +271,16 @@ void LLFloaterImagePreview::draw()
 				}
 				glEnd();
 
-				mAvatarPreview->unbindTexture();
+				if (selected == 9)
+					mSculptedPreview->unbindTexture();
+				else
+					mAvatarPreview->unbindTexture();
 			}
 		}
 	}
 }
 
+
 //-----------------------------------------------------------------------------
 // loadImage()
 //-----------------------------------------------------------------------------
@@ -397,6 +421,7 @@ BOOL LLFloaterImagePreview::handleHover(S32 x, S32 y, MASK mask)
 			else
 			{
 				mAvatarPreview->pan((F32)(x - mLastMouseX) * -0.005f, (F32)(y - mLastMouseY) * -0.005f);
+				mSculptedPreview->pan((F32)(x - mLastMouseX) * -0.005f, (F32)(y - mLastMouseY) * -0.005f);
 			}
 		}
 		else if (local_mask == MASK_ORBIT)
@@ -405,6 +430,7 @@ BOOL LLFloaterImagePreview::handleHover(S32 x, S32 y, MASK mask)
 			F32 pitch_radians = (F32)(y - mLastMouseY) * 0.02f;
 			
 			mAvatarPreview->rotate(yaw_radians, pitch_radians);
+			mSculptedPreview->rotate(yaw_radians, pitch_radians);
 		}
 		else 
 		{
@@ -421,6 +447,8 @@ BOOL LLFloaterImagePreview::handleHover(S32 x, S32 y, MASK mask)
 				
 				mAvatarPreview->rotate(yaw_radians, 0.f);
 				mAvatarPreview->zoom(zoom_amt);
+				mSculptedPreview->rotate(yaw_radians, 0.f);
+				mSculptedPreview->zoom(zoom_amt);
 			}
 		}
 
@@ -466,12 +494,13 @@ BOOL LLFloaterImagePreview::handleHover(S32 x, S32 y, MASK mask)
 		else
 		{
 			mAvatarPreview->refresh();
+			mSculptedPreview->refresh();
 		}
 
 		LLUI::setCursorPositionLocal(this, mLastMouseX, mLastMouseY);
 	}
 
-	if (!mPreviewRect.pointInRect(x, y) || !mAvatarPreview)
+	if (!mPreviewRect.pointInRect(x, y) || !mAvatarPreview || !mSculptedPreview)
 	{
 		return LLFloater::handleHover(x, y, mask);
 	}
@@ -500,6 +529,9 @@ BOOL LLFloaterImagePreview::handleScrollWheel(S32 x, S32 y, S32 clicks)
 	{
 		mAvatarPreview->zoom((F32)clicks * -0.2f);
 		mAvatarPreview->refresh();
+
+		mSculptedPreview->zoom((F32)clicks * -0.2f);
+		mSculptedPreview->refresh();
 	}
 
 	return TRUE;
@@ -540,6 +572,7 @@ LLImagePreviewAvatar::LLImagePreviewAvatar(S32 width, S32 height) : LLDynamicTex
 	mTextureName = 0;
 }
 
+
 LLImagePreviewAvatar::~LLImagePreviewAvatar()
 {
 	mDummyAvatar->markDead();
@@ -582,7 +615,7 @@ void LLImagePreviewAvatar::setPreviewTarget(const char* joint_name, const char*
 //-----------------------------------------------------------------------------
 // update()
 //-----------------------------------------------------------------------------
-BOOL	LLImagePreviewAvatar::render()
+BOOL LLImagePreviewAvatar::render()
 {
 	mNeedsUpdate = FALSE;
 	LLVOAvatar* avatarp = mDummyAvatar;
@@ -620,6 +653,7 @@ BOOL	LLImagePreviewAvatar::render()
 
 	stop_glerror();
 
+	gCamera->setAspect((F32)mWidth / mHeight);
 	gCamera->setView(gCamera->getDefaultFOV() / mCameraZoom);
 	gCamera->setPerspective(FALSE, mOrigin.mX, mOrigin.mY, mWidth, mHeight, FALSE);
 
@@ -672,3 +706,170 @@ void LLImagePreviewAvatar::pan(F32 right, F32 up)
 	mCameraOffset.mV[VY] = llclamp(mCameraOffset.mV[VY] + right * mCameraDistance / mCameraZoom, -1.f, 1.f);
 	mCameraOffset.mV[VZ] = llclamp(mCameraOffset.mV[VZ] + up * mCameraDistance / mCameraZoom, -1.f, 1.f);
 }
+
+
+//-----------------------------------------------------------------------------
+// LLImagePreviewSculpted
+//-----------------------------------------------------------------------------
+
+LLImagePreviewSculpted::LLImagePreviewSculpted(S32 width, S32 height) : LLDynamicTexture(width, height, 3, ORDER_MIDDLE, FALSE)
+{
+	mNeedsUpdate = TRUE;
+	mCameraDistance = 0.f;
+	mCameraYaw = 0.f;
+	mCameraPitch = 0.f;
+	mCameraZoom = 1.f;
+	mTextureName = 0;
+
+	LLVolumeParams volume_params;
+	volume_params.setType(LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_CIRCLE);
+	mVolume = new LLVolume(volume_params, (F32) MAX_LOD);
+
+	/*
+	mDummyAvatar = new LLVOAvatar(LLUUID::null, LL_PCODE_LEGACY_AVATAR, gAgent.getRegion());
+	mDummyAvatar->createDrawable(&gPipeline);
+	mDummyAvatar->mIsDummy = TRUE;
+	mDummyAvatar->mSpecialRenderMode = 2;
+	mDummyAvatar->setPositionAgent(LLVector3::zero);
+	mDummyAvatar->slamPosition();
+	mDummyAvatar->updateJointLODs();
+	mDummyAvatar->updateGeometry(mDummyAvatar->mDrawable);
+	gPipeline.markVisible(mDummyAvatar->mDrawable, *gCamera);
+	mTextureName = 0;
+	*/
+}
+
+
+LLImagePreviewSculpted::~LLImagePreviewSculpted()
+{
+	/*
+	mDummyAvatar->markDead();
+	*/
+}
+
+
+void LLImagePreviewSculpted::setPreviewTarget(LLImageRaw* imagep, F32 distance)
+{ 
+	mCameraDistance = distance;
+	mCameraZoom = 1.f;
+	mCameraPitch = 0.f;
+	mCameraYaw = 0.f;
+	mCameraOffset.clearVec();
+
+	if (imagep)
+	{
+		mVolume->sculpt(imagep->getWidth(), imagep->getHeight(), imagep->getComponents(), imagep->getData(), 0);
+	}
+	
+}
+
+
+//-----------------------------------------------------------------------------
+// render()
+//-----------------------------------------------------------------------------
+BOOL LLImagePreviewSculpted::render()
+{
+	mNeedsUpdate = FALSE;
+
+	LLGLSUIDefault def;
+	LLGLDisable no_blend(GL_BLEND);
+	LLGLEnable cull(GL_CULL_FACE);
+	LLGLDepthTest depth(GL_TRUE);
+
+	glMatrixMode(GL_PROJECTION);
+	glPushMatrix();
+	glLoadIdentity();
+	glOrtho(0.0f, mWidth, 0.0f, mHeight, -1.0f, 1.0f);
+
+	glMatrixMode(GL_MODELVIEW);
+	glPushMatrix();
+	glLoadIdentity();
+		
+	glColor4f(0.15f, 0.2f, 0.3f, 1.f);
+
+	gl_rect_2d_simple( mWidth, mHeight );
+
+	glMatrixMode(GL_PROJECTION);
+	glPopMatrix();
+
+	glMatrixMode(GL_MODELVIEW);
+	glPopMatrix();
+
+	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+	
+	LLVector3 target_pos(0, 0, 0);
+
+	LLQuaternion camera_rot = LLQuaternion(mCameraPitch, LLVector3::y_axis) * 
+		LLQuaternion(mCameraYaw, LLVector3::z_axis);
+
+	LLQuaternion av_rot = camera_rot;
+	gCamera->setOriginAndLookAt(
+		target_pos + ((LLVector3(mCameraDistance, 0.f, 0.f) + mCameraOffset) * av_rot),		// camera
+		LLVector3::z_axis,																	// up
+		target_pos + (mCameraOffset  * av_rot) );											// point of interest
+
+	stop_glerror();
+
+	gCamera->setAspect((F32) mWidth / mHeight);
+	gCamera->setView(gCamera->getDefaultFOV() / mCameraZoom);
+	gCamera->setPerspective(FALSE, mOrigin.mX, mOrigin.mY, mWidth, mHeight, FALSE);
+
+	gPipeline.enableLightsAvatar(0.0);
+
+		
+	glPushMatrix();
+	glScalef(0.5, 0.5, 0.5);
+	
+	glBegin(GL_TRIANGLES);
+	glColor3f(0.8f, 0.8f, 0.8f);
+
+	const LLVolumeFace &vf = mVolume->getVolumeFace(0);
+	S32 num_indices = (S32)vf.mIndices.size();
+	for (U32 i = 0; (S32)i < num_indices; i++)
+	{
+		LLVector3 normal = vf.mVertices[vf.mIndices[i]].mNormal;
+		normal.normVec();
+		glNormal3f(normal.mV[VX], normal.mV[VY], normal.mV[VZ]);
+
+		LLVector3 position = vf.mVertices[vf.mIndices[i]].mPosition;
+		glVertex3f(position.mV[VX], position.mV[VY], position.mV[VZ]);
+	}
+		
+	glEnd();
+	
+	glPopMatrix();
+	
+	return TRUE;
+}
+
+//-----------------------------------------------------------------------------
+// refresh()
+//-----------------------------------------------------------------------------
+void LLImagePreviewSculpted::refresh()
+{ 
+	mNeedsUpdate = TRUE; 
+}
+
+//-----------------------------------------------------------------------------
+// rotate()
+//-----------------------------------------------------------------------------
+void LLImagePreviewSculpted::rotate(F32 yaw_radians, F32 pitch_radians)
+{
+	mCameraYaw = mCameraYaw + yaw_radians;
+
+	mCameraPitch = llclamp(mCameraPitch + pitch_radians, F_PI_BY_TWO * -0.8f, F_PI_BY_TWO * 0.8f);
+}
+
+//-----------------------------------------------------------------------------
+// zoom()
+//-----------------------------------------------------------------------------
+void LLImagePreviewSculpted::zoom(F32 zoom_amt)
+{
+	mCameraZoom	= llclamp(mCameraZoom + zoom_amt, 1.f, 10.f);
+}
+
+void LLImagePreviewSculpted::pan(F32 right, F32 up)
+{
+	mCameraOffset.mV[VY] = llclamp(mCameraOffset.mV[VY] + right * mCameraDistance / mCameraZoom, -1.f, 1.f);
+	mCameraOffset.mV[VZ] = llclamp(mCameraOffset.mV[VZ] + up * mCameraDistance / mCameraZoom, -1.f, 1.f);
+}
diff --git a/indra/newview/llfloaterimagepreview.h b/indra/newview/llfloaterimagepreview.h
index 4978a6ea0ba31ad3cc0e26b93e3211621b64f30a..af98466cf8d48f38606a2cd827ffe95f61de53d2 100644
--- a/indra/newview/llfloaterimagepreview.h
+++ b/indra/newview/llfloaterimagepreview.h
@@ -19,6 +19,34 @@ class LLViewerJointMesh;
 class LLVOAvatar;
 class LLTextBox;
 
+class LLImagePreviewSculpted : public LLDynamicTexture
+{
+ public:
+	LLImagePreviewSculpted(S32 width, S32 height);
+	virtual ~LLImagePreviewSculpted();
+
+	void setPreviewTarget(LLImageRaw *imagep, F32 distance);
+	void setTexture(U32 name) { mTextureName = name; }
+
+	BOOL render();
+	void refresh();
+	void rotate(F32 yaw_radians, F32 pitch_radians);
+	void zoom(F32 zoom_amt);
+	void pan(F32 right, F32 up);
+	virtual BOOL needsRender() { return mNeedsUpdate; }
+
+ protected:
+	BOOL        mNeedsUpdate;
+	U32         mTextureName;
+	F32			mCameraDistance;
+	F32			mCameraYaw;
+	F32			mCameraPitch;
+	F32			mCameraZoom;
+	LLVector3	mCameraOffset;
+	LLPointer<LLVolume> mVolume;
+};
+
+
 class LLImagePreviewAvatar : public LLDynamicTexture
 {
 public:
@@ -71,6 +99,7 @@ class LLFloaterImagePreview : public LLFloaterNameDesc
 
 	LLPointer<LLImageRaw> mRawImagep;
 	LLImagePreviewAvatar* mAvatarPreview;
+	LLImagePreviewSculpted* mSculptedPreview;
 	S32				mLastMouseX;
 	S32				mLastMouseY;
 	LLRect			mPreviewRect;
diff --git a/indra/newview/llmanipscale.cpp b/indra/newview/llmanipscale.cpp
index 56a4352e221354c16b61f5392b85e2c3f34c992a..14da426d9a0a3455fca7256695d0a58f8e8b447e 100644
--- a/indra/newview/llmanipscale.cpp
+++ b/indra/newview/llmanipscale.cpp
@@ -584,6 +584,7 @@ void LLManipScale::renderFaces( const LLBBox& bbox )
 	if (mManipPart == LL_NO_PART)
 	{
 		glColor4fv( default_normal_color.mV );
+		LLGLDepthTest gls_depth(GL_FALSE);
 		glBegin(GL_QUADS); 
 		{
 			// Face 0
@@ -746,7 +747,8 @@ void LLManipScale::renderCorners( const LLBBox& bbox )
 void LLManipScale::renderBoxHandle( F32 x, F32 y, F32 z )
 {
 	LLGLDisable gls_tex(GL_TEXTURE_2D);
-	
+	LLGLDepthTest gls_depth(GL_FALSE);
+
 	glPushMatrix();
 	{
 		glTranslatef( x, y, z );
diff --git a/indra/newview/llpanelobject.cpp b/indra/newview/llpanelobject.cpp
index 314b7bed8fb82840d8401c7592f5709f8af8186e..dcfede70aa88353e67ea9b1afc244eea50ecd394 100644
--- a/indra/newview/llpanelobject.cpp
+++ b/indra/newview/llpanelobject.cpp
@@ -33,6 +33,7 @@
 #include "llresmgr.h"
 #include "llselectmgr.h"
 #include "llspinctrl.h"
+#include "lltexturectrl.h"
 #include "lltextbox.h"
 #include "lltool.h"
 #include "lltoolcomp.h"
@@ -60,6 +61,7 @@ enum {
 	MI_TORUS,
 	MI_TUBE,
 	MI_RING,
+	MI_SCULPT,
 	MI_NONE,
 	MI_VOLUME_COUNT
 };
@@ -232,6 +234,34 @@ BOOL	LLPanelObject::postBuild()
 	childSetCommitCallback("Revolutions",onCommitParametric,this);
 	mSpinRevolutions->setValidateBeforeCommit( &precommitValidate );
 
+	// Sculpt
+	mCtrlSculptTexture = LLUICtrlFactory::getTexturePickerByName(this,"sculpt texture control");
+	mCtrlSculptTexture->setDefaultImageAssetID(LLUUID(SCULPT_DEFAULT_TEXTURE));
+	mCtrlSculptTexture->setCommitCallback( LLPanelObject::onCommitSculpt );
+	mCtrlSculptTexture->setOnCancelCallback( LLPanelObject::onCancelSculpt );
+	mCtrlSculptTexture->setOnSelectCallback( LLPanelObject::onSelectSculpt );
+	mCtrlSculptTexture->setDropCallback(LLPanelObject::onDropSculpt);
+	mCtrlSculptTexture->setCallbackUserData( this );
+	// Don't allow (no copy) or (no transfer) textures to be selected during immediate mode
+	mCtrlSculptTexture->setImmediateFilterPermMask(PERM_COPY | PERM_TRANSFER);
+	// Allow any texture to be used during non-immediate mode.
+	mCtrlSculptTexture->setNonImmediateFilterPermMask(PERM_NONE);
+	LLAggregatePermissions texture_perms;
+	if (gSelectMgr->selectGetAggregateTexturePermissions(texture_perms))
+	{
+		            BOOL can_copy =
+						texture_perms.getValue(PERM_COPY) == LLAggregatePermissions::AP_EMPTY ||
+						texture_perms.getValue(PERM_COPY) == LLAggregatePermissions::AP_ALL;
+					            BOOL can_transfer =
+									texture_perms.getValue(PERM_TRANSFER) == LLAggregatePermissions::AP_EMPTY ||
+									texture_perms.getValue(PERM_TRANSFER) == LLAggregatePermissions::AP_ALL;
+								mCtrlSculptTexture->setCanApplyImmediately(can_copy && can_transfer);
+	}
+	else
+	{
+		mCtrlSculptTexture->setCanApplyImmediately(FALSE);
+	}
+
 	// Start with everyone disabled
 	clearCtrls();
 
@@ -583,6 +613,14 @@ void LLPanelObject::getState( )
 			llinfos << "Unknown path " << (S32) path << " profile " << (S32) profile << " in getState" << llendl;
 			selected_item = MI_BOX;
 		}
+
+
+		if (objectp->getParameterEntryInUse(LLNetworkData::PARAMS_SCULPT))
+		{
+			selected_item = MI_SCULPT;
+		}
+
+		
 		mComboBaseType	->setCurrentByIndex( selected_item );
 		mSelectedType = selected_item;
 		
@@ -740,6 +778,8 @@ void LLPanelObject::getState( )
 
 	// Compute control visibility, label names, and twist range.
 	// Start with defaults.
+	BOOL cut_visible                = TRUE;
+	BOOL hollow_visible             = TRUE;
 	BOOL top_size_x_visible			= TRUE;
 	BOOL top_size_y_visible			= TRUE;
 	BOOL top_shear_x_visible		= TRUE;
@@ -750,6 +790,7 @@ void LLPanelObject::getState( )
 	BOOL skew_visible				= FALSE;
 	BOOL radius_offset_visible		= FALSE;
 	BOOL revolutions_visible		= FALSE;
+	BOOL sculpt_texture_visible     = FALSE;
 	F32	 twist_min					= OBJECT_TWIST_LINEAR_MIN;
 	F32	 twist_max					= OBJECT_TWIST_LINEAR_MAX;
 	F32	 twist_inc					= OBJECT_TWIST_LINEAR_INC;
@@ -789,6 +830,23 @@ void LLPanelObject::getState( )
 		twist_inc				= OBJECT_TWIST_INC;
 
 		break;
+
+	case MI_SCULPT:
+		cut_visible             = FALSE;
+		hollow_visible          = FALSE;
+		twist_visible           = FALSE;
+		top_size_x_visible      = FALSE;
+		top_size_y_visible      = FALSE;
+		top_shear_x_visible     = FALSE;
+		top_shear_y_visible     = FALSE;
+		skew_visible            = FALSE;
+		advanced_cut_visible    = FALSE;
+		taper_visible           = FALSE;
+		radius_offset_visible   = FALSE;
+		revolutions_visible     = FALSE;
+		sculpt_texture_visible  = TRUE;
+
+		break;
 		
 	case MI_BOX:
 	case MI_CYLINDER:
@@ -909,6 +967,15 @@ void LLPanelObject::getState( )
 	mSpinRevolutions ->setEnabled( enabled );
 
 	// Update field visibility
+	mLabelCut		->setVisible( cut_visible );
+	mSpinCutBegin	->setVisible( cut_visible );
+	mSpinCutEnd		->setVisible( cut_visible ); 
+
+	mLabelHollow	->setVisible( hollow_visible );
+	mSpinHollow		->setVisible( hollow_visible );
+	mLabelHoleType	->setVisible( hollow_visible );
+	mComboHoleType	->setVisible( hollow_visible );
+	
 	mLabelTwist		->setVisible( twist_visible );
 	mSpinTwist		->setVisible( twist_visible );
 	mSpinTwistBegin	->setVisible( twist_visible );
@@ -942,6 +1009,30 @@ void LLPanelObject::getState( )
 	mLabelRevolutions->setVisible( revolutions_visible );
 	mSpinRevolutions ->setVisible( revolutions_visible );
 
+	mCtrlSculptTexture->setVisible( sculpt_texture_visible );
+
+
+	// sculpt texture
+
+	if (selected_item == MI_SCULPT)
+	{
+        LLUUID id;
+		LLSculptParams *sculpt_params = (LLSculptParams *)objectp->getParameterEntry(LLNetworkData::PARAMS_SCULPT);
+
+		LLTextureCtrl*  mTextureCtrl = LLViewerUICtrlFactory::getTexturePickerByName(this,"sculpt texture control");
+		if((mTextureCtrl) && (sculpt_params))
+		{
+			mTextureCtrl->setTentative(FALSE);
+			mTextureCtrl->setEnabled(editable);
+			mTextureCtrl->setImageAssetID(sculpt_params->getSculptTexture());
+
+			if (mObject != objectp)  // we've just selected a new object, so save for undo
+				mSculptTextureRevert = sculpt_params->getSculptTexture();
+		}
+
+	}
+
+	
 	//----------------------------------------------------------------------------
 
 	mObject = objectp;
@@ -1063,9 +1154,26 @@ void LLPanelObject::onCommitParametric( LLUICtrl* ctrl, void* userdata )
 	LLVolumeParams volume_params;
 	self->getVolumeParams(volume_params);
 	
+
+	
+	// set sculpting
+	S32 selected_type = self->mComboBaseType->getCurrentIndex();
+
+	if (selected_type == MI_SCULPT)
+	{
+		self->mObject->setParameterEntryInUse(LLNetworkData::PARAMS_SCULPT, TRUE, TRUE);
+	}
+	else
+	{
+		LLSculptParams *sculpt_params = (LLSculptParams *)self->mObject->getParameterEntry(LLNetworkData::PARAMS_SCULPT);
+		if (sculpt_params)
+			self->mObject->setParameterEntryInUse(LLNetworkData::PARAMS_SCULPT, FALSE, TRUE);
+	}
+
 	// Update the volume, if necessary.
 	self->mObject->updateVolume(volume_params);
 
+
 	// This was added to make sure thate when changes are made, the UI
 	// adjusts to present valid options.
 	// *FIX: only some changes, ie, hollow or primitive type changes,
@@ -1118,6 +1226,11 @@ void LLPanelObject::getVolumeParams(LLVolumeParams& volume_params)
 		path = LL_PCODE_PATH_CIRCLE;
 		break;
 
+	case MI_SCULPT:
+		profile = LL_PCODE_PROFILE_CIRCLE;
+		path = LL_PCODE_PATH_CIRCLE;
+		break;
+		
 	default:
 		llwarns << "Unknown base type " << selected_type 
 			<< " in getVolumeParams()" << llendl;
@@ -1128,6 +1241,7 @@ void LLPanelObject::getVolumeParams(LLVolumeParams& volume_params)
 		break;
 	}
 
+
 	if (path == LL_PCODE_PATH_LINE)
 	{
 		LLVOVolume *volobjp = (LLVOVolume *)(LLViewerObject*)(mObject);
@@ -1338,6 +1452,23 @@ void LLPanelObject::getVolumeParams(LLVolumeParams& volume_params)
 	F32 shear_x = mSpinShearX->get();
 	F32 shear_y = mSpinShearY->get();
 	volume_params.setShear( shear_x, shear_y );
+
+	if (selected_type == MI_SCULPT)
+	{
+		volume_params.setSculptID(LLUUID::null, 0);
+		volume_params.setBeginAndEndT   (0, 1);
+		volume_params.setBeginAndEndS   (0, 1);
+		volume_params.setHollow         (0);
+		volume_params.setTwistBegin     (0);
+		volume_params.setTwistEnd       (0);
+		volume_params.setRatio          (1, 0.5);
+		volume_params.setShear          (0, 0);
+		volume_params.setTaper          (0, 0);
+		volume_params.setRevolutions    (1);
+		volume_params.setRadiusOffset   (0);
+		volume_params.setSkew           (0);
+	}
+
 }
 
 // BUG: Make work with multiple objects
@@ -1482,6 +1613,18 @@ void LLPanelObject::sendPosition()
 	}
 }
 
+void LLPanelObject::sendSculpt()
+{
+	LLTextureCtrl* mTextureCtrl = gUICtrlFactory->getTexturePickerByName(this,"sculpt texture control");
+	if(!mTextureCtrl)
+		return;
+
+	LLSculptParams sculpt_params;
+	sculpt_params.setSculptTexture(mTextureCtrl->getImageAssetID());
+	sculpt_params.setSculptType(LL_SCULPT_TYPE_SPHERE);
+	
+	mObject->setParameterEntry(LLNetworkData::PARAMS_SCULPT, sculpt_params, TRUE);
+}
 
 void LLPanelObject::refresh()
 {
@@ -1677,3 +1820,59 @@ void LLPanelObject::onCommitCastShadows( LLUICtrl* ctrl, void* userdata )
 	LLPanelObject* self = (LLPanelObject*) userdata;
 	self->sendCastShadows();
 }
+
+
+// static
+void LLPanelObject::onSelectSculpt(LLUICtrl* ctrl, void* userdata)
+{
+	LLPanelObject* self = (LLPanelObject*) userdata;
+
+    LLTextureCtrl* mTextureCtrl = gUICtrlFactory->getTexturePickerByName(self, "sculpt texture control");
+
+	if (mTextureCtrl)
+		self->mSculptTextureRevert = mTextureCtrl->getImageAssetID();
+	
+	self->sendSculpt();
+}
+
+
+void LLPanelObject::onCommitSculpt( LLUICtrl* ctrl, void* userdata )
+{
+	LLPanelObject* self = (LLPanelObject*) userdata;
+
+	self->sendSculpt();
+}
+
+// static
+BOOL LLPanelObject::onDropSculpt(LLUICtrl*, LLInventoryItem* item, void* userdata)
+{
+	LLPanelObject* self = (LLPanelObject*) userdata;
+
+    LLTextureCtrl* mTextureCtrl = gUICtrlFactory->getTexturePickerByName(self, "sculpt texture control");
+
+	if (mTextureCtrl)
+	{
+		LLUUID asset = item->getAssetUUID();
+
+		mTextureCtrl->setImageAssetID(asset);
+		self->mSculptTextureRevert = asset;
+	}
+	
+
+	return TRUE;
+}
+
+
+// static
+void LLPanelObject::onCancelSculpt(LLUICtrl* ctrl, void* userdata)
+{
+	LLPanelObject* self = (LLPanelObject*) userdata;
+
+	LLTextureCtrl* mTextureCtrl = gUICtrlFactory->getTexturePickerByName(self,"sculpt texture control");
+	if(!mTextureCtrl)
+		return;
+	
+	mTextureCtrl->setImageAssetID(self->mSculptTextureRevert);
+	
+	self->sendSculpt();
+}
diff --git a/indra/newview/llpanelobject.h b/indra/newview/llpanelobject.h
index 07b65b63724f912400ede9976aec2683b321b099..8c1bea0108071b844bdda681e9bbc786fd9f9056 100644
--- a/indra/newview/llpanelobject.h
+++ b/indra/newview/llpanelobject.h
@@ -23,6 +23,9 @@ class LLViewerObject;
 class LLComboBox;
 class LLPanelInventory;
 class LLColorSwatchCtrl;
+class LLTextureCtrl;
+class LLInventoryItem;
+class LLUUID;
 
 class LLPanelObject : public LLPanel
 {
@@ -50,6 +53,11 @@ class LLPanelObject : public LLPanel
 	static void 	onCommitParametric(LLUICtrl* ctrl, void* userdata);
 
 	static void 	onCommitMaterial(		LLUICtrl* ctrl, void* userdata);
+
+	static void     onCommitSculpt(        LLUICtrl* ctrl, void* userdata);
+	static void     onCancelSculpt(        LLUICtrl* ctrl, void* userdata);
+	static void     onSelectSculpt(        LLUICtrl* ctrl, void* userdata);
+	static BOOL     onDropSculpt(LLUICtrl* ctrl, LLInventoryItem* item, void* ud);
 	
 protected:
 	void			getState();
@@ -61,7 +69,8 @@ class LLPanelObject : public LLPanel
 	void			sendIsTemporary();
 	void			sendIsPhantom();
 	void			sendCastShadows();
-
+	void            sendSculpt();
+	
 	void 			getVolumeParams(LLVolumeParams& volume_params);
 	
 protected:
@@ -133,12 +142,16 @@ class LLPanelObject : public LLPanel
 	LLCheckBoxCtrl	*mCheckPhantom;
 	LLCheckBoxCtrl	*mCheckCastShadows;
 
+	LLTextureCtrl   *mCtrlSculptTexture;
+	
 	LLVector3		mCurEulerDegrees;		// to avoid sending rotation when not changed
 	BOOL			mIsPhysical;			// to avoid sending "physical" when not changed
 	BOOL			mIsTemporary;			// to avoid sending "temporary" when not changed
 	BOOL			mIsPhantom;				// to avoid sending "phantom" when not changed
 	BOOL			mCastShadows;			// to avoid sending "cast shadows" when not changed
 	S32				mSelectedType;			// So we know what selected type we last were
+
+	LLUUID          mSculptTextureRevert;   // so we can revert the sculpt texture on cancel
 	
 	LLPointer<LLViewerObject> mObject;
 	LLPointer<LLViewerObject> mRootObject;
diff --git a/indra/newview/llviewercamera.cpp b/indra/newview/llviewercamera.cpp
index a155a7aeec610f5721147b39d9a38442725d1e06..da93aced1f3ffd704cde2b87d960daef304dc37a 100644
--- a/indra/newview/llviewercamera.cpp
+++ b/indra/newview/llviewercamera.cpp
@@ -602,7 +602,7 @@ BOOL LLViewerCamera::areVertsVisible(LLViewerObject* volumep, BOOL all_verts)
 	
 	LLMatrix4 render_mat(vo_volume->getRenderRotation(), LLVector4(vo_volume->getRenderPosition()));
 
-	num_faces = volume->getNumFaces();
+	num_faces = volume->getNumVolumeFaces();
 	for (i = 0; i < num_faces; i++)
 	{
 		const LLVolumeFace& face = volume->getVolumeFace(i);
diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp
index d1a0b3724d2c784d66d22ff6b48a7130a67447c0..cc31aaef6732b805f5da8c2a9ed93db89b9a3f77 100644
--- a/indra/newview/llviewerinventory.cpp
+++ b/indra/newview/llviewerinventory.cpp
@@ -164,6 +164,7 @@ void LLViewerInventoryItem::updateServer(BOOL is_new) const
 	msg->nextBlockFast(_PREHASH_AgentData);
 	msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
 	msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+	msg->addUUIDFast(_PREHASH_TransactionID, mTransactionID);
 	msg->nextBlockFast(_PREHASH_InventoryData);
 	msg->addU32Fast(_PREHASH_CallbackID, 0);
 	packMessage(msg);
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index bf4ad172e66c43c9298767b272115f4160ad636b..279dfe2923205eb5f3f94f0d4e2bb314f82bffe1 100644
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -1308,9 +1308,8 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,
 
 				U32 value;
 				dp->unpackU32(value, "SpecialCode");
-
 				dp->setPassFlags(value);
-
+				dp->unpackUUID(owner_id, "Owner");
 
 				if (value & 0x80)
 				{
@@ -1449,7 +1448,6 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,
 				if (value & 0x10)
 				{
 					dp->unpackUUID(sound_uuid, "SoundUUID");
-					dp->unpackUUID(owner_id, "OwnerID");
 					dp->unpackF32(gain, "SoundGain");
 					dp->unpackU8(sound_flags, "SoundFlags");
 					dp->unpackF32(cutoff, "SoundRadius");
@@ -3996,9 +3994,9 @@ void LLViewerObject::unpackParticleSource(const S32 block_num, const LLUUID& own
 	}
 	else
 	{
+		LLViewerPartSourceScript *pss = LLViewerPartSourceScript::unpackPSS(this, NULL, block_num);
 		//If the owner is muted, don't create the system
 		if(gMuteListp->isMuted(owner_id)) return;
-		LLViewerPartSourceScript *pss = LLViewerPartSourceScript::unpackPSS(this, NULL, block_num);
 
 		// We need to be able to deal with a particle source that hasn't changed, but still got an update!
 		if (pss)
@@ -4045,10 +4043,9 @@ void LLViewerObject::unpackParticleSource(LLDataPacker &dp, const LLUUID& owner_
 	}
 	else
 	{
+		LLViewerPartSourceScript *pss = LLViewerPartSourceScript::unpackPSS(this, NULL, dp);
 		//If the owner is muted, don't create the system
 		if(gMuteListp->isMuted(owner_id)) return;
-		LLViewerPartSourceScript *pss = LLViewerPartSourceScript::unpackPSS(this, NULL, dp);
-
 		// We need to be able to deal with a particle source that hasn't changed, but still got an update!
 		if (pss)
 		{
@@ -4240,6 +4237,12 @@ LLViewerObject::ExtraParameter* LLViewerObject::createNewParameterEntry(U16 para
 		  new_block = new LLLightParams();
 		  break;
 	  }
+	  case LLNetworkData::PARAMS_SCULPT:
+	  {
+		  new_block = new LLSculptParams();
+		  break;
+	  }
+
 	  default:
 	  {
 		  llinfos << "Unknown param type." << llendl;
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index b53480ec13cda154ba7df468ff649d35d3924e64..6f68f04d67fa8193bbef2d57dae4e8147a339bf1 100644
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -42,7 +42,7 @@
 
 // Viewer object cache version, change if object update
 // format changes. JC
-const U32 INDRA_OBJECT_CACHE_VERSION = 12;
+const U32 INDRA_OBJECT_CACHE_VERSION = 14;
 
 
 extern BOOL gNoRender;
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index 1090bf4210ba115de0fbeaa0b33b1a22dbb623fb..ec64cc23b307b5619266065568de83cb441c16c6 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -69,6 +69,8 @@ LLVOVolume::LLVOVolume(const LLUUID &id, const LLPCode pcode, LLViewerRegion *re
 	mGlobalVolume = FALSE;
 	mVObjRadius = LLVector3(1,1,0.5f).magVec();
 	mNumFaces = 0;
+	mLODChanged = FALSE;
+	mSculptChanged = FALSE;
 }
 
 LLVOVolume::~LLVOVolume()
@@ -96,6 +98,15 @@ U32 LLVOVolume::processUpdateMessage(LLMessageSystem *mesgsys,
 	// Do base class updates...
 	U32 retval = LLViewerObject::processUpdateMessage(mesgsys, user_data, block_num, update_type, dp);
 
+	LLUUID sculpt_id;
+	U8 sculpt_type = 0;
+	if (isSculpted())
+	{
+		LLSculptParams *sculpt_params = (LLSculptParams *)getParameterEntry(LLNetworkData::PARAMS_SCULPT);
+		sculpt_id = sculpt_params->getSculptTexture();
+		sculpt_type = sculpt_params->getSculptType();
+	}
+
 	if (!dp)
 	{
 		if (update_type == OUT_FULL)
@@ -137,6 +148,7 @@ U32 LLVOVolume::processUpdateMessage(LLMessageSystem *mesgsys,
 			// Unpack volume data
 			LLVolumeParams volume_params;
 			LLVolumeMessage::unpackVolumeParams(&volume_params, mesgsys, _PREHASH_ObjectData, block_num);
+			volume_params.setSculptID(sculpt_id, sculpt_type);
 
 			if (setVolume(volume_params, 0))
 			{
@@ -166,7 +178,9 @@ U32 LLVOVolume::processUpdateMessage(LLMessageSystem *mesgsys,
 				llwarns << "Bogus volume parameters in object " << getID() << llendl;
 				llwarns << getRegion()->getOriginGlobal() << llendl;
 			}
-			
+
+			volume_params.setSculptID(sculpt_id, sculpt_type);
+
 			if (setVolume(volume_params, 0))
 			{
 				markForUpdate(TRUE);
@@ -442,6 +456,28 @@ void LLVOVolume::updateTextures()
 			if (pri > max_vsize) max_vsize = pri;
 		}	
 	}
+	
+	if (isSculpted())
+	{
+		LLSculptParams *sculpt_params = (LLSculptParams *)getParameterEntry(LLNetworkData::PARAMS_SCULPT);
+		LLUUID id =  sculpt_params->getSculptTexture(); 
+		mSculptTexture = gImageList.getImage(id);
+		if (mSculptTexture.notNull())
+		{
+			mSculptTexture->addTextureStats(mPixelArea);
+		}
+
+		S32 desired_discard = MAX_LOD - mLOD;
+		S32 current_discard = getVolume()->getSculptLevel();
+
+		if (desired_discard != current_discard)
+		{
+			gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, FALSE);
+			mSculptChanged = TRUE;
+		}
+		
+	}
+
 
 	if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_AREA))
 	{
@@ -604,22 +640,79 @@ BOOL LLVOVolume::setVolume(const LLVolumeParams &volume_params, const S32 detail
 			}
 		}
 	}
+	
 	mGlobalVolume = (mVolumeImpl && mVolumeImpl->isVolumeGlobal());
 	
-	if (LLPrimitive::setVolume(volume_params, mLOD, (mVolumeImpl && mVolumeImpl->isVolumeUnique())))
+	if ((LLPrimitive::setVolume(volume_params, mLOD, (mVolumeImpl && mVolumeImpl->isVolumeUnique()))) || mSculptChanged)
 	{
 		mFaceMappingChanged = TRUE;
-
+		
 		if (mVolumeImpl)
 		{
 			mVolumeImpl->onSetVolume(volume_params, detail);
 		}
+		
+		if (isSculpted())
+		{
+			mSculptTexture = gImageList.getImage(volume_params.getSculptID());
+			if (mSculptTexture.notNull())
+			{
+				sculpt();
+			}
+		}
+		else
+		{
+			mSculptTexture = NULL;
+		}
 
 		return TRUE;
 	}
 	return FALSE;
 }
 
+// sculpt replaces generate() for sculpted surfaces
+void LLVOVolume::sculpt()
+{
+	U16 sculpt_height = 0;
+	U16 sculpt_width = 0;
+	S8 sculpt_components = 0;
+	const U8* sculpt_data = NULL;
+
+	if (mSculptTexture.notNull())
+	{
+		S32 discard_level;
+		S32 desired_discard = MAX_LOD - mLOD;  // desired
+
+		discard_level = desired_discard;
+		
+		S32 max_discard = mSculptTexture->getMaxDiscardLevel();
+		if (discard_level > max_discard)
+			discard_level = max_discard;    // clamp to the best we can do
+
+		S32 best_discard = mSculptTexture->getDiscardLevel();
+		if (discard_level < best_discard)
+			discard_level = best_discard;   // clamp to what we have
+
+		if (best_discard == -1)
+			discard_level = -1;  // and if we have nothing, set to nothing
+
+		
+		S32 current_discard = getVolume()->getSculptLevel();
+		if (current_discard == discard_level)  // no work to do here
+			return;
+		
+		LLPointer<LLImageRaw> raw_image = new LLImageRaw();
+		mSculptTexture->readBackRaw(discard_level, raw_image, TRUE);
+
+		sculpt_height = raw_image->getHeight();
+		sculpt_width = raw_image->getWidth();
+
+		sculpt_components = raw_image->getComponents();
+		sculpt_data = raw_image->getData();
+		getVolume()->sculpt(sculpt_width, sculpt_height, sculpt_components, sculpt_data, discard_level);
+	}
+}
+
 S32	LLVOVolume::computeLODDetail(F32 distance, F32 radius)
 {
 	S32	cur_detail;
@@ -958,7 +1051,7 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable)
 			genBBoxes(FALSE);
 		}
 	}
-	else if (mLODChanged)
+	else if ((mLODChanged) || (mSculptChanged))
 	{
 		LLPointer<LLVolume> old_volumep, new_volumep;
 		F32 old_lod, new_lod;
@@ -974,7 +1067,7 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable)
 		new_volumep = getVolume();
 		new_lod = new_volumep->getDetail();
 
-		if (new_lod != old_lod)
+		if ((new_lod != old_lod) || mSculptChanged)
 		{
 			compiled = TRUE;
 			sNumLODChanges += getVolume()->getNumFaces();
@@ -1010,6 +1103,7 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable)
 	
 	mVolumeChanged = FALSE;
 	mLODChanged = FALSE;
+	mSculptChanged = FALSE;
 	mFaceMappingChanged = FALSE;
 
 	return TRUE;
@@ -1017,9 +1111,16 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable)
 
 void LLVOVolume::updateFaceSize(S32 idx)
 {
-	const LLVolumeFace& vol_face = getVolume()->getVolumeFace(idx);
 	LLFace* facep = mDrawable->getFace(idx);
-	facep->setSize(vol_face.mVertices.size(), vol_face.mIndices.size());
+	if (idx >= getVolume()->getNumVolumeFaces())
+	{
+		facep->setSize(0,0);
+	}
+	else
+	{
+		const LLVolumeFace& vol_face = getVolume()->getVolumeFace(idx);
+		facep->setSize(vol_face.mVertices.size(), vol_face.mIndices.size());
+	}
 }
 
 BOOL LLVOVolume::isRootEdit() const
@@ -1449,7 +1550,6 @@ BOOL LLVOVolume::isFlexible() const
 	{
 		if (getVolume()->getParams().getPathParams().getCurveType() != LL_PCODE_PATH_FLEXIBLE)
 		{
-			llwarns << "wtf" << llendl;
 			LLVolumeParams volume_params = getVolume()->getParams();
 			U8 profile_and_hole = volume_params.getProfileParams().getCurveType();
 			volume_params.setType(profile_and_hole, LL_PCODE_PATH_FLEXIBLE);
@@ -1462,6 +1562,16 @@ BOOL LLVOVolume::isFlexible() const
 	}
 }
 
+BOOL LLVOVolume::isSculpted() const
+{
+	if (getParameterEntryInUse(LLNetworkData::PARAMS_SCULPT))
+	{
+		return TRUE;
+	}
+	
+	return FALSE;
+}
+
 BOOL LLVOVolume::isVolumeGlobal() const
 {
 	if (mVolumeImpl)
diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h
index 16a91bce8e04e634b02e3980e954e18ec6ae2b47..bde9058f4c4672f1eae41272a08fd8c4bad8c632 100644
--- a/indra/newview/llvovolume.h
+++ b/indra/newview/llvovolume.h
@@ -132,6 +132,7 @@ class LLVOVolume : public LLViewerObject
 				void	setTexture(const S32 face);
 
 	/*virtual*/ BOOL	setVolume(const LLVolumeParams &volume_params, const S32 detail, bool unique_volume = false);
+				void	sculpt();
 				void	updateRelativeXform();
 	/*virtual*/ BOOL	updateGeometry(LLDrawable *drawable);
 	/*virtual*/ void	updateFaceSize(S32 idx);
@@ -177,6 +178,7 @@ class LLVOVolume : public LLViewerObject
 	// Flexible Objects
 	U32 getVolumeInterfaceID() const;
 	virtual BOOL isFlexible() const;
+	virtual BOOL isSculpted() const;
 	BOOL isVolumeGlobal() const;
 	BOOL canBeFlexible() const;
 	BOOL setIsFlexible(BOOL is_flexible);
@@ -203,12 +205,14 @@ class LLVOVolume : public LLViewerObject
 	LLFrameTimer mTextureUpdateTimer;
 	S32			mLOD;
 	BOOL		mLODChanged;
+	BOOL		mSculptChanged;
 	F32			mRadius;
 	LLMatrix4	mRelativeXform;
 	LLMatrix3	mRelativeXformInvTrans;
 	BOOL		mVolumeChanged;
 	F32			mVObjRadius;
 	LLVolumeInterface *mVolumeImpl;
+	LLPointer<LLViewerImage> mSculptTexture;
 	
 	// statics
 public:
diff --git a/scripts/messages/message_template.msg b/scripts/messages/message_template.msg
index 8213ed0bc9d4240d7c68fef16748774a8b6c7804..71bbb0ee141d266e0181ac8729abfdc2f3ac6879 100644
--- a/scripts/messages/message_template.msg
+++ b/scripts/messages/message_template.msg
@@ -2122,6 +2122,10 @@ sim -> dataserver
 		{ AnimID		LLUUID }
 		{ StartAnim		BOOL }
 	}
+	{
+		PhysicalAvatarEventList Variable
+		{ TypeData		Variable	1 }
+	}
 }
 
 // AgentRequestSit - Try to sit on an object
@@ -3957,6 +3961,11 @@ sim -> dataserver
 		AnimationSourceList Variable
 		{ ObjectID		LLUUID }
 	}
+	{
+		PhysicalAvatarEventList Variable
+		{ TypeData		Variable	1 }
+	}
+
 }
 
 // AvatarAppearance - Update visual params
@@ -6360,6 +6369,7 @@ sim -> dataserver
 		AgentData			Single
 		{	AgentID			LLUUID	}
 		{	SessionID		LLUUID	}
+		{	TransactionID	LLUUID	}
 	}
 	{
 		InventoryData		Variable
@@ -6400,6 +6410,7 @@ sim -> dataserver
 		AgentData			Single
 		{	AgentID			LLUUID	}
 		{	SimApproved		BOOL	}
+		{	TransactionID	LLUUID	}
 	}
 	{
 		InventoryData		Variable
@@ -6928,6 +6939,11 @@ sim -> dataserver
 // saving into task inventory.
 {
 	DeRezAck Low Trusted Unencoded
+	{
+		TransactionData			Single
+		{	TransactionID	LLUUID	}
+		{	Success			BOOL	}
+	}
 }
 
 // This message is sent from viewer -> simulator when the viewer wants