diff options
| author | Leyla Farazha <leyla@lindenlab.com> | 2011-03-29 16:33:47 -0700 | 
|---|---|---|
| committer | Leyla Farazha <leyla@lindenlab.com> | 2011-03-29 16:33:47 -0700 | 
| commit | ac4e4607b8bde0fa05af75da5f873ef42e3c5918 (patch) | |
| tree | d7c4e24a69d2b4e3a8d5bbe333795db98c4cb156 | |
| parent | e69aa18c0dfbef2fa3bbefeba08fa1c258c69fb3 (diff) | |
| parent | 1aecac62eb88125546057be2a2a70a6b2eba1a57 (diff) | |
Merge
| -rw-r--r-- | indra/llmath/llvolume.cpp | 50 | ||||
| -rw-r--r-- | indra/llmath/llvolume.h | 2 | ||||
| -rwxr-xr-x | indra/llprimitive/llmodel.cpp | 464 | ||||
| -rwxr-xr-x | indra/llprimitive/llmodel.h | 79 | ||||
| -rw-r--r-- | indra/llrender/llvertexbuffer.cpp | 16 | ||||
| -rw-r--r-- | indra/llrender/llvertexbuffer.h | 2 | ||||
| -rwxr-xr-x | indra/newview/llfloatermodelpreview.cpp | 134 | ||||
| -rw-r--r-- | indra/newview/llfloatermodelpreview.h | 3 | ||||
| -rw-r--r-- | indra/newview/llfloatermodelwizard.cpp | 1 | ||||
| -rwxr-xr-x | indra/newview/llmeshrepository.cpp | 332 | ||||
| -rw-r--r-- | indra/newview/llmeshrepository.h | 40 | ||||
| -rw-r--r-- | indra/newview/llspatialpartition.cpp | 51 | ||||
| -rw-r--r-- | indra/newview/llvoavatar.cpp | 5 | ||||
| -rw-r--r-- | indra/newview/llvoavatar.h | 1 | ||||
| -rw-r--r-- | indra/newview/skins/minimal/xui/de/menu_inspect_self_gear.xml | 2 | ||||
| -rw-r--r-- | indra/newview/skins/minimal/xui/es/menu_inspect_self_gear.xml | 2 | ||||
| -rw-r--r-- | indra/newview/skins/minimal/xui/fr/menu_inspect_self_gear.xml | 2 | ||||
| -rw-r--r-- | indra/newview/skins/minimal/xui/pt/menu_inspect_self_gear.xml | 2 | 
18 files changed, 643 insertions, 545 deletions
| diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index 7a2f06da8f..dc360818d6 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -2143,56 +2143,6 @@ bool LLVolumeFace::VertexData::compareNormal(const LLVolumeFace::VertexData& rhs  	return retval;
  }
 -BOOL LLVolume::createVolumeFacesFromFile(const std::string& file_name)
 -{
 -	std::ifstream is;
 -	
 -	is.open(file_name.c_str(), std::ifstream::in | std::ifstream::binary);
 -
 -	BOOL success = createVolumeFacesFromStream(is);
 -	
 -	is.close();
 -
 -	return success;
 -}
 -
 -BOOL LLVolume::createVolumeFacesFromStream(std::istream& is)
 -{
 -	mSculptLevel = -1;  // default is an error occured
 -
 -	LLSD header;
 -	{
 -		if (!LLSDSerialize::fromBinary(header, is, 1024*1024*1024))
 -		{
 -			llwarns << "Mesh header parse error.  Not a valid mesh asset!" << llendl;
 -			return FALSE;
 -		}
 -	}
 -	
 -	std::string nm[] = 
 -	{
 -		"lowest_lod",
 -		"low_lod",
 -		"medium_lod",
 -		"high_lod",
 -		"physics_shape",
 -	};
 -
 -	const S32 MODEL_LODS = 5;
 -
 -	S32 lod = llclamp((S32) mDetail, 0, MODEL_LODS);
 -
 -	if (header[nm[lod]]["offset"].asInteger() == -1 || 
 -		header[nm[lod]]["size"].asInteger() == 0 )
 -	{ //cannot load requested LOD
 -		return FALSE;
 -	}
 -
 -	is.seekg(header[nm[lod]]["offset"].asInteger(), std::ios_base::cur);
 -
 -	return unpackVolumeFaces(is, header[nm[lod]]["size"].asInteger());
 -}
 -
  bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size)
  {
  	//input stream is now pointing at a zlib compressed block of LLSD
 diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h index 60b64b1285..01bfbd858b 100644 --- a/indra/llmath/llvolume.h +++ b/indra/llmath/llvolume.h @@ -1048,8 +1048,6 @@ protected:  	BOOL generate();  	void createVolumeFaces();  public: -	virtual BOOL createVolumeFacesFromFile(const std::string& file_name); -	virtual BOOL createVolumeFacesFromStream(std::istream& is);  	virtual bool unpackVolumeFaces(std::istream& is, S32 size);  	virtual void makeTetrahedron(); diff --git a/indra/llprimitive/llmodel.cpp b/indra/llprimitive/llmodel.cpp index 3669fef0dc..595f9aa307 100755 --- a/indra/llprimitive/llmodel.cpp +++ b/indra/llprimitive/llmodel.cpp @@ -775,43 +775,6 @@ BOOL LLModel::createVolumeFacesFromDomMesh(domMesh* mesh)  	return FALSE;  } - -BOOL LLModel::createVolumeFacesFromFile(const std::string& file_name) -{ -	DAE dae; -	domCOLLADA* dom = dae.open(file_name); -	if (dom) -	{ -		daeDatabase* db = dae.getDatabase(); - -		daeInt count = db->getElementCount(NULL, COLLADA_TYPE_MESH); -		 -		mVolumeFaces.clear(); -		mMaterialList.clear(); - -		for (daeInt idx = 0; idx < count; ++idx) -		{ -			domMesh* mesh = NULL; - -			db->getElement((daeElement**) &mesh, idx, NULL, COLLADA_TYPE_MESH); -			 -			if (mesh) -			{ -				addVolumeFacesFromDomMesh(mesh); -			} -		} - -		if (getNumVolumeFaces() > 0) -		{ -			optimizeVolumeFaces(); -			normalizeVolumeFaces(); -			return TRUE; -		} -	} - -	return FALSE; -} -  void LLModel::offsetMesh( const LLVector3& pivotPoint )  {  	LLVector4a pivot( pivotPoint[VX], pivotPoint[VY], pivotPoint[VZ] ); @@ -1352,16 +1315,6 @@ std::string LLModel::getElementLabel(daeElement *element)  }  //static  -LLModel* LLModel::loadModelFromDae(std::string filename) -{ -	LLVolumeParams volume_params; -	volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); -	LLModel* ret = new LLModel(volume_params, 0.f);  -	ret->createVolumeFacesFromFile(filename); -	return ret; -} - -//static   LLModel* LLModel::loadModelFromDomMesh(domMesh *mesh)  {  	LLVolumeParams volume_params; @@ -1473,49 +1426,7 @@ LLSD LLModel::writeModel(  	if (skinning)  	{ //write skinning block -		if (high->mJointList.size() != high->mInvBindMatrix.size()) -		{ -			llerrs << "WTF?" << llendl; -		} - -		for (U32 i = 0; i < high->mJointList.size(); ++i) -		{ -			mdl["skin"]["joint_names"][i] = high->mJointList[i]; - -			for (U32 j = 0; j < 4; j++) -			{ -				for (U32 k = 0; k < 4; k++) -				{ -					mdl["skin"]["inverse_bind_matrix"][i][j*4+k] = high->mInvBindMatrix[i].mMatrix[j][k];  -				} -			} -		} - -		for (U32 i = 0; i < 4; i++) -		{ -			for (U32 j = 0; j < 4; j++) -			{ -				mdl["skin"]["bind_shape_matrix"][i*4+j] = high->mBindShapeMatrix.mMatrix[i][j]; -			} -		} -		 -		 -		if ( upload_joints && high->mAlternateBindMatrix.size() > 0 ) -		{ -			for (U32 i = 0; i < high->mJointList.size(); ++i) -			{ -				for (U32 j = 0; j < 4; j++) -				{ -					for (U32 k = 0; k < 4; k++) -					{ -						mdl["skin"]["alt_inverse_bind_matrix"][i][j*4+k] = high->mAlternateBindMatrix[i].mMatrix[j][k];  -					} -				} -			} - -			mdl["skin"]["pelvis_offset"] = high->mPelvisOffset; -		} -		 +		mdl["skin"] = high->mSkinInfo.asLLSD(upload_joints);  	}  	if (!decomp.empty() || !base_hull.empty()) @@ -1897,12 +1808,6 @@ LLSD LLModel::writeModelToStream(std::ostream& ostr, LLSD& mdl, BOOL nowrite)  	return header;  } -//static  -LLModel* LLModel::loadModelFromAsset(std::string filename, S32 lod) -{ -	return NULL; -} -  LLModel::weight_list& LLModel::getJointInfluences(const LLVector3& pos)  {  	weight_map::iterator iter = mSkinWeights.find(pos); @@ -1976,27 +1881,380 @@ LLModel::weight_list& LLModel::getJointInfluences(const LLVector3& pos)  void LLModel::setConvexHullDecomposition(  	const LLModel::convex_hull_decomposition& decomp)  { -	mConvexHullDecomp = decomp; +	mPhysics.mHull = decomp; +	mPhysics.mMesh.clear(); +	updateHullCenters(); +} -	mHullCenter.resize(mConvexHullDecomp.size()); +void LLModel::updateHullCenters() +{ +	mHullCenter.resize(mPhysics.mHull.size());  	mHullPoints = 0;  	mCenterOfHullCenters.clear(); -	for (U32 i = 0; i < decomp.size(); ++i) +	for (U32 i = 0; i < mPhysics.mHull.size(); ++i)  	{  		LLVector3 cur_center; -		for (U32 j = 0; j < decomp[i].size(); ++j) +		for (U32 j = 0; j < mPhysics.mHull[i].size(); ++j)  		{ -			cur_center += decomp[i][j]; +			cur_center += mPhysics.mHull[i][j];  		}  		mCenterOfHullCenters += cur_center; -		cur_center *= 1.f/decomp[i].size(); +		cur_center *= 1.f/mPhysics.mHull[i].size();  		mHullCenter[i] = cur_center; -		mHullPoints += decomp[i].size(); +		mHullPoints += mPhysics.mHull[i].size();  	}  	mCenterOfHullCenters *= 1.f / mHullPoints;  } +bool LLModel::loadModel(std::istream& is)
 +{
 +	mSculptLevel = -1;  // default is an error occured
 +
 +	LLSD header;
 +	{
 +		if (!LLSDSerialize::fromBinary(header, is, 1024*1024*1024))
 +		{
 +			llwarns << "Mesh header parse error.  Not a valid mesh asset!" << llendl;
 +			return false;
 +		}
 +	}
 +	
 +	std::string nm[] = 
 +	{
 +		"lowest_lod",
 +		"low_lod",
 +		"medium_lod",
 +		"high_lod",
 +		"physics_shape",
 +	};
 +
 +	const S32 MODEL_LODS = 5;
 +
 +	S32 lod = llclamp((S32) mDetail, 0, MODEL_LODS);
 +
 +	if (header[nm[lod]]["offset"].asInteger() == -1 || 
 +		header[nm[lod]]["size"].asInteger() == 0 )
 +	{ //cannot load requested LOD
 +		return false;
 +	}
 +
 +	bool has_skin = header["skin"]["offset"].asInteger() >=0 &&
 +					header["skin"]["size"].asInteger() > 0;
 +
 +	if (lod == LLModel::LOD_HIGH)
 +	{ //try to load skin info and decomp info
 +		std::ios::pos_type cur_pos = is.tellg();
 +		loadSkinInfo(header, is);
 +		is.seekg(cur_pos);
 +	}
 +
 +	if (lod == LLModel::LOD_PHYSICS)
 +	{
 +		std::ios::pos_type cur_pos = is.tellg();
 +		loadDecomposition(header, is);
 +		is.seekg(cur_pos);
 +	}
 +
 +	is.seekg(header[nm[lod]]["offset"].asInteger(), std::ios_base::cur);
 +
 +	if (unpackVolumeFaces(is, header[nm[lod]]["size"].asInteger()))
 +	{
 +		if (has_skin)
 +		{ 
 +			//build out mSkinWeight from face info
 +			for (S32 i = 0; i < getNumVolumeFaces(); ++i)
 +			{
 +				const LLVolumeFace& face = getVolumeFace(i);
 +
 +				if (face.mWeights)
 +				{
 +					for (S32 j = 0; j < face.mNumVertices; ++j)
 +					{
 +						LLVector4a& w = face.mWeights[j];
 +
 +						std::vector<JointWeight> wght;
 +
 +						for (S32 k = 0; k < 4; ++k)
 +						{
 +							S32 idx = (S32) w[k];
 +							F32 f = w[k] - idx;
 +							if (f > 0.f)
 +							{
 +								wght.push_back(JointWeight(idx, f));
 +							}
 +						}
 +
 +						if (!wght.empty())
 +						{
 +							LLVector3 pos(face.mPositions[j].getF32ptr());
 +							mSkinWeights[pos] = wght;
 +						}
 +					}
 +				}
 +			}
 +		}
 +		return true;
 +	}
 +
 +	return false;
 +
 +}
 + + +bool LLModel::loadSkinInfo(LLSD& header, std::istream &is) +{ +	S32 offset = header["skin"]["offset"].asInteger(); +	S32 size = header["skin"]["size"].asInteger(); + +	if (offset >= 0 && size > 0) +	{ +		is.seekg(offset, std::ios_base::cur); + +		LLSD skin_data; + +		if (unzip_llsd(skin_data, is, size)) +		{ +			mSkinInfo.fromLLSD(skin_data); +			return true; +		} +	} + +	return false; +} + +bool LLModel::loadDecomposition(LLSD& header, std::istream& is) +{ +	S32 offset = header["decomposition"]["offset"].asInteger(); +	S32 size = header["decomposition"]["size"].asInteger(); + +	if (offset >= 0 && size > 0) +	{ +		is.seekg(offset, std::ios_base::cur); + +		LLSD data; + +		if (unzip_llsd(data, is, size)) +		{ +			mPhysics.fromLLSD(data); +			updateHullCenters(); +		} +	} + +	return true; +} + + +LLMeshSkinInfo::LLMeshSkinInfo(LLSD& skin) +{ +	fromLLSD(skin); +} + +void LLMeshSkinInfo::fromLLSD(LLSD& skin) +{ +	if (skin.has("joint_names")) +	{ +		for (U32 i = 0; i < skin["joint_names"].size(); ++i) +		{ +			mJointNames.push_back(skin["joint_names"][i]); +		} +	} + +	if (skin.has("inverse_bind_matrix")) +	{ +		for (U32 i = 0; i < skin["inverse_bind_matrix"].size(); ++i) +		{ +			LLMatrix4 mat; +			for (U32 j = 0; j < 4; j++) +			{ +				for (U32 k = 0; k < 4; k++) +				{ +					mat.mMatrix[j][k] = skin["inverse_bind_matrix"][i][j*4+k].asReal(); +				} +			} + +			mInvBindMatrix.push_back(mat); +		} +	} + +	if (skin.has("bind_shape_matrix")) +	{ +		for (U32 j = 0; j < 4; j++) +		{ +			for (U32 k = 0; k < 4; k++) +			{ +				mBindShapeMatrix.mMatrix[j][k] = skin["bind_shape_matrix"][j*4+k].asReal(); +			} +		} +	} + +	if (skin.has("alt_inverse_bind_matrix")) +	{ +		for (U32 i = 0; i < skin["alt_inverse_bind_matrix"].size(); ++i) +		{ +			LLMatrix4 mat; +			for (U32 j = 0; j < 4; j++) +			{ +				for (U32 k = 0; k < 4; k++) +				{ +					mat.mMatrix[j][k] = skin["alt_inverse_bind_matrix"][i][j*4+k].asReal(); +				} +			} +			 +			mAlternateBindMatrix.push_back(mat); +		} +	} + +	if (skin.has("pelvis_offset")) +	{ +		mPelvisOffset = skin["pelvis_offset"].asReal(); +	} +} + +LLSD LLMeshSkinInfo::asLLSD(bool include_joints) const +{ +	LLSD ret; + +	for (U32 i = 0; i < mJointNames.size(); ++i) +	{ +		ret["joint_names"][i] = mJointNames[i]; + +		for (U32 j = 0; j < 4; j++) +		{ +			for (U32 k = 0; k < 4; k++) +			{ +				ret["inverse_bind_matrix"][i][j*4+k] = mInvBindMatrix[i].mMatrix[j][k];  +			} +		} +	} + +	for (U32 i = 0; i < 4; i++) +	{ +		for (U32 j = 0; j < 4; j++) +		{ +			ret["bind_shape_matrix"][i*4+j] = mBindShapeMatrix.mMatrix[i][j]; +		} +	} +		 +	if ( include_joints && mAlternateBindMatrix.size() > 0 ) +	{ +		for (U32 i = 0; i < mJointNames.size(); ++i) +		{ +			for (U32 j = 0; j < 4; j++) +			{ +				for (U32 k = 0; k < 4; k++) +				{ +					ret["alt_inverse_bind_matrix"][i][j*4+k] = mAlternateBindMatrix[i].mMatrix[j][k];  +				} +			} +		} + +		ret["pelvis_offset"] = mPelvisOffset; +	} + +	return ret; +} + +LLModel::Decomposition::Decomposition(LLSD& data) +{ +	fromLLSD(data); +} + +void LLModel::Decomposition::fromLLSD(LLSD& decomp) +{ +	if (decomp.has("HullList")) +	{ +		// 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(); + +		U16* p = (U16*) &position[0]; + +		mHull.resize(hulls.size()); + +		LLVector3 min; +		LLVector3 max; +		LLVector3 range; + +		min.setValue(decomp["Min"]); +		max.setValue(decomp["Max"]); +		range = max-min; + +		for (U32 i = 0; i < hulls.size(); ++i) +		{ +			U16 count = (hulls[i] == 0) ? 256 : hulls[i]; +			 +			for (U32 j = 0; j < count; ++j) +			{ +				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], +					(F32) p[2]/65535.f*range.mV[2]+min.mV[2])); +				p += 3; +			}		  + +		} +	} + +	if (decomp.has("Hull")) +	{ +		const LLSD::Binary& position = decomp["Hull"].asBinary(); + +		U16* p = (U16*) &position[0]; + +		LLVector3 min; +		LLVector3 max; +		LLVector3 range; + +		min.setValue(decomp["Min"]); +		max.setValue(decomp["Max"]); +		range = max-min; + +		U16 count = position.size()/6; +		 +		for (U32 j = 0; j < count; ++j) +		{ +			mBaseHull.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], +				(F32) p[2]/65535.f*range.mV[2]+min.mV[2])); +			p += 3; +		}		  +	} +	else +	{ +		//empty base hull mesh to indicate decomposition has been loaded +		//but contains no base hull +		mBaseHullMesh.clear();; +	} + +} + +void LLModel::Decomposition::merge(const LLModel::Decomposition* rhs) +{ +	if (!rhs) +	{ +		return; +	} + +	if (mMeshID != rhs->mMeshID) +	{ +		llerrs << "Attempted to merge with decomposition of some other mesh." << llendl; +	} + +	if (mBaseHull.empty()) +	{ //take base hull and decomposition from rhs +		mHull = rhs->mHull; +		mBaseHull = rhs->mBaseHull; +		mMesh = rhs->mMesh; +		mBaseHullMesh = rhs->mBaseHullMesh; +	} + +	if (mPhysicsShapeMesh.empty()) +	{ //take physics shape mesh from rhs +		mPhysicsShapeMesh = rhs->mPhysicsShapeMesh; +	} +} diff --git a/indra/llprimitive/llmodel.h b/indra/llprimitive/llmodel.h index addf527d8d..e9450d2967 100755 --- a/indra/llprimitive/llmodel.h +++ b/indra/llprimitive/llmodel.h @@ -27,6 +27,7 @@  #ifndef LL_LLMODEL_H  #define LL_LLMODEL_H +#include "llpointer.h"  #include "llvolume.h"  #include "v4math.h"  #include "m4math.h" @@ -36,6 +37,24 @@ class domMesh;  #define MAX_MODEL_FACES 8 + +class LLMeshSkinInfo  +{ +public: +	LLUUID mMeshID; +	std::vector<std::string> mJointNames; +	std::vector<LLMatrix4> mInvBindMatrix; +	std::vector<LLMatrix4> mAlternateBindMatrix; +	std::map<std::string, U32> mJointMap; + +	LLMeshSkinInfo() { } +	LLMeshSkinInfo(LLSD& data); +	void fromLLSD(LLSD& data); +	LLSD asLLSD(bool include_joints) const; +	LLMatrix4 mBindShapeMatrix; +	float mPelvisOffset; +}; +  class LLModel : public LLVolume  {  public: @@ -58,6 +77,9 @@ public:  	LLModel(LLVolumeParams& params, F32 detail);  	~LLModel(); +	bool loadModel(std::istream& is); +	bool loadSkinInfo(LLSD& header, std::istream& is); +	bool loadDecomposition(LLSD& header, std::istream& is);  	static LLSD writeModel(  		std::string filename,  		LLModel* physics, @@ -98,8 +120,6 @@ public:  		LLSD& mdl,  		BOOL nowrite = FALSE); -	static LLModel* loadModelFromAsset(std::string filename, S32 lod); -	static LLModel* loadModelFromDae(std::string filename);  	static LLModel* loadModelFromDomMesh(domMesh* mesh);  	static std::string getElementLabel(daeElement* element);  	std::string getName() const; @@ -177,17 +197,8 @@ public:  	//get list of weight influences closest to given position  	weight_list& getJointInfluences(const LLVector3& pos); -	//should always be true that mJointList[mJointMap["foo"]] == "foo" - -	//map of joint names to joint index -	std::map<std::string, U32> mJointMap; - -	//list of joint names -	std::vector<std::string> mJointList; - -	LLMatrix4 mBindShapeMatrix; -	std::vector<LLMatrix4> mInvBindMatrix; -	std::vector<LLMatrix4> mAlternateBindMatrix; +	LLMeshSkinInfo mSkinInfo; +	  	std::string mRequestedLabel; // name requested in UI, if any.  	std::string mLabel; // name computed from dae. @@ -197,9 +208,10 @@ public:  	float	mPelvisOffset;  	// convex hull decomposition  	S32 mDecompID; -	convex_hull_decomposition mConvexHullDecomp; +	  	void setConvexHullDecomposition(  		const convex_hull_decomposition& decomp); +	void updateHullCenters();  	LLVector3 mCenterOfHullCenters;  	std::vector<LLVector3> mHullCenter; @@ -208,9 +220,46 @@ public:  	//ID for storing this model in a .slm file  	S32 mLocalID; +	class PhysicsMesh +	{ +	public: +		std::vector<LLVector3> mPositions; +		std::vector<LLVector3> mNormals; + +		void clear() +		{ +			mPositions.clear(); +			mNormals.clear(); +		} + +		bool empty() const +		{ +			return mPositions.empty(); +		} +	}; + +	class Decomposition +	{ +	public: +		Decomposition() { } +		Decomposition(LLSD& data); +		void fromLLSD(LLSD& data); +		 +		void merge(const Decomposition* rhs); + +		LLUUID mMeshID; +		LLModel::convex_hull_decomposition mHull; +		LLModel::hull mBaseHull; + +		std::vector<LLModel::PhysicsMesh> mMesh; +		LLModel::PhysicsMesh mBaseHullMesh; +		LLModel::PhysicsMesh mPhysicsShapeMesh; +	}; + +	Decomposition mPhysics; +  protected:  	void addVolumeFacesFromDomMesh(domMesh* mesh); -	virtual BOOL createVolumeFacesFromFile(const std::string& file_name);  	virtual BOOL createVolumeFacesFromDomMesh(domMesh *mesh);  }; diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp index 0d3f5b81bc..73efbfc999 100644 --- a/indra/llrender/llvertexbuffer.cpp +++ b/indra/llrender/llvertexbuffer.cpp @@ -236,6 +236,22 @@ void LLVertexBuffer::setupClientArrays(U32 data_mask)  	}  } +//static +void LLVertexBuffer::drawArrays(U32 mode, const std::vector<LLVector3>& pos, const std::vector<LLVector3>& norm) +{ +	U32 count = pos.size(); +	llassert(norm.size() >= pos.size()); + +	unbind(); +	 +	setupClientArrays(MAP_VERTEX | MAP_NORMAL); + +	glVertexPointer(3, GL_FLOAT, 0, pos[0].mV); +	glNormalPointer(GL_FLOAT, 0, norm[0].mV); + +	glDrawArrays(sGLMode[mode], 0, count); +} +  void LLVertexBuffer::validateRange(U32 start, U32 end, U32 count, U32 indices_offset) const  {  	if (start >= (U32) mRequestedNumVerts || diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h index 2bbc17fb12..6c0895512e 100644 --- a/indra/llrender/llvertexbuffer.h +++ b/indra/llrender/llvertexbuffer.h @@ -97,6 +97,8 @@ public:  	static void initClass(bool use_vbo, bool no_vbo_mapping);  	static void cleanupClass();  	static void setupClientArrays(U32 data_mask); +	static void drawArrays(U32 mode, const std::vector<LLVector3>& pos, const std::vector<LLVector3>& norm); +   	static void clientCopy(F64 max_time = 0.005); //copy data from client to GL  	static void unbind(); //unbind any bound vertex buffer diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 4d498840fe..a2a25105bc 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -389,7 +389,11 @@ LLFloaterModelPreview::~LLFloaterModelPreview()  		gAgentAvatarp->resetJointPositions();  	} +	 +	if ( mModelPreview ) +	{  	delete mModelPreview; +	}  	if (mGLName)  	{ @@ -1326,17 +1330,19 @@ bool LLModelLoader::doLoadModel()  						{ //get bind shape matrix  							domFloat4x4& dom_value = bind_mat->getValue(); +							LLMeshSkinInfo& skin_info = model->mSkinInfo; +  							for (int i = 0; i < 4; i++)  							{  								for(int j = 0; j < 4; j++)  								{ -									model->mBindShapeMatrix.mMatrix[i][j] = dom_value[i + j*4]; +									skin_info.mBindShapeMatrix.mMatrix[i][j] = dom_value[i + j*4];  								}  							}  							LLMatrix4 trans = normalized_transformation; -							trans *= model->mBindShapeMatrix; -							model->mBindShapeMatrix = trans; +							trans *= skin_info.mBindShapeMatrix; +							skin_info.mBindShapeMatrix = trans;  						} @@ -1475,7 +1481,7 @@ bool LLModelLoader::doLoadModel()  							xsNMTOKEN semantic = input->getSemantic();  							if (strcmp(semantic, COMMON_PROFILE_INPUT_JOINT) == 0) -							{ //found joint source, fill model->mJointMap and model->mJointList +							{ //found joint source, fill model->mJointMap and model->mSkinInfo.mJointNames  								daeElement* elem = input->getSource().getElement();  								domSource* source = daeSafeCast<domSource>(elem); @@ -1496,8 +1502,8 @@ bool LLModelLoader::doLoadModel()  											{  												name = mJointMap[name];  											} -											model->mJointList.push_back(name); -											model->mJointMap[name] = j; +											model->mSkinInfo.mJointNames.push_back(name); +											model->mSkinInfo.mJointMap[name] = j;  										}  									}  									else @@ -1514,8 +1520,8 @@ bool LLModelLoader::doLoadModel()  												{  													name = mJointMap[name];  												} -												model->mJointList.push_back(name); -												model->mJointMap[name] = j; +												model->mSkinInfo.mJointNames.push_back(name); +												model->mSkinInfo.mJointMap[name] = j;  											}  										}  									} @@ -1544,7 +1550,7 @@ bool LLModelLoader::doLoadModel()  												}  											} -											model->mInvBindMatrix.push_back(mat); +											model->mSkinInfo.mInvBindMatrix.push_back(mat);  										}  									}  								} @@ -1555,8 +1561,8 @@ bool LLModelLoader::doLoadModel()  						//(which means we have all the joints that are required for an avatar versus  						//a skinned asset attached to a node in a file that contains an entire skeleton,  						//but does not use the skeleton). -						mPreview->setRigValid( doesJointArrayContainACompleteRig( model->mJointList ) ); -							if ( !skeletonWithNoRootNode && !model->mJointList.empty() && mPreview->isRigValid() )  +						mPreview->setRigValid( doesJointArrayContainACompleteRig( model->mSkinInfo.mJointNames ) ); +						if ( !skeletonWithNoRootNode && !model->mSkinInfo.mJointNames.empty() && mPreview->isRigValid() )   						{  							mResetJoints = true;  						} @@ -1596,8 +1602,8 @@ bool LLModelLoader::doLoadModel()  						//in the same order as they were stored in the joint buffer. The joints associated  						//with the skeleton are not stored in the same order as they are in the exported joint buffer.  						//This remaps the skeletal joints to be in the same order as the joints stored in the model. -						std::vector<std::string> :: const_iterator jointIt  = model->mJointList.begin(); -						const int jointCnt = model->mJointList.size(); +						std::vector<std::string> :: const_iterator jointIt  = model->mSkinInfo.mJointNames.begin(); +						const int jointCnt = model->mSkinInfo.mJointNames.size();  						for ( int i=0; i<jointCnt; ++i, ++jointIt )  						{  							std::string lookingForJoint = (*jointIt).c_str(); @@ -1606,9 +1612,9 @@ bool LLModelLoader::doLoadModel()  							if ( jointTransforms.find( lookingForJoint ) != jointTransforms.end() )  							{  								LLMatrix4 jointTransform = jointTransforms[lookingForJoint]; -								LLMatrix4 newInverse = model->mInvBindMatrix[i]; +								LLMatrix4 newInverse = model->mSkinInfo.mInvBindMatrix[i];  								newInverse.setTranslation( jointTransforms[lookingForJoint].getTranslation() ); -								model->mAlternateBindMatrix.push_back( newInverse ); +								model->mSkinInfo.mAlternateBindMatrix.push_back( newInverse );  							}  							else  							{ @@ -1813,10 +1819,15 @@ bool LLModelLoader::loadFromSLM(const std::string& filename)  		{  			std::stringstream str(mesh[i].asString());  			LLPointer<LLModel> loaded_model = new LLModel(volume_params, (F32) lod); -			if (loaded_model->createVolumeFacesFromStream(str)) +			if (loaded_model->loadModel(str))  			{  				loaded_model->mLocalID = i;  				model[lod].push_back(loaded_model); + +				if (lod == LLModel::LOD_HIGH && !loaded_model->mSkinInfo.mJointNames.empty()) +				{ //check to see if rig is valid +					mPreview->setRigValid( doesJointArrayContainACompleteRig( loaded_model->mSkinInfo.mJointNames ) ); +				}  			}  			else  			{ @@ -1878,8 +1889,6 @@ void LLModelLoader::loadModelCallback()  	{ //wait until this thread is stopped before deleting self  		apr_sleep(100);  	} - -	delete this;  }  void LLModelLoader::handlePivotPoint( daeElement* pRoot ) @@ -2455,6 +2464,7 @@ LLModelPreview::~LLModelPreview()  {  	if (mModelLoader)  	{ +		delete mModelLoader;  		mModelLoader->mPreview = NULL;  	}  	//*HACK : *TODO : turn this back on when we understand why this crashes @@ -2510,8 +2520,8 @@ U32 LLModelPreview::calcResourceCost()  			LLModel::convex_hull_decomposition& decomp =  			instance.mLOD[LLModel::LOD_PHYSICS] ? -			instance.mLOD[LLModel::LOD_PHYSICS]->mConvexHullDecomp : -			instance.mModel->mConvexHullDecomp; +			instance.mLOD[LLModel::LOD_PHYSICS]->mPhysics.mHull : +			instance.mModel->mPhysics.mHull;  			LLSD ret = LLModel::writeModel(  										   "", @@ -2729,8 +2739,8 @@ void LLModelPreview::saveUploadData(const std::string& filename, bool save_skinw  			LLModel::convex_hull_decomposition& decomp =  				instance.mLOD[LLModel::LOD_PHYSICS].notNull() ?  -				instance.mLOD[LLModel::LOD_PHYSICS]->mConvexHullDecomp :  -				instance.mModel->mConvexHullDecomp; +				instance.mLOD[LLModel::LOD_PHYSICS]->mPhysics.mHull :  +				instance.mModel->mPhysics.mHull;  			LLModel::writeModel(str,   				instance.mLOD[LLModel::LOD_PHYSICS],  @@ -2901,6 +2911,9 @@ void LLModelPreview::loadModelCallback(S32 lod)  		mBaseModel.clear();  		mBaseScene.clear(); +		bool skin_weights = false; +		bool joint_positions = false; +  		for (S32 lod = 0; lod < LLModel::NUM_LODS; ++lod)  		{ //for each LoD @@ -2934,11 +2947,39 @@ void LLModelPreview::loadModelCallback(S32 lod)  						}  						mModel[lod][idx] = list_iter->mModel;	 +						if (!list_iter->mModel->mSkinWeights.empty()) +						{ +							skin_weights = true; + +							if (!list_iter->mModel->mSkinInfo.mAlternateBindMatrix.empty()) +							{ +								joint_positions = true; +							} +						}  					}  				}  			}  		} +		if (mFMP) +		{ +			LLFloaterModelPreview* fmp = (LLFloaterModelPreview*) mFMP; + +			if (skin_weights) +			{ //enable uploading/previewing of skin weights if present in .slm file +				fmp->enableViewOption("show_skin_weight"); +				mViewOption["show_skin_weight"] = true; +				fmp->childSetValue("upload_skin", true); +			} + +			if (joint_positions) +			{  +				fmp->enableViewOption("show_joint_positions"); +				mViewOption["show_joint_positions"] = true; +				fmp->childSetValue("upload_joints", true); +			} +		} +  		//copy high lod to base scene for LoD generation  		mBaseScene = mScene[LLModel::LOD_HIGH];  		mBaseModel = mModel[LLModel::LOD_HIGH]; @@ -2952,14 +2993,8 @@ void LLModelPreview::loadModelCallback(S32 lod)  		mScene[lod] = mModelLoader->mScene;  		mVertexBuffer[lod].clear(); -		if (lod == LLModel::LOD_PHYSICS) -		{ -			mPhysicsMesh.clear(); -		} -  		setPreviewLOD(lod); -  		if (lod == LLModel::LOD_HIGH)  		{ //save a copy of the highest LOD for automatic LOD manipulation  			if (mBaseModel.empty()) @@ -3082,11 +3117,6 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim  		return;  	} -	if (which_lod == LLModel::LOD_PHYSICS) -	{ //clear physics mesh map -		mPhysicsMesh.clear(); -	} -  	LLVertexBuffer::unbind();  	stop_gloderror(); @@ -3415,11 +3445,7 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim  			//of an open problem).  			target_model->mPosition = base->mPosition;  			target_model->mSkinWeights = base->mSkinWeights; -			target_model->mJointMap = base->mJointMap; -			target_model->mJointList = base->mJointList; -			target_model->mInvBindMatrix = base->mInvBindMatrix; -			target_model->mBindShapeMatrix = base->mBindShapeMatrix; -			target_model->mAlternateBindMatrix = base->mAlternateBindMatrix; +			target_model->mSkinInfo = base->mSkinInfo;  			//copy material list  			target_model->mMaterialList = base->mMaterialList; @@ -3639,7 +3665,7 @@ void LLModelPreview::updateStatusMessages()  		LLModel* model = mModel[LLModel::LOD_PHYSICS][i];  		S32 cur_submeshes = model->getNumVolumeFaces(); -		LLModel::convex_hull_decomposition& decomp = model->mConvexHullDecomp; +		LLModel::convex_hull_decomposition& decomp = model->mPhysics.mHull;  		if (!decomp.empty())  		{ @@ -4276,12 +4302,17 @@ BOOL LLModelPreview::render()  					{  						LLMutexLock(decomp->mMutex); -						std::map<LLPointer<LLModel>, std::vector<LLPointer<LLVertexBuffer> > >::iterator iter = -							mPhysicsMesh.find(model); -						if (iter != mPhysicsMesh.end()) +						LLModel::Decomposition& physics = model->mPhysics; + +						if (physics.mMesh.empty()) +						{ //build vertex buffer for physics mesh +							gMeshRepo.buildPhysicsMesh(physics); +						} +							 +						if (!physics.mMesh.empty())  						{ //render hull instead of mesh  							render_mesh = false; -							for (U32 i = 0; i < iter->second.size(); ++i) +							for (U32 i = 0; i < physics.mMesh.size(); ++i)  							{  								if (explode > 0.f)  								{ @@ -4300,14 +4331,8 @@ BOOL LLModelPreview::render()  									hull_colors.push_back(LLColor4U(rand()%128+127, rand()%128+127, rand()%128+127, 255));  								} -								LLVertexBuffer* buff = iter->second[i]; -								if (buff) -								{ -									buff->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL); -  									glColor4ubv(hull_colors[i].mV); -									buff->drawArrays(LLRender::TRIANGLES, 0, buff->getNumVerts()); -								} +								LLVertexBuffer::drawArrays(LLRender::TRIANGLES, physics.mMesh[i].mPositions, physics.mMesh[i].mNormals);  								if (explode > 0.f)  								{ @@ -4391,12 +4416,12 @@ BOOL LLModelPreview::render()  							//build matrix palette  							LLMatrix4 mat[64]; -							for (U32 j = 0; j < model->mJointList.size(); ++j) +							for (U32 j = 0; j < model->mSkinInfo.mJointNames.size(); ++j)  							{ -								LLJoint* joint = avatar->getJoint(model->mJointList[j]); +								LLJoint* joint = avatar->getJoint(model->mSkinInfo.mJointNames[j]);  								if (joint)  								{ -									mat[j] = model->mInvBindMatrix[j]; +									mat[j] = model->mSkinInfo.mInvBindMatrix[j];  									mat[j] *= joint->getWorldMatrix();  								}  							} @@ -4437,7 +4462,7 @@ BOOL LLModelPreview::render()  								//VECTORIZE THIS  								LLVector3 v(face.mPositions[j].getF32ptr()); -								v = v * model->mBindShapeMatrix; +								v = v * model->mSkinInfo.mBindShapeMatrix;  								v = v * final_mat;  								position[j] = v; @@ -4687,7 +4712,6 @@ void LLFloaterModelPreview::DecompRequest::completed()  			{  				if (sInstance->mModelPreview)  				{ -					sInstance->mModelPreview->mPhysicsMesh[mModel] = mHullMesh;  					sInstance->mModelPreview->mDirty = true;  					LLFloaterModelPreview::sInstance->mModelPreview->refresh();  				} diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h index 68fa0fa4c1..6542ed4fbe 100644 --- a/indra/newview/llfloatermodelpreview.h +++ b/indra/newview/llfloatermodelpreview.h @@ -358,8 +358,7 @@ public:  	U32 mGroup;  	std::map<LLPointer<LLModel>, U32> mObject;  	U32 mMaxTriangleLimit; -	std::map<LLPointer<LLModel>, std::vector<LLPointer<LLVertexBuffer> > > mPhysicsMesh; - +	  	LLMeshUploadThread::instance_list mUploadData;  	std::set<LLViewerFetchedTexture* > mTextureSet; diff --git a/indra/newview/llfloatermodelwizard.cpp b/indra/newview/llfloatermodelwizard.cpp index 9751b87b4c..532c6789bb 100644 --- a/indra/newview/llfloatermodelwizard.cpp +++ b/indra/newview/llfloatermodelwizard.cpp @@ -485,7 +485,6 @@ void LLFloaterModelWizard::DecompRequest::completed()  	{  		if (sInstance->mModelPreview)  		{ -			sInstance->mModelPreview->mPhysicsMesh[mModel] = mHullMesh;  			sInstance->mModelPreview->mDirty = true;  			LLFloaterModelWizard::sInstance->mModelPreview->refresh();  		} diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index a2792bcdc6..752e4c8744 100755 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -108,19 +108,13 @@ U32 get_volume_memory_size(const LLVolume* volume)  	return indices*2+vertices*11+sizeof(LLVolume)+sizeof(LLVolumeFace)*volume->getNumVolumeFaces();  } -LLVertexBuffer* get_vertex_buffer_from_mesh(LLCDMeshData& mesh, F32 scale = 1.f) +void get_vertex_buffer_from_mesh(LLCDMeshData& mesh, LLModel::PhysicsMesh& res, F32 scale = 1.f)  { -	LLVertexBuffer* buff = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL, 0); -	buff->allocateBuffer(mesh.mNumTriangles*3, 0, true); - -	LLStrider<LLVector3> pos; -	LLStrider<LLVector3> norm; +	res.mPositions.clear(); +	res.mNormals.clear(); -	buff->getVertexStrider(pos); -	buff->getNormalStrider(norm); -  	const F32* v = mesh.mVertexBase; -	 +  	if (mesh.mIndexType == LLCDMeshData::INT_16)  	{  		U16* idx = (U16*) mesh.mIndexBase; @@ -139,13 +133,13 @@ LLVertexBuffer* get_vertex_buffer_from_mesh(LLCDMeshData& mesh, F32 scale = 1.f)  			LLVector3 n = (v1-v0)%(v2-v0);  			n.normalize(); -			*pos++ = v0*scale; -			*pos++ = v1*scale; -			*pos++ = v2*scale; +			res.mPositions.push_back(v0*scale); +			res.mPositions.push_back(v1*scale); +			res.mPositions.push_back(v2*scale); -			*norm++ = n; -			*norm++ = n; -			*norm++ = n;			 +			res.mNormals.push_back(n); +			res.mNormals.push_back(n); +			res.mNormals.push_back(n);			  		}  	}  	else @@ -166,17 +160,15 @@ LLVertexBuffer* get_vertex_buffer_from_mesh(LLCDMeshData& mesh, F32 scale = 1.f)  			LLVector3 n = (v1-v0)%(v2-v0);  			n.normalize(); -			*(pos++) = v0*scale; -			*(pos++) = v1*scale; -			*(pos++) = v2*scale; +			res.mPositions.push_back(v0*scale); +			res.mPositions.push_back(v1*scale); +			res.mPositions.push_back(v2*scale); -			*(norm++) = n; -			*(norm++) = n; -			*(norm++) = n;			 +			res.mNormals.push_back(n); +			res.mNormals.push_back(n); +			res.mNormals.push_back(n);			  		}  	} - -	return buff;  }  S32 LLMeshRepoThread::sActiveHeaderRequests = 0; @@ -1111,66 +1103,9 @@ bool LLMeshRepoThread::skinInfoReceived(const LLUUID& mesh_id, U8* data, S32 dat  	}  	{ -		LLMeshSkinInfo info; +		LLMeshSkinInfo info(skin);  		info.mMeshID = mesh_id; -		if (skin.has("joint_names")) -		{ -			for (U32 i = 0; i < skin["joint_names"].size(); ++i) -			{ -				info.mJointNames.push_back(skin["joint_names"][i]); -			} -		} - -		if (skin.has("inverse_bind_matrix")) -		{ -			for (U32 i = 0; i < skin["inverse_bind_matrix"].size(); ++i) -			{ -				LLMatrix4 mat; -				for (U32 j = 0; j < 4; j++) -				{ -					for (U32 k = 0; k < 4; k++) -					{ -						mat.mMatrix[j][k] = skin["inverse_bind_matrix"][i][j*4+k].asReal(); -					} -				} - -				info.mInvBindMatrix.push_back(mat); -			} -		} - -		if (skin.has("bind_shape_matrix")) -		{ -			for (U32 j = 0; j < 4; j++) -			{ -				for (U32 k = 0; k < 4; k++) -				{ -					info.mBindShapeMatrix.mMatrix[j][k] = skin["bind_shape_matrix"][j*4+k].asReal(); -				} -			} -		} - -		if (skin.has("alt_inverse_bind_matrix")) -		{ -			for (U32 i = 0; i < skin["alt_inverse_bind_matrix"].size(); ++i) -			{ -				LLMatrix4 mat; -				for (U32 j = 0; j < 4; j++) -				{ -					for (U32 k = 0; k < 4; k++) -					{ -						mat.mMatrix[j][k] = skin["alt_inverse_bind_matrix"][i][j*4+k].asReal(); -					} -				} -				 -				info.mAlternateBindMatrix.push_back(mat); -			} -		} - -		if (skin.has("pelvis_offset")) -		{ -			info.mPelvisOffset = skin["pelvis_offset"].asReal(); -		}  		//llinfos<<"info pelvis offset"<<info.mPelvisOffset<<llendl;  		mSkinInfoQ.push(info);  	} @@ -1196,119 +1131,8 @@ bool LLMeshRepoThread::decompositionReceived(const LLUUID& mesh_id, U8* data, S3  	}  	{ -		LLMeshDecomposition* d = new LLMeshDecomposition(); +		LLModel::Decomposition* d = new LLModel::Decomposition(decomp);  		d->mMeshID = mesh_id; - -		if (decomp.has("HullList")) -		{ -			// 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(); - -			U16* p = (U16*) &position[0]; - -			d->mHull.resize(hulls.size()); - -			LLVector3 min; -			LLVector3 max; -			LLVector3 range; - -			min.setValue(decomp["Min"]); -			max.setValue(decomp["Max"]); -			range = max-min; - -			for (U32 i = 0; i < hulls.size(); ++i) -			{ -				U16 count = (hulls[i] == 0) ? 256 : hulls[i]; -				 -				for (U32 j = 0; j < count; ++j) -				{ -					d->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], -						(F32) p[2]/65535.f*range.mV[2]+min.mV[2])); -					p += 3; -				}		  - -			} -				 -			//get mesh for decomposition -			for (U32 i = 0; i < d->mHull.size(); ++i) -			{ -				LLCDHull hull; -				hull.mNumVertices = d->mHull[i].size(); -				hull.mVertexBase = d->mHull[i][0].mV; -				hull.mVertexStrideBytes = 12; - -				LLCDMeshData mesh; -				LLCDResult res = LLCD_OK; -				if (LLConvexDecomposition::getInstance() != NULL) -				{ -					res = LLConvexDecomposition::getInstance()->getMeshFromHull(&hull, &mesh); -				} -				if (res != LLCD_OK) -				{ -					llwarns << "could not get mesh from hull from convex decomposition lib." << llendl; -					return false; -				} - - -				d->mMesh.push_back(get_vertex_buffer_from_mesh(mesh)); -			}	 -		} - -		if (decomp.has("Hull")) -		{ -			const LLSD::Binary& position = decomp["Hull"].asBinary(); - -			U16* p = (U16*) &position[0]; - -			LLVector3 min; -			LLVector3 max; -			LLVector3 range; - -			min.setValue(decomp["Min"]); -			max.setValue(decomp["Max"]); -			range = max-min; - -			U16 count = position.size()/6; -			 -			for (U32 j = 0; j < count; ++j) -			{ -				d->mBaseHull.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], -					(F32) p[2]/65535.f*range.mV[2]+min.mV[2])); -				p += 3; -			}		  -				 -			//get mesh for decomposition -			LLCDHull hull; -			hull.mNumVertices = d->mBaseHull.size(); -			hull.mVertexBase = d->mBaseHull[0].mV; -			hull.mVertexStrideBytes = 12; - -			LLCDMeshData mesh; -			LLCDResult res = LLCD_OK; -			if (LLConvexDecomposition::getInstance() != NULL) -			{ -				res = LLConvexDecomposition::getInstance()->getMeshFromHull(&hull, &mesh); -			} -			if (res != LLCD_OK) -			{ -				llwarns << "could not get mesh from hull from convex decomposition lib." << llendl; -				return false; -			} - -			d->mBaseHullMesh = get_vertex_buffer_from_mesh(mesh); -		} -		else -		{ -			//empty vertex buffer to indicate decomposition has been fetched -			//but contains no base hull -			d->mBaseHullMesh = new LLVertexBuffer(0, 0); -		} -  		mDecompositionQ.push(d);  	} @@ -1319,12 +1143,12 @@ bool LLMeshRepoThread::physicsShapeReceived(const LLUUID& mesh_id, U8* data, S32  {  	LLSD physics_shape; -	LLMeshDecomposition* d = new LLMeshDecomposition(); +	LLModel::Decomposition* d = new LLModel::Decomposition();  	d->mMeshID = mesh_id;  	if (data == NULL)  	{ //no data, no physics shape exists -		d->mPhysicsShapeMesh = new LLVertexBuffer(0,0); +		d->mPhysicsShapeMesh.clear();  	}  	else  	{ @@ -1348,33 +1172,22 @@ bool LLMeshRepoThread::physicsShapeReceived(const LLUUID& mesh_id, U8* data, S32  				index_count += face.mNumIndices;  			} -			d->mPhysicsShapeMesh = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX, 0); - -			d->mPhysicsShapeMesh->allocateBuffer(vertex_count, index_count, true); - -			LLStrider<LLVector3> pos; -			LLStrider<U16> idx; +			d->mPhysicsShapeMesh.clear(); -			d->mPhysicsShapeMesh->getVertexStrider(pos); -			d->mPhysicsShapeMesh->getIndexStrider(idx); +			std::vector<LLVector3>& pos = d->mPhysicsShapeMesh.mPositions; +			std::vector<LLVector3>& norm = d->mPhysicsShapeMesh.mNormals; -			S32 idx_offset = 0;  			for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i)  			{  				const LLVolumeFace& face = volume->getVolumeFace(i); -				if (idx_offset + face.mNumIndices > 65535) -				{ //avoid 16-bit index overflow -					continue; -				} - -				LLVector4a::memcpyNonAliased16(pos[idx_offset].mV, face.mPositions[0].getF32ptr(), face.mNumVertices*sizeof(LLVector4a));  				for (S32 i = 0; i < face.mNumIndices; ++i)  				{ -					*idx++ = face.mIndices[i] + idx_offset; -				} +					U16 idx = face.mIndices[i]; -				idx_offset += face.mNumVertices; +					pos.push_back(LLVector3(face.mPositions[idx].getF32ptr())); +					norm.push_back(LLVector3(face.mNormals[idx].getF32ptr()));				 +				}			  			}  		}  	} @@ -2485,33 +2298,7 @@ void LLMeshRepository::notifySkinInfoReceived(LLMeshSkinInfo& info)  	mLoadingSkins.erase(info.mMeshID);  } -void LLMeshDecomposition::merge(const LLMeshDecomposition* rhs) -{ -	if (!rhs) -	{ -		return; -	} - -	if (mMeshID != rhs->mMeshID) -	{ -		llerrs << "Attempted to merge with decomposition of some other mesh." << llendl; -	} - -	if (mBaseHull.empty()) -	{ //take base hull and decomposition from rhs -		mHull = rhs->mHull; -		mBaseHull = rhs->mBaseHull; -		mMesh = rhs->mMesh; -		mBaseHullMesh = rhs->mBaseHullMesh; -	} - -	if (mPhysicsShapeMesh.isNull()) -	{ //take physics shape mesh from rhs -		mPhysicsShapeMesh = rhs->mPhysicsShapeMesh; -	} -} - -void LLMeshRepository::notifyDecompositionReceived(LLMeshDecomposition* decomp) +void LLMeshRepository::notifyDecompositionReceived(LLModel::Decomposition* decomp)  {  	decomposition_map::iterator iter = mDecompositionMap.find(decomp->mMeshID);  	if (iter == mDecompositionMap.end()) @@ -2653,7 +2440,7 @@ void LLMeshRepository::fetchPhysicsShape(const LLUUID& mesh_id)  {  	if (mesh_id.notNull())  	{ -		LLMeshDecomposition* decomp = NULL; +		LLModel::Decomposition* decomp = NULL;  		decomposition_map::iterator iter = mDecompositionMap.find(mesh_id);  		if (iter != mDecompositionMap.end())  		{ @@ -2661,7 +2448,7 @@ void LLMeshRepository::fetchPhysicsShape(const LLUUID& mesh_id)  		}  		//decomposition block hasn't been fetched yet -		if (!decomp || decomp->mPhysicsShapeMesh.isNull()) +		if (!decomp || decomp->mPhysicsShapeMesh.empty())  		{  			LLMutexLock lock(mMeshMutex);  			//add volume to list of loading meshes @@ -2676,9 +2463,9 @@ void LLMeshRepository::fetchPhysicsShape(const LLUUID& mesh_id)  } -const LLMeshDecomposition* LLMeshRepository::getDecomposition(const LLUUID& mesh_id) +LLModel::Decomposition* LLMeshRepository::getDecomposition(const LLUUID& mesh_id)  { -	LLMeshDecomposition* ret = NULL; +	LLModel::Decomposition* ret = NULL;  	if (mesh_id.notNull())  	{ @@ -2689,7 +2476,7 @@ const LLMeshDecomposition* LLMeshRepository::getDecomposition(const LLUUID& mesh  		}  		//decomposition block hasn't been fetched yet -		if (!ret || ret->mBaseHullMesh.isNull()) +		if (!ret || ret->mBaseHullMesh.empty())  		{  			LLMutexLock lock(mMeshMutex);  			//add volume to list of loading meshes @@ -2792,8 +2579,8 @@ void LLMeshUploadThread::sendCostRequest(LLMeshUploadData& data)  	LLModel::convex_hull_decomposition& decomp =  		data.mModel[LLModel::LOD_PHYSICS].notNull() ?  -		data.mModel[LLModel::LOD_PHYSICS]->mConvexHullDecomp :  -		data.mBaseModel->mConvexHullDecomp; +		data.mModel[LLModel::LOD_PHYSICS]->mPhysics.mHull :  +		data.mBaseModel->mPhysics.mHull;  	LLModel::hull dummy_hull; @@ -2893,8 +2680,8 @@ void LLMeshUploadThread::doUploadModel(LLMeshUploadData& data)  		LLModel::convex_hull_decomposition& decomp =  			data.mModel[LLModel::LOD_PHYSICS].notNull() ?  -			data.mModel[LLModel::LOD_PHYSICS]->mConvexHullDecomp :  -			data.mBaseModel->mConvexHullDecomp; +			data.mModel[LLModel::LOD_PHYSICS]->mPhysics.mHull :  +			data.mBaseModel->mPhysics.mHull;  		LLModel::writeModel(  			ostr,   @@ -3412,7 +3199,7 @@ void LLPhysicsDecomp::doDecomposition()  			// if LLConvexDecomposition is a stub, num_hulls should have been set to 0 above, and we should not reach this code  			LLConvexDecomposition::getInstance()->getMeshFromStage(stage, i, &mesh); -			mCurRequest->mHullMesh[i] = get_vertex_buffer_from_mesh(mesh); +			get_vertex_buffer_from_mesh(mesh, mCurRequest->mHullMesh[i]);  			mMutex->lock();  			mCurRequest->mHull[i] = p; @@ -3685,3 +3472,46 @@ LLSD LLImportMaterial::asLLSD()  	return ret;  } + +void LLMeshRepository::buildPhysicsMesh(LLModel::Decomposition& decomp) +{ +	decomp.mMesh.resize(decomp.mHull.size());
 +
 +	for (U32 i = 0; i < decomp.mHull.size(); ++i)
 +	{
 +		LLCDHull hull; +		hull.mNumVertices = decomp.mHull[i].size(); +		hull.mVertexBase = decomp.mHull[i][0].mV; +		hull.mVertexStrideBytes = 12; + +		LLCDMeshData mesh; +		LLCDResult res = LLCD_OK; +		if (LLConvexDecomposition::getInstance() != NULL) +		{ +			res = LLConvexDecomposition::getInstance()->getMeshFromHull(&hull, &mesh); +		} +		if (res == LLCD_OK) +		{ +			get_vertex_buffer_from_mesh(mesh, decomp.mMesh[i]);
 +		}
 +	} + +	if (!decomp.mBaseHull.empty() && decomp.mBaseHullMesh.empty()) +	{ //get mesh for base hull +		LLCDHull hull; +		hull.mNumVertices = decomp.mBaseHull.size(); +		hull.mVertexBase = decomp.mBaseHull[0].mV; +		hull.mVertexStrideBytes = 12; + +		LLCDMeshData mesh; +		LLCDResult res = LLCD_OK; +		if (LLConvexDecomposition::getInstance() != NULL) +		{ +			res = LLConvexDecomposition::getInstance()->getMeshFromHull(&hull, &mesh); +		} +		if (res == LLCD_OK) +		{ +			get_vertex_buffer_from_mesh(mesh, decomp.mBaseHullMesh); +		} +	} +} diff --git a/indra/newview/llmeshrepository.h b/indra/newview/llmeshrepository.h index 4e349a1270..31c2049c32 100644 --- a/indra/newview/llmeshrepository.h +++ b/indra/newview/llmeshrepository.h @@ -132,34 +132,6 @@ public:  	LLSD asLLSD();  }; -class LLMeshSkinInfo  -{ -public: -	LLUUID mMeshID; -	std::vector<std::string> mJointNames; -	std::vector<LLMatrix4> mInvBindMatrix; -	std::vector<LLMatrix4> mAlternateBindMatrix; -	 -	LLMatrix4 mBindShapeMatrix; -	float mPelvisOffset; -}; - -class LLMeshDecomposition -{ -public: -	LLMeshDecomposition() { } - -	void merge(const LLMeshDecomposition* rhs); - -	LLUUID mMeshID; -	LLModel::convex_hull_decomposition mHull; -	LLModel::hull mBaseHull; - -	std::vector<LLPointer<LLVertexBuffer> > mMesh; -	LLPointer<LLVertexBuffer> mBaseHullMesh; -	LLPointer<LLVertexBuffer> mPhysicsShapeMesh; -}; -  class LLPhysicsDecomp : public LLThread  {  public: @@ -178,7 +150,7 @@ public:  		//output state  		std::string mStatusMessage; -		std::vector<LLPointer<LLVertexBuffer> > mHullMesh; +		std::vector<LLModel::PhysicsMesh> mHullMesh;  		LLModel::convex_hull_decomposition mHull;  		//status message callback, called from decomposition thread @@ -313,7 +285,7 @@ public:  	std::set<LLUUID> mPhysicsShapeRequests;  	//queue of completed Decomposition info requests -	std::queue<LLMeshDecomposition*> mDecompositionQ; +	std::queue<LLModel::Decomposition*> mDecompositionQ;  	//queue of requested headers  	std::queue<HeaderRequest> mHeaderReqQ; @@ -477,17 +449,19 @@ public:  	void notifyMeshLoaded(const LLVolumeParams& mesh_params, LLVolume* volume);  	void notifyMeshUnavailable(const LLVolumeParams& mesh_params, S32 lod);  	void notifySkinInfoReceived(LLMeshSkinInfo& info); -	void notifyDecompositionReceived(LLMeshDecomposition* info); +	void notifyDecompositionReceived(LLModel::Decomposition* info);  	S32 getActualMeshLOD(const LLVolumeParams& mesh_params, S32 lod);  	U32 calcResourceCost(LLSD& header);  	U32 getResourceCost(const LLUUID& mesh_params);  	const LLMeshSkinInfo* getSkinInfo(const LLUUID& mesh_id); -	const LLMeshDecomposition* getDecomposition(const LLUUID& mesh_id); +	LLModel::Decomposition* getDecomposition(const LLUUID& mesh_id);  	void fetchPhysicsShape(const LLUUID& mesh_id);  	bool hasPhysicsShape(const LLUUID& mesh_id);  	void buildHull(const LLVolumeParams& params, S32 detail); +	void buildPhysicsMesh(LLModel::Decomposition& decomp); +  	const LLSD& getMeshHeader(const LLUUID& mesh_id);  	void uploadModel(std::vector<LLModelInstance>& data, LLVector3& scale, bool upload_textures, @@ -501,7 +475,7 @@ public:  	typedef std::map<LLUUID, LLMeshSkinInfo> skin_map;  	skin_map mSkinMap; -	typedef std::map<LLUUID, LLMeshDecomposition*> decomposition_map; +	typedef std::map<LLUUID, LLModel::Decomposition*> decomposition_map;  	decomposition_map mDecompositionMap;  	LLMutex*					mMeshMutex; diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp index 5e7af6bbb3..65f7d299bc 100644 --- a/indra/newview/llspatialpartition.cpp +++ b/indra/newview/llspatialpartition.cpp @@ -2961,31 +2961,21 @@ S32 get_physics_detail(const LLVolumeParams& volume_params, const LLVector3& sca  void renderMeshBaseHull(LLVOVolume* volume, U32 data_mask, LLColor4& color, LLColor4& line_color)  {  	LLUUID mesh_id = volume->getVolume()->getParams().getSculptID(); -	const LLMeshDecomposition* decomp = gMeshRepo.getDecomposition(mesh_id); +	LLModel::Decomposition* decomp = gMeshRepo.getDecomposition(mesh_id);  	const LLVector3 center(0,0,0);  	const LLVector3 size(0.25f,0.25f,0.25f);  	if (decomp)  	{		 -		LLVertexBuffer* buff = decomp->mBaseHullMesh; - -		if (buff && buff->getNumVerts() > 0) +		if (!decomp->mBaseHullMesh.empty())  		{ -			buff->setBuffer(data_mask); - -		/*	glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); -			glColor4fv(line_color.mV); -			buff->drawArrays(LLRender::TRIANGLES, 0, buff->getNumVerts()); -			glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);*/ - -			{ -				glColor4fv(color.mV); -				buff->drawArrays(LLRender::TRIANGLES, 0, buff->getNumVerts()); -			} +			glColor4fv(color.mV); +			LLVertexBuffer::drawArrays(LLRender::TRIANGLES, decomp->mBaseHullMesh.mPositions, decomp->mBaseHullMesh.mNormals);  		}  		else  		{ +			gMeshRepo.buildPhysicsMesh(*decomp);  			gGL.color3f(0,1,1);  			drawBoxOutline(center, size);  		} @@ -2998,19 +2988,16 @@ void renderMeshBaseHull(LLVOVolume* volume, U32 data_mask, LLColor4& color, LLCo  	}  } -void render_hull(LLVertexBuffer* buff, U32 data_mask, const LLColor4& color, const LLColor4& line_color) +void render_hull(LLModel::PhysicsMesh& mesh, const LLColor4& color, const LLColor4& line_color)  { -	buff->setBuffer(data_mask); -  	glColor4fv(color.mV); -	buff->drawArrays(LLRender::TRIANGLES, 0, buff->getNumVerts()); - +	LLVertexBuffer::drawArrays(LLRender::TRIANGLES, mesh.mPositions, mesh.mNormals);  	LLGLEnable offset(GL_POLYGON_OFFSET_LINE);  	glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);  	glPolygonOffset(3.f, 3.f);  	glLineWidth(3.f);  	glColor4fv(line_color.mV); -	buff->drawArrays(LLRender::TRIANGLES, 0, buff->getNumVerts()); +	LLVertexBuffer::drawArrays(LLRender::TRIANGLES, mesh.mPositions, mesh.mNormals);  	glLineWidth(1.f);  	glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);  } @@ -3075,7 +3062,7 @@ void renderPhysicsShape(LLDrawable* drawable, LLVOVolume* volume)  	if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::USER_MESH)  	{  		LLUUID mesh_id = volume->getVolume()->getParams().getSculptID(); -		const LLMeshDecomposition* decomp = gMeshRepo.getDecomposition(mesh_id); +		LLModel::Decomposition* decomp = gMeshRepo.getDecomposition(mesh_id);  		if (decomp)  		{ //render a physics based mesh @@ -3084,27 +3071,33 @@ void renderPhysicsShape(LLDrawable* drawable, LLVOVolume* volume)  			if (!decomp->mHull.empty())  			{ //decomposition exists, use that -				for (U32 i = 0; i < decomp->mHull.size(); ++i) + +				if (decomp->mMesh.empty()) +				{ +					gMeshRepo.buildPhysicsMesh(*decomp); +				} + +				for (U32 i = 0; i < decomp->mMesh.size(); ++i)  				{		 -					render_hull(decomp->mMesh[i], data_mask, color, line_color); +					render_hull(decomp->mMesh[i], color, line_color);  				}  			} -			else if (decomp->mPhysicsShapeMesh.notNull() && decomp->mPhysicsShapeMesh->getNumVerts() > 0) +			else if (!decomp->mPhysicsShapeMesh.empty())  			{   				//decomp has physics mesh, render that mesh  				glColor4fv(color.mV); -				pushBufferVerts(decomp->mPhysicsShapeMesh, data_mask); -				 +				LLVertexBuffer::drawArrays(LLRender::TRIANGLES, decomp->mPhysicsShapeMesh.mPositions, decomp->mPhysicsShapeMesh.mNormals); +								  				glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);  				glColor4fv(line_color.mV); -				pushBufferVerts(decomp->mPhysicsShapeMesh, data_mask); +				LLVertexBuffer::drawArrays(LLRender::TRIANGLES, decomp->mPhysicsShapeMesh.mPositions, decomp->mPhysicsShapeMesh.mNormals);  				glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);  			}  			else  			{ //no mesh or decomposition, render base hull  				renderMeshBaseHull(volume, data_mask, color, line_color); -				if (decomp->mPhysicsShapeMesh.isNull()) +				if (decomp->mPhysicsShapeMesh.empty())  				{  					//attempt to fetch physics shape mesh if available  					gMeshRepo.fetchPhysicsShape(mesh_id); diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 7468281f65..71706f0146 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -762,6 +762,7 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,  	mPelvisOffset = LLVector3(0.0f,0.0f,0.0f);
  	mLastPelvisToFoot = 0.0f;
  	mPelvisFixup = 0.0f;
 +	mLastPelvisFixup = 0.0f;
  }
  //------------------------------------------------------------------------
 @@ -3805,6 +3806,7 @@ void LLVOAvatar::setPelvisOffset( bool hasOffset, const LLVector3& offsetAmount,  		//Store off last pelvis to foot value
  		mLastPelvisToFoot = mPelvisToFoot;
  		mPelvisOffset	  = offsetAmount;
 +		mLastPelvisFixup  = mPelvisFixup;
  		mPelvisFixup	  = pelvisFixup;
  	}
  }
 @@ -3825,6 +3827,7 @@ void LLVOAvatar::postPelvisSetRecalc( void )  void LLVOAvatar::setPelvisOffset( F32 pelvisFixupAmount )
  {	
  	mHasPelvisOffset  = true;
 +	mLastPelvisFixup  = mPelvisFixup;	
  	mPelvisFixup	  = pelvisFixupAmount;	
  }
  //------------------------------------------------------------------------
 @@ -4965,6 +4968,7 @@ void LLVOAvatar::resetJointPositions( void )  		mSkeleton[i].setId( LLUUID::null );
  	}
  	mHasPelvisOffset = false;
 +	mPelvisFixup	 = mLastPelvisFixup;
  }
  //-----------------------------------------------------------------------------
  // resetSpecificJointPosition
 @@ -5024,6 +5028,7 @@ void LLVOAvatar::resetJointPositionsToDefault( void )  	}
  	//make sure we don't apply the joint offset
  	mHasPelvisOffset = false;
 +	mPelvisFixup	 = mLastPelvisFixup;
  	postPelvisSetRecalc();
  }
  //-----------------------------------------------------------------------------
 diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index 1552532a97..edec1b480a 100644 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -301,6 +301,7 @@ public:  	LLVector3			mPelvisOffset;
  	F32					mLastPelvisToFoot;
  	F32					mPelvisFixup;
 +	F32					mLastPelvisFixup;
  	LLVector3			mHeadOffset; // current head position
  	LLViewerJoint		mRoot;
 diff --git a/indra/newview/skins/minimal/xui/de/menu_inspect_self_gear.xml b/indra/newview/skins/minimal/xui/de/menu_inspect_self_gear.xml index 19264db598..443092319b 100644 --- a/indra/newview/skins/minimal/xui/de/menu_inspect_self_gear.xml +++ b/indra/newview/skins/minimal/xui/de/menu_inspect_self_gear.xml @@ -1,5 +1,5 @@  <?xml version="1.0" encoding="utf-8" standalone="yes"?> -<toggleable_menu name="Gear Menu"> +<toggleable_menu name="Self Pie">  	<menu_item_call label="Hinsetzen" name="Sit Down Here"/>  	<menu_item_call label="Aufstehen" name="Stand Up"/>  	<menu_item_call label="Meine Freunde" name="Friends..."/> diff --git a/indra/newview/skins/minimal/xui/es/menu_inspect_self_gear.xml b/indra/newview/skins/minimal/xui/es/menu_inspect_self_gear.xml index 6b76137114..1a49efb9d0 100644 --- a/indra/newview/skins/minimal/xui/es/menu_inspect_self_gear.xml +++ b/indra/newview/skins/minimal/xui/es/menu_inspect_self_gear.xml @@ -1,5 +1,5 @@  <?xml version="1.0" encoding="utf-8" standalone="yes"?> -<toggleable_menu name="Gear Menu"> +<toggleable_menu name="Self Pie">  	<menu_item_call label="Sentarme" name="Sit Down Here"/>  	<menu_item_call label="Levantarme" name="Stand Up"/>  	<menu_item_call label="Mis amigos" name="Friends..."/> diff --git a/indra/newview/skins/minimal/xui/fr/menu_inspect_self_gear.xml b/indra/newview/skins/minimal/xui/fr/menu_inspect_self_gear.xml index 7a79c00123..fd48aa4f7d 100644 --- a/indra/newview/skins/minimal/xui/fr/menu_inspect_self_gear.xml +++ b/indra/newview/skins/minimal/xui/fr/menu_inspect_self_gear.xml @@ -1,5 +1,5 @@  <?xml version="1.0" encoding="utf-8" standalone="yes"?> -<toggleable_menu name="Gear Menu"> +<toggleable_menu name="Self Pie">  	<menu_item_call label="M'asseoir" name="Sit Down Here"/>  	<menu_item_call label="Me lever" name="Stand Up"/>  	<menu_item_call label="Mes amis" name="Friends..."/> diff --git a/indra/newview/skins/minimal/xui/pt/menu_inspect_self_gear.xml b/indra/newview/skins/minimal/xui/pt/menu_inspect_self_gear.xml index e514d2f4f5..c1f27e765d 100644 --- a/indra/newview/skins/minimal/xui/pt/menu_inspect_self_gear.xml +++ b/indra/newview/skins/minimal/xui/pt/menu_inspect_self_gear.xml @@ -1,5 +1,5 @@  <?xml version="1.0" encoding="utf-8" standalone="yes"?> -<toggleable_menu name="Gear Menu"> +<toggleable_menu name="Self Pie">  	<menu_item_call label="Sentar" name="Sit Down Here"/>  	<menu_item_call label="Ficar de pé" name="Stand Up"/>  	<menu_item_call label="Meus amigos" name="Friends..."/> | 
