diff options
| author | Dave Parks <davep@lindenlab.com> | 2011-06-03 00:15:56 -0500 | 
|---|---|---|
| committer | Dave Parks <davep@lindenlab.com> | 2011-06-03 00:15:56 -0500 | 
| commit | f4722b39059147088b9008736370b407daec5d91 (patch) | |
| tree | ad6e700e992a392362061c767d5d96f5638a8b0c /indra | |
| parent | b77e027fcc09937f1d87f02025866a42afa51e39 (diff) | |
| parent | b0a04b08f7b3cf4040b9708125a548e646b990f7 (diff) | |
merge
Diffstat (limited to 'indra')
| -rw-r--r-- | indra/llprimitive/llmodel.cpp | 76 | ||||
| -rw-r--r-- | indra/newview/llfloatermodelpreview.cpp | 160 | ||||
| -rwxr-xr-x | indra/newview/llmeshrepository.cpp | 181 | 
3 files changed, 304 insertions, 113 deletions
| diff --git a/indra/llprimitive/llmodel.cpp b/indra/llprimitive/llmodel.cpp index 3439cf3310..5acf93cfc4 100644 --- a/indra/llprimitive/llmodel.cpp +++ b/indra/llprimitive/llmodel.cpp @@ -50,7 +50,7 @@ std::string model_names[] =  	"low_lod",  	"medium_lod",  	"high_lod", -	"physics_shape" +	"physics_mesh"  };  const int MODEL_NAMES_LENGTH = sizeof(model_names) / sizeof(std::string); @@ -1390,7 +1390,11 @@ LLSD LLModel::writeModel(  	if (!decomp.mBaseHull.empty() ||  		!decomp.mHull.empty())		  	{ -		mdl["decomposition"] = decomp.asLLSD(); +		mdl["physics_convex"] = decomp.asLLSD(); +		if (!decomp.mHull.empty()) +		{ //convex decomposition exists, physics mesh will not be used +			model[LLModel::LOD_PHYSICS] = NULL; +		}  	}  	for (U32 idx = 0; idx < MODEL_NAMES_LENGTH; ++idx) @@ -1449,7 +1453,6 @@ LLSD LLModel::writeModel(  					//position + normal  					for (U32 k = 0; k < 3; ++k)  					{ //for each component -  						//convert to 16-bit normalized across domain  						U16 val = (U16) (((pos[k]-min_pos.mV[k])/pos_range.mV[k])*65535); @@ -1493,7 +1496,6 @@ LLSD LLModel::writeModel(  				//write out face data  				mdl[model_names[idx]][i]["PositionDomain"]["Min"] = min_pos.getValue();  				mdl[model_names[idx]][i]["PositionDomain"]["Max"] = max_pos.getValue(); -  				mdl[model_names[idx]][i]["TexCoord0Domain"]["Min"] = min_tc.getValue();  				mdl[model_names[idx]][i]["TexCoord0Domain"]["Max"] = max_tc.getValue(); @@ -1586,15 +1588,15 @@ LLSD LLModel::writeModelToStream(std::ostream& ostr, LLSD& mdl, BOOL nowrite)  	std::string decomposition; -	if (mdl.has("decomposition")) +	if (mdl.has("physics_convex"))  	{ //write out convex decomposition -		decomposition = zip_llsd(mdl["decomposition"]); +		decomposition = zip_llsd(mdl["physics_convex"]);  		U32 size = decomposition.size();  		if (size > 0)  		{ -			header["decomposition"]["offset"] = (LLSD::Integer) cur_offset; -			header["decomposition"]["size"] = (LLSD::Integer) size; +			header["physics_convex"]["offset"] = (LLSD::Integer) cur_offset; +			header["physics_convex"]["size"] = (LLSD::Integer) size;  			cur_offset += size;  			bytes += size;  		} @@ -1615,11 +1617,6 @@ LLSD LLModel::writeModelToStream(std::ostream& ostr, LLSD& mdl, BOOL nowrite)  			cur_offset += size;  			bytes += size;  		} -		else -		{ -			header[model_names[i]]["offset"] = -1; -			header[model_names[i]]["size"] = 0; -		}  	}  	if (!nowrite) @@ -1633,7 +1630,7 @@ LLSD LLModel::writeModelToStream(std::ostream& ostr, LLSD& mdl, BOOL nowrite)  		if (!decomposition.empty())  		{ //write decomposition block -			ostr.write((const char*) decomposition.data(), header["decomposition"]["size"].asInteger()); +			ostr.write((const char*) decomposition.data(), header["physics_convex"]["size"].asInteger());  		}  		for (S32 i = 0; i < MODEL_NAMES_LENGTH; i++) @@ -1772,7 +1769,7 @@ bool LLModel::loadModel(std::istream& is)  		"low_lod",  		"medium_lod",  		"high_lod", -		"physics_shape", +		"physics_mesh",  	};  	const S32 MODEL_LODS = 5; @@ -1871,8 +1868,8 @@ bool LLModel::loadSkinInfo(LLSD& header, std::istream &is)  bool LLModel::loadDecomposition(LLSD& header, std::istream& is)  { -	S32 offset = header["decomposition"]["offset"].asInteger(); -	S32 size = header["decomposition"]["size"].asInteger(); +	S32 offset = header["physics_convex"]["offset"].asInteger(); +	S32 size = header["physics_convex"]["size"].asInteger();  	if (offset >= 0 && size > 0)  	{ @@ -2012,7 +2009,7 @@ void LLModel::Decomposition::fromLLSD(LLSD& decomp)  	{  		// updated for const-correctness. gcc is picky about this type of thing - Nyx  		const LLSD::Binary& hulls = decomp["HullList"].asBinary(); -		const LLSD::Binary& position = decomp["Position"].asBinary(); +		const LLSD::Binary& position = decomp["Positions"].asBinary();  		U16* p = (U16*) &position[0]; @@ -2022,11 +2019,19 @@ void LLModel::Decomposition::fromLLSD(LLSD& decomp)  		LLVector3 max;  		LLVector3 range; -		min.setValue(decomp["Min"]); -		max.setValue(decomp["Max"]); +		if (decomp.has("Min")) +		{ +			min.setValue(decomp["Min"]); +			max.setValue(decomp["Max"]); +		} +		else +		{ +			min.set(-0.5f, -0.5f, -0.5f); +			max.set(0.5f, 0.5f, 0.5f); +		} +  		range = max-min; -		  		for (U32 i = 0; i < hulls.size(); ++i)  		{  			U16 count = (hulls[i] == 0) ? 256 : hulls[i]; @@ -2042,6 +2047,7 @@ void LLModel::Decomposition::fromLLSD(LLSD& decomp)  				//point must be unique  				//llassert(valid.find(test) == valid.end());  				valid.insert(test); +  				mHull[i].push_back(LLVector3(  					(F32) p[0]/65535.f*range.mV[0]+min.mV[0],  					(F32) p[1]/65535.f*range.mV[1]+min.mV[1], @@ -2056,9 +2062,9 @@ void LLModel::Decomposition::fromLLSD(LLSD& decomp)  		}  	} -	if (decomp.has("Hull")) +	if (decomp.has("BoundingVerts"))  	{ -		const LLSD::Binary& position = decomp["Hull"].asBinary(); +		const LLSD::Binary& position = decomp["BundingVerts"].asBinary();  		U16* p = (U16*) &position[0]; @@ -2113,11 +2119,9 @@ LLSD LLModel::Decomposition::asLLSD() const  	}  	//write decomposition block -	// ["decomposition"]["HullList"] -- list of 8 bit integers, each entry represents a hull with specified number of points -	// ["decomposition"]["PositionDomain"]["Min"/"Max"] -	// ["decomposition"]["Position"] -- list of 16-bit integers to be decoded to given domain, encoded 3D points -	// ["decomposition"]["Hull"] -- list of 16-bit integers to be decoded to given domain, encoded 3D points representing a single hull approximation of given shape -	 +	// ["physics_convex"]["HullList"] -- list of 8 bit integers, each entry represents a hull with specified number of points +	// ["physics_convex"]["Position"] -- list of 16-bit integers to be decoded to given domain, encoded 3D points +	// ["physics_convex"]["BoundingVerts"] -- list of 16-bit integers to be decoded to given domain, encoded 3D points representing a single hull approximation of given shape  	//get minimum and maximum  	LLVector3 min; @@ -2166,6 +2170,8 @@ LLSD LLModel::Decomposition::asLLSD() const  	{  		LLSD::Binary p(total*3*2); +		LLVector3 min(-0.5f, -0.5f, -0.5f); +		LLVector3 max(0.5f, 0.5f, 0.5f);  		LLVector3 range = max-min;  		U32 vert_idx = 0; @@ -2181,8 +2187,12 @@ LLSD LLModel::Decomposition::asLLSD() const  				U64 test = 0;  				for (U32 k = 0; k < 3; k++)  				{ +					F32* src = (F32*) (mHull[i][j].mV); + +					llassert(src[k] <= 0.501f && src[k] >= -0.501f); +  					//convert to 16-bit normalized across domain -					U16 val = (U16) (((mHull[i][j].mV[k]-min.mV[k])/range.mV[k])*65535); +					U16 val = (U16) (((src[k]-min.mV[k])/range.mV[k])*65535);  					if(valid.size() < 3)  					{ @@ -2210,13 +2220,15 @@ LLSD LLModel::Decomposition::asLLSD() const  			llassert(valid.size() > 2);  		} -		ret["Position"] = p; +		ret["Positions"] = p;  	}  	if (!mBaseHull.empty())  	{  		LLSD::Binary p(mBaseHull.size()*3*2); +		LLVector3 min(-0.5f, -0.5f, -0.5f); +		LLVector3 max(0.5f, 0.5f, 0.5f);  		LLVector3 range = max-min;  		U32 vert_idx = 0; @@ -2224,6 +2236,8 @@ LLSD LLModel::Decomposition::asLLSD() const  		{  			for (U32 k = 0; k < 3; k++)  			{ +				llassert(mBaseHull[j].mV[k] <= 0.50001f && mBaseHull[j].mV[k] >= -0.50001f); +  				//convert to 16-bit normalized across domain  				U16 val = (U16) (((mBaseHull[j].mV[k]-min.mV[k])/range.mV[k])*65535); @@ -2239,7 +2253,7 @@ LLSD LLModel::Decomposition::asLLSD() const  			}  		} -		ret["Hull"] = p; +		ret["BoundingVerts"] = p;  	}  	return ret; diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 8be5c427fe..f21d60dd03 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -178,6 +178,80 @@ std::string lod_label_name[NUM_LOD+1] =  	"I went off the end of the lod_label_name array.  Me so smart."  }; + +#define LL_DEGENERACY_TOLERANCE  1e-7f + +inline F32 dot3fpu(const LLVector4a& a, const LLVector4a& b) +{ +    volatile F32 p0 = a[0] * b[0]; +    volatile F32 p1 = a[1] * b[1]; +    volatile F32 p2 = a[2] * b[2]; +    return p0 + p1 + p2; +} + +bool ll_is_degenerate(const LLVector4a& a, const LLVector4a& b, const LLVector4a& c, F32 tolerance = LL_DEGENERACY_TOLERANCE) +{ +        // small area check +        { +                LLVector4a edge1; edge1.setSub( a, b ); +                LLVector4a edge2; edge2.setSub( a, c ); +                ////////////////////////////////////////////////////////////////////////// +                /// Linden Modified +                ////////////////////////////////////////////////////////////////////////// + +                // If no one edge is more than 10x longer than any other edge, we weaken +                // the tolerance by a factor of 1e-4f. + +                LLVector4a edge3; edge3.setSub( c, b ); +				const F32 len1sq = edge1.dot3(edge1).getF32(); +                const F32 len2sq = edge2.dot3(edge2).getF32(); +                const F32 len3sq = edge3.dot3(edge3).getF32(); +                bool abOK = (len1sq <= 100.f * len2sq) && (len1sq <= 100.f * len3sq); +                bool acOK = (len2sq <= 100.f * len1sq) && (len1sq <= 100.f * len3sq); +                bool cbOK = (len3sq <= 100.f * len1sq) && (len1sq <= 100.f * len2sq); +                if ( abOK && acOK && cbOK ) +                { +                        tolerance *= 1e-4f; +                } + +                ////////////////////////////////////////////////////////////////////////// +                /// End Modified +                ////////////////////////////////////////////////////////////////////////// + +                LLVector4a cross; cross.setCross3( edge1, edge2 ); + +                LLVector4a edge1b; edge1b.setSub( b, a ); +                LLVector4a edge2b; edge2b.setSub( b, c ); +                LLVector4a crossb; crossb.setCross3( edge1b, edge2b ); + +                if ( ( cross.dot3(cross).getF32() < tolerance ) || ( crossb.dot3(crossb).getF32() < tolerance )) +                { +                        return true; +                } +        } + +        // point triangle distance check +        { +                LLVector4a Q; Q.setSub(a, b); +                LLVector4a R; R.setSub(c, b); + +                const F32 QQ = dot3fpu(Q, Q); +                const F32 RR = dot3fpu(R, R); +                const F32 QR = dot3fpu(R, Q); + +                volatile F32 QQRR = QQ * RR; +                volatile F32 QRQR = QR * QR; +                F32 Det = (QQRR - QRQR); + +                if( Det == 0.0f ) +                { +                        return true; +                } +        } + +        return false; +} +  bool validate_face(const LLVolumeFace& face)  {  	for (U32 i = 0; i < face.mNumIndices; ++i) @@ -189,6 +263,31 @@ bool validate_face(const LLVolumeFace& face)  		}  	} +	if (face.mNumIndices % 3 != 0 || face.mNumIndices == 0) +	{ +		llwarns << "Face has invalid number of indices." << llendl; +		return false; +	} + +	/*const LLVector4a scale(0.5f); + +	for (U32 i = 0; i < face.mNumIndices; i+=3) +	{ +		U16 idx1 = face.mIndices[i]; +		U16 idx2 = face.mIndices[i+1]; +		U16 idx3 = face.mIndices[i+2]; + +		LLVector4a v1; v1.setMul(face.mPositions[idx1], scale); +		LLVector4a v2; v2.setMul(face.mPositions[idx2], scale); +		LLVector4a v3; v3.setMul(face.mPositions[idx3], scale); + +		if (ll_is_degenerate(v1,v2,v3)) +		{ +			llwarns << "Degenerate face found!" << llendl; +			return false; +		} +	}*/ +  	return true;  } @@ -3784,7 +3883,35 @@ void LLModelPreview::updateStatusMessages()  		mMaxTriangleLimit = total_tris[LLModel::LOD_HIGH];  	} +	bool has_degenerate = false; + +	{//check for degenerate triangles in physics mesh +		U32 lod = LLModel::LOD_PHYSICS; +		const LLVector4a scale(0.5f); +		for (U32 i = 0; i < mModel[lod].size() && !has_degenerate; ++i) +		{ //for each model in the lod +			if (mModel[lod][i]->mPhysics.mHull.empty()) +			{ //no decomp exists +				S32 cur_submeshes = mModel[lod][i]->getNumVolumeFaces(); +				for (S32 j = 0; j < cur_submeshes && !has_degenerate; ++j) +				{ //for each submesh (face), add triangles and vertices to current total +					const LLVolumeFace& face = mModel[lod][i]->getVolumeFace(j); +					for (S32 k = 0; k < face.mNumIndices && !has_degenerate; ) +					{ +						LLVector4a v1; v1.setMul(face.mPositions[face.mIndices[k++]], scale); +						LLVector4a v2; v2.setMul(face.mPositions[face.mIndices[k++]], scale); +						LLVector4a v3; v3.setMul(face.mPositions[face.mIndices[k++]], scale); +						if (ll_is_degenerate(v1,v2,v3)) +						{ +							has_degenerate = true; +						} +					} +				} +			} +		} +	} +	  	mFMP->childSetTextArg("submeshes_info", "[SUBMESHES]", llformat("%d", total_submeshes[LLModel::LOD_HIGH]));  	std::string mesh_status_na = mFMP->getString("mesh_status_na"); @@ -3885,7 +4012,10 @@ void LLModelPreview::updateStatusMessages()  		for (U32 j = 0; upload_ok && j < mdl->mPhysics.mHull.size(); ++j)  		{ -			upload_ok = upload_ok && mdl->mPhysics.mHull[i].size() <= 256; +			if (mdl->mPhysics.mHull[j].size() > 256) +			{ +				upload_ok = false; +			}  		}  	} @@ -3909,7 +4039,7 @@ void LLModelPreview::updateStatusMessages()  	}  	const BOOL confirmed_checkbox = mFMP->getChild<LLCheckBoxCtrl>("confirm_checkbox")->getValue().asBoolean(); -	if ( upload_ok && !errorStateFromLoader && skinAndRigOk && confirmed_checkbox) +	if ( upload_ok && !errorStateFromLoader && skinAndRigOk && !has_degenerate && confirmed_checkbox)  	{  		mFMP->childEnable("ok_btn");  	} @@ -4695,6 +4825,32 @@ BOOL LLModelPreview::render()  							glLineWidth(3.f);  							glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);  							buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); + +							{ //show degenerate triangles +								LLStrider<LLVector3> pos_strider;  +								buffer->getVertexStrider(pos_strider, 0); +								LLVector4a* pos = (LLVector4a*) pos_strider.get(); +							 +								LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS); +								LLGLDisable cull(GL_CULL_FACE); +								LLStrider<U16> idx; +								buffer->getIndexStrider(idx, 0); + +								glColor4f(1.f,0.f,0.f,1.f); +								const LLVector4a scale(0.5f); +								for (U32 i = 0; i < buffer->getNumIndices(); i += 3) +								{ +									LLVector4a v1; v1.setMul(pos[*idx++], scale); +									LLVector4a v2; v2.setMul(pos[*idx++], scale); +									LLVector4a v3; v3.setMul(pos[*idx++], scale); + +									if (ll_is_degenerate(v1,v2,v3)) +									{ +										buffer->draw(LLRender::TRIANGLES, 3, i); +									} +								} +							} +  							glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);  							glLineWidth(1.f);  						} diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 12e0b26fed..d8024b362e 100755 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -62,6 +62,8 @@  #include "llinventorymodel.h"
  #include "llfoldertype.h"
 +#include "boost/lexical_cast.hpp"
 +
  #ifndef LL_WINDOWS
  #include "netdb.h"
  #endif
 @@ -85,6 +87,12 @@ U32 LLMeshRepository::sPeakKbps = 0;  const U32 MAX_TEXTURE_UPLOAD_RETRIES = 5;
 +static S32 dump_num = 0;
 +std::string make_dump_name(std::string prefix, S32 num)
 +{
 +	return prefix + boost::lexical_cast<std::string>(num) + std::string(".xml");
 +	
 +}
  void dumpLLSDToFile(const LLSD& content, std::string filename);
  std::string header_lod[] = 
 @@ -498,7 +506,7 @@ public:  		//assert_main_thread();
  		llinfos << "completed" << llendl;
  		mThread->mPendingUploads--;
 -		dumpLLSDToFile(content,"whole_model_fee_response.xml");
 +		dumpLLSDToFile(content,make_dump_name("whole_model_fee_response_",dump_num));
  		if (isGoodStatus(status))
  		{
  			mThread->mWholeModelUploadURL = content["uploader"].asString(); 
 @@ -530,7 +538,7 @@ public:  		//assert_main_thread();
  		llinfos << "upload completed" << llendl;
  		mThread->mPendingUploads--;
 -		dumpLLSDToFile(content,"whole_model_upload_response.xml");
 +		dumpLLSDToFile(content,make_dump_name("whole_model_upload_response_",dump_num));
  		// requested "mesh" asset type isn't actually the type
  		// of the resultant object, fix it up here.
  		mPostData["asset_type"] = "object";
 @@ -829,8 +837,8 @@ bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id)  	if (header_size > 0)
  	{
 -		S32 offset = header_size + mMeshHeader[mesh_id]["decomposition"]["offset"].asInteger();
 -		S32 size = mMeshHeader[mesh_id]["decomposition"]["size"].asInteger();
 +		S32 offset = header_size + mMeshHeader[mesh_id]["physics_convex"]["offset"].asInteger();
 +		S32 size = mMeshHeader[mesh_id]["physics_convex"]["size"].asInteger();
  		mHeaderMutex->unlock();
 @@ -901,8 +909,8 @@ bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id)  	if (header_size > 0)
  	{
 -		S32 offset = header_size + mMeshHeader[mesh_id]["physics_shape"]["offset"].asInteger();
 -		S32 size = mMeshHeader[mesh_id]["physics_shape"]["size"].asInteger();
 +		S32 offset = header_size + mMeshHeader[mesh_id]["physics_mesh"]["offset"].asInteger();
 +		S32 size = mMeshHeader[mesh_id]["physics_mesh"]["size"].asInteger();
  		mHeaderMutex->unlock();
 @@ -1385,14 +1393,14 @@ BOOL LLMeshUploadThread::isDiscarded()  void LLMeshUploadThread::run()
  {
 -	if (gSavedSettings.getBOOL("MeshUseWholeModelUpload"))
 +	//if (gSavedSettings.getBOOL("MeshUseWholeModelUpload"))
  	{
  		doWholeModelUpload();
  	}
 -	else
 +	/*else
  	{
  		doIterativeUpload();
 -	}
 +	}*/
  }
  void dumpLLSDToFile(const LLSD& content, std::string filename)
 @@ -1431,9 +1439,13 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures)  	{
  		LLMeshUploadData data;
  		data.mBaseModel = iter->first;
 -		LLModelInstance& instance = *(iter->second.begin());
 -		LLModel* model = instance.mModel;
 -		if (mesh_index.find(model) == mesh_index.end())
 +		LLModelInstance& first_instance = *(iter->second.begin());
 +		for (S32 i = 0; i < 5; i++)
 +		{
 +			data.mModel[i] = first_instance.mLOD[i];
 +		}
 +
 +		if (mesh_index.find(data.mBaseModel) == mesh_index.end())
  		{
  			// Have not seen this model before - create a new mesh_list entry for it.
  			std::string model_name = data.mBaseModel->getName();
 @@ -1466,107 +1478,116 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures)  			std::string str = ostr.str();
  			res["mesh_list"][mesh_num] = LLSD::Binary(str.begin(),str.end()); 
 -			mesh_index[model] = mesh_num;
 +			mesh_index[data.mBaseModel] = mesh_num;
  			mesh_num++;
  		}
 +
 +		// For all instances that use this model
 +		for (instance_list::iterator instance_iter = iter->second.begin();
 +			 instance_iter != iter->second.end();
 +			 ++instance_iter)
 +		{
 +
 +			LLModelInstance& instance = *instance_iter;
 -		LLSD instance_entry;
 +			LLSD instance_entry;
 -		for (S32 i = 0; i < 5; i++)
 -		{
 -			data.mModel[i] = instance.mLOD[i];
 -		}
 +			for (S32 i = 0; i < 5; i++)
 +			{
 +				data.mModel[i] = instance.mLOD[i];
 +			}
 -		LLVector3 pos, scale;
 -		LLQuaternion rot;
 -		LLMatrix4 transformation = instance.mTransform;
 -		decomposeMeshMatrix(transformation,pos,rot,scale);
 -		instance_entry["position"] = ll_sd_from_vector3(pos);
 -		instance_entry["rotation"] = ll_sd_from_quaternion(rot);
 -		instance_entry["scale"] = ll_sd_from_vector3(scale);
 +			LLVector3 pos, scale;
 +			LLQuaternion rot;
 +			LLMatrix4 transformation = instance.mTransform;
 +			decomposeMeshMatrix(transformation,pos,rot,scale);
 +			instance_entry["position"] = ll_sd_from_vector3(pos);
 +			instance_entry["rotation"] = ll_sd_from_quaternion(rot);
 +			instance_entry["scale"] = ll_sd_from_vector3(scale);
 -		instance_entry["material"] = LL_MCODE_WOOD;
 -		LLPermissions perm;
 -		perm.setOwnerAndGroup(gAgent.getID(), gAgent.getID(), LLUUID::null, false);
 -		perm.setCreator(gAgent.getID());
 +			instance_entry["material"] = LL_MCODE_WOOD;
 +			LLPermissions perm;
 +			perm.setOwnerAndGroup(gAgent.getID(), gAgent.getID(), LLUUID::null, false);
 +			perm.setCreator(gAgent.getID());
 -		perm.initMasks(PERM_ITEM_UNRESTRICTED | PERM_MOVE, //base
 -					   PERM_ITEM_UNRESTRICTED | PERM_MOVE, //owner
 -					   LLFloaterPerms::getEveryonePerms(),
 -					   LLFloaterPerms::getGroupPerms(),
 -					   LLFloaterPerms::getNextOwnerPerms());
 -		instance_entry["permissions"] = ll_create_sd_from_permissions(perm);
 -		instance_entry["physics_shape_type"] = (U8)(LLViewerObject::PHYSICS_SHAPE_CONVEX_HULL);
 -		instance_entry["mesh"] = mesh_index[model];
 +			perm.initMasks(PERM_ITEM_UNRESTRICTED | PERM_MOVE, //base
 +						   PERM_ITEM_UNRESTRICTED | PERM_MOVE, //owner
 +						   LLFloaterPerms::getEveryonePerms(),
 +						   LLFloaterPerms::getGroupPerms(),
 +						   LLFloaterPerms::getNextOwnerPerms());
 +			instance_entry["permissions"] = ll_create_sd_from_permissions(perm);
 +			instance_entry["physics_shape_type"] = (U8)(LLViewerObject::PHYSICS_SHAPE_CONVEX_HULL);
 +			instance_entry["mesh"] = mesh_index[data.mBaseModel];
 -		if (mUploadTextures)
 -		{
  			instance_entry["face_list"] = LLSD::emptyArray();
 -			for (S32 face_num = 0; face_num < model->getNumVolumeFaces(); face_num++)
 +			for (S32 face_num = 0; face_num < data.mBaseModel->getNumVolumeFaces(); face_num++)
  			{
  				LLImportMaterial& material = instance.mMaterial[face_num];
  				LLSD face_entry = LLSD::emptyMap();
  				LLViewerFetchedTexture *texture = material.mDiffuseMap.get();
 -				if (texture != NULL)
 +				if ((texture != NULL) &&
 +					(textures.find(texture) == textures.end()))
  				{
 -					if (textures.find(texture) == textures.end())
 -					{
 -						textures.insert(texture);
 -					}
 +					textures.insert(texture);
 +				}
 -					std::stringstream ostr;
 -					if (include_textures) // otherwise data is blank.
 +				std::stringstream texture_str;
 +				if (texture != NULL && include_textures && mUploadTextures)
 +				{
 +					// Get binary rep of texture, if needed.
 +					LLTextureUploadData data(texture, material.mDiffuseMapLabel);
 +					if (!data.mTexture->isRawImageValid())
  					{
 -						LLTextureUploadData data(texture, material.mDiffuseMapLabel);
 -						if (!data.mTexture->isRawImageValid())
 -						{
 -							data.mTexture->reloadRawImage(data.mTexture->getDiscardLevel());
 -						}
 -						
 -						LLPointer<LLImageJ2C> upload_file =
 -							LLViewerTextureList::convertToUploadFile(data.mTexture->getRawImage());
 -						ostr.write((const char*) upload_file->getData(), upload_file->getDataSize());
 +						data.mTexture->reloadRawImage(data.mTexture->getDiscardLevel());
  					}
 +						
 +					LLPointer<LLImageJ2C> upload_file =
 +						LLViewerTextureList::convertToUploadFile(data.mTexture->getRawImage());
 +					texture_str.write((const char*) upload_file->getData(), upload_file->getDataSize());
 +				}
 -					if (texture_index.find(texture) == texture_index.end())
 -					{
 -						texture_index[texture] = texture_num;
 -						std::string str = ostr.str();
 -						res["texture_list"][texture_num] = LLSD::Binary(str.begin(),str.end());
 -						texture_num++;
 -					}
 +				if (texture != NULL &&
 +					mUploadTextures &&
 +					texture_index.find(texture) == texture_index.end())
 +				{
 +					texture_index[texture] = texture_num;
 +					std::string str = texture_str.str();
 +					res["texture_list"][texture_num] = LLSD::Binary(str.begin(),str.end());
 +					texture_num++;
  				}
  				// Subset of TextureEntry fields.
 -				if (texture)
 +				if (texture != NULL && mUploadTextures)
  				{
  					face_entry["image"] = texture_index[texture];
 +					face_entry["scales"] = 1.0;
 +					face_entry["scalet"] = 1.0;
 +					face_entry["offsets"] = 0.0;
 +					face_entry["offsett"] = 0.0;
 +					face_entry["imagerot"] = 0.0;
  				}
 -				face_entry["scales"] = 1.0;
 -				face_entry["scalet"] = 1.0;
 -				face_entry["offsets"] = 0.0;
 -				face_entry["offsett"] = 0.0;
 -				face_entry["imagerot"] = 0.0;
  				face_entry["colors"] = ll_sd_from_color4(material.mDiffuseColor);
  				face_entry["fullbright"] = material.mFullbright;
  				instance_entry["face_list"][face_num] = face_entry;
 -			}
 -		}
 +		    }
 -		res["instance_list"][instance_num] = instance_entry;
 -		instance_num++;
 +			res["instance_list"][instance_num] = instance_entry;
 +			instance_num++;
 +		}
  	}
  	result["asset_resources"] = res;
 -	dumpLLSDToFile(result,"whole_model.xml");
 +	dumpLLSDToFile(result,make_dump_name("whole_model_",dump_num));
  	dest = result;
  }
  void LLMeshUploadThread::doWholeModelUpload()
  {
 +	dump_num++;
 +	
  	mCurlRequest = new LLCurlRequest();	
  	// Queue up models for hull generation (viewer-side)
 @@ -1611,7 +1632,7 @@ void LLMeshUploadThread::doWholeModelUpload()  	LLSD model_data;
  	wholeModelToLLSD(model_data,false);
 -	dumpLLSDToFile(model_data,"whole_model_fee_request.xml");
 +	dumpLLSDToFile(model_data,make_dump_name("whole_model_fee_request_",dump_num));
  	mPendingUploads++;
  	LLCurlRequest::headers_t headers;
 @@ -1633,7 +1654,7 @@ void LLMeshUploadThread::doWholeModelUpload()  		LLSD full_model_data;
  		wholeModelToLLSD(full_model_data, true);
  		LLSD body = full_model_data["asset_resources"];
 -		dumpLLSDToFile(body,"whole_model_body.xml");
 +		dumpLLSDToFile(body,make_dump_name("whole_model_body_",dump_num));
  		mCurlRequest->post(mWholeModelUploadURL, headers, body,
  						   new LLWholeModelUploadResponder(this, model_data));
  		do
 @@ -2234,7 +2255,7 @@ void LLMeshHeaderResponder::completedRaw(U32 status, const std::string& reason,  		//just in case skin info or decomposition is at the end of the file (which it shouldn't be)
  		lod_bytes = llmax(lod_bytes, header["skin"]["offset"].asInteger() + header["skin"]["size"].asInteger());
 -		lod_bytes = llmax(lod_bytes, header["decomposition"]["offset"].asInteger() + header["decomposition"]["size"].asInteger());
 +		lod_bytes = llmax(lod_bytes, header["physics_convex"]["offset"].asInteger() + header["physics_convex"]["size"].asInteger());
  		S32 header_bytes = (S32) gMeshRepo.mThread->mMeshHeaderSize[mesh_id];
  		S32 bytes = lod_bytes + header_bytes; 
 @@ -2860,7 +2881,7 @@ void LLMeshRepository::buildHull(const LLVolumeParams& params, S32 detail)  bool LLMeshRepository::hasPhysicsShape(const LLUUID& mesh_id)
  {
  	LLSD mesh = mThread->getMeshHeader(mesh_id);
 -	return mesh.has("physics_shape") && mesh["physics_shape"].has("size") && (mesh["physics_shape"]["size"].asInteger() > 0);
 +	return mesh.has("physics_mesh") && mesh["physics_mesh"].has("size") && (mesh["physics_mesh"]["size"].asInteger() > 0);
  }
  LLSD& LLMeshRepository::getMeshHeader(const LLUUID& mesh_id)
 @@ -3314,8 +3335,8 @@ bool LLImportMaterial::operator<(const LLImportMaterial &rhs) const  void LLMeshRepository::updateInventory(inventory_data data)
  {
  	LLMutexLock lock(mMeshMutex);
 -	dumpLLSDToFile(data.mPostData,"update_inventory_post_data.xml");
 -	dumpLLSDToFile(data.mResponse,"update_inventory_response.xml");
 +	dumpLLSDToFile(data.mPostData,make_dump_name("update_inventory_post_data_",dump_num));
 +	dumpLLSDToFile(data.mResponse,make_dump_name("update_inventory_response_",dump_num));
  	mInventoryQ.push(data);
  }
 | 
