diff options
Diffstat (limited to 'indra/newview')
| -rwxr-xr-x | indra/newview/CMakeLists.txt | 5 | ||||
| -rwxr-xr-x | indra/newview/app_settings/settings.xml | 44 | ||||
| -rw-r--r--[-rwxr-xr-x] | indra/newview/llcallbacklist.cpp | 0 | ||||
| -rwxr-xr-x | indra/newview/llcallbacklist.h | 72 | ||||
| -rwxr-xr-x | indra/newview/llfloatermodelpreview.cpp | 2971 | ||||
| -rwxr-xr-x | indra/newview/llfloatermodelpreview.h | 132 | ||||
| -rwxr-xr-x | indra/newview/llmeshrepository.cpp | 407 | ||||
| -rwxr-xr-x | indra/newview/llmeshrepository.h | 50 | ||||
| -rwxr-xr-x | indra/newview/skins/default/xui/en/floater_model_preview.xml | 38 | ||||
| -rwxr-xr-x | indra/newview/skins/default/xui/en/notifications.xml | 5 | ||||
| -rwxr-xr-x | indra/newview/skins/default/xui/en/strings.xml | 16 | 
11 files changed, 1054 insertions, 2686 deletions
| diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 67c00576be..3f45b06786 100755 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -140,7 +140,6 @@ set(viewer_SOURCE_FILES      llbreadcrumbview.cpp      llbrowsernotification.cpp      llbuycurrencyhtml.cpp -    llcallbacklist.cpp      llcallingcard.cpp      llcapabilitylistener.cpp      llcaphttpsender.cpp @@ -755,7 +754,6 @@ set(viewer_HEADER_FILES      llbox.h      llbreadcrumbview.h      llbuycurrencyhtml.h -    llcallbacklist.h      llcallingcard.h      llcapabilitylistener.h      llcapabilityprovider.h @@ -1018,6 +1016,9 @@ set(viewer_HEADER_FILES      llnameeditor.h      llnamelistctrl.h      llnavigationbar.h +    llfloaterimnearbychat.h +    llfloaterimnearbychathandler.h +    llfloaterimnearbychatlistener.h      llnetmap.h      llnotificationhandler.h      llnotificationmanager.h diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 9d9bc43bd7..8ca6bb879d 100755 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -2,6 +2,50 @@  <llsd xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    xsi:noNamespaceSchemaLocation="llsd.xsd">  <map> +  <key>ImporterDebug</key> +  <map> +    <key>Comment</key> +    <string>Enable debug output to more precisely identify sources of import errors. Warning: the output can slow down import on many machines.</string> +    <key>Persist</key> +    <integer>1</integer> +    <key>Type</key> +    <string>Boolean</string> +    <key>Value</key> +    <integer>0</integer> +  </map> +  <key>ImporterLegacyMatching</key> +  <map> +    <key>Comment</key> +    <string>Enable index based model matching.</string> +    <key>Persist</key> +    <integer>1</integer> +    <key>Type</key> +    <string>Boolean</string> +    <key>Value</key> +    <integer>0</integer> +  </map> +  <key>ImporterModelLimit</key> +  <map> +    <key>Comment</key> +    <string>Limits amount of importer generated models for dae files</string> +    <key>Persist</key> +    <integer>1</integer> +    <key>Type</key> +    <string>U32</string> +    <key>Value</key> +    <integer>768</integer> +  </map> +  <key>IMShowTime</key> +  <map> +    <key>Comment</key> +    <string>Enable(disable) timestamp showing in the chat.</string> +    <key>Persist</key> +    <integer>1</integer> +    <key>Type</key> +    <string>Boolean</string> +    <key>Value</key> +    <integer>1</integer> +  </map>      <key>IMShowTime</key>      <map>        <key>Comment</key> diff --git a/indra/newview/llcallbacklist.cpp b/indra/newview/llcallbacklist.cpp index 59ecbdd0ea..59ecbdd0ea 100755..100644 --- a/indra/newview/llcallbacklist.cpp +++ b/indra/newview/llcallbacklist.cpp diff --git a/indra/newview/llcallbacklist.h b/indra/newview/llcallbacklist.h deleted file mode 100755 index 0516c9cdb4..0000000000 --- a/indra/newview/llcallbacklist.h +++ /dev/null @@ -1,72 +0,0 @@ -/**  - * @file llcallbacklist.h - * @brief A simple list of callback functions to call. - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - *  - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - *  - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * Lesser General Public License for more details. - *  - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - *  - * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA - * $/LicenseInfo$ - */ - -#ifndef LL_LLCALLBACKLIST_H -#define LL_LLCALLBACKLIST_H - -#include "llstl.h" - -class LLCallbackList -{ -public: -	typedef void (*callback_t)(void*); -	 -	LLCallbackList(); -	~LLCallbackList(); - -	void addFunction( callback_t func, void *data = NULL );		// register a callback, which will be called as func(data) -	BOOL containsFunction( callback_t func, void *data = NULL );	// true if list already contains the function/data pair -	BOOL deleteFunction( callback_t func, void *data = NULL );		// removes the first instance of this function/data pair from the list, false if not found -	void callFunctions();												// calls all functions -	void deleteAllFunctions(); - -	static void test(); - -protected: -	// Use a list so that the callbacks are ordered in case that matters -	typedef std::pair<callback_t,void*> callback_pair_t; -	typedef std::list<callback_pair_t > callback_list_t; -	callback_list_t	mCallbackList; -}; - -typedef boost::function<void ()> nullary_func_t; -typedef boost::function<bool ()> bool_func_t; - -// Call a given callable once in idle loop. -void doOnIdleOneTime(nullary_func_t callable); - -// Repeatedly call a callable in idle loop until it returns true. -void doOnIdleRepeating(bool_func_t callable); - -// Call a given callable once after specified interval. -void doAfterInterval(nullary_func_t callable, F32 seconds); - -// Call a given callable every specified number of seconds, until it returns true. -void doPeriodically(bool_func_t callable, F32 seconds); - -extern LLCallbackList gIdleCallbacks; - -#endif diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 72c9170b06..aa2c37055f 100755 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -26,35 +26,8 @@  #include "llviewerprecompiledheaders.h" -#if LL_MSVC -#pragma warning (disable : 4263) -#pragma warning (disable : 4264) -#endif -#include "dae.h" -//#include "dom.h" -#include "dom/domAsset.h" -#include "dom/domBind_material.h" -#include "dom/domCOLLADA.h" -#include "dom/domConstants.h" -#include "dom/domController.h" -#include "dom/domEffect.h" -#include "dom/domGeometry.h" -#include "dom/domInstance_geometry.h" -#include "dom/domInstance_material.h" -#include "dom/domInstance_node.h" -#include "dom/domInstance_effect.h" -#include "dom/domMaterial.h" -#include "dom/domMatrix.h" -#include "dom/domNode.h" -#include "dom/domProfile_COMMON.h" -#include "dom/domRotate.h" -#include "dom/domScale.h" -#include "dom/domTranslate.h" -#include "dom/domVisual_scene.h" -#if LL_MSVC -#pragma warning (default : 4263) -#pragma warning (default : 4264) -#endif +#include "llmodelloader.h" +#include "lldaeloader.h"  #include "llfloatermodelpreview.h" @@ -112,14 +85,15 @@  #include "llanimationstates.h"  #include "llviewernetwork.h"  #include "llviewershadermgr.h" -#include "glod/glod.h" -const S32 SLM_SUPPORTED_VERSION = 3; +#include "glod/glod.h" +#include <boost/algorithm/string.hpp>  //static  S32 LLFloaterModelPreview::sUploadAmount = 10;  LLFloaterModelPreview* LLFloaterModelPreview::sInstance = NULL; -std::list<LLModelLoader*> LLModelLoader::sActiveLoaderList; + +bool LLModelPreview::sIgnoreLoadedCallback = false;  // "Retain%" decomp parameter has values from 0.0 to 1.0 by 0.01  // But according to the UI spec for upload model floater, this parameter @@ -199,190 +173,37 @@ std::string lod_label_name[NUM_LOD+1] =  	"I went off the end of the lod_label_name array.  Me so smart."  }; -std::string colladaVersion[VERSIONTYPE_COUNT+1] =  -{ -	"1.4.0", -	"1.4.1", -	"Unsupported" -}; - - -#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) +BOOL stop_gloderror()  { +	GLuint error = glodGetError(); -	for (U32 v = 0; v < face.mNumVertices; v++) -	{ -		if(face.mPositions && !face.mPositions[v].isFinite3()) -		{ -			LL_WARNS() << "NaN position data in face found!" << LL_ENDL; -			return false; -		} - -		if(face.mNormals && !face.mNormals[v].isFinite3()) -		{ -			LL_WARNS() << "NaN normal data in face found!" << LL_ENDL; -			return false; -		} -	} - -	for (U32 i = 0; i < face.mNumIndices; ++i) -	{ -		if (face.mIndices[i] >= face.mNumVertices) -		{ -			LL_WARNS() << "Face has invalid index." << LL_ENDL; -			return false; -		} -	} - -	if (face.mNumIndices % 3 != 0 || face.mNumIndices == 0) +	if (error != GLOD_NO_ERROR)  	{ -		LL_WARNS() << "Face has invalid number of indices." << LL_ENDL; -		return false; +		LL_WARNS() << "GLOD error detected, cannot generate LOD: " << std::hex << error << LL_ENDL; +		return TRUE;  	} - -	/*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)) -		{ -			LL_WARNS() << "Degenerate face found!" << LL_ENDL; -			return false; -		} -	}*/ -	return true; +	return FALSE;  } -bool validate_model(const LLModel* mdl) +LLViewerFetchedTexture* bindMaterialDiffuseTexture(const LLImportMaterial& material)  { -	if (mdl->getNumVolumeFaces() == 0) -	{ -		LL_WARNS() << "Model has no faces!" << LL_ENDL; -		return false; -	} +	LLViewerFetchedTexture *texture = LLViewerTextureManager::getFetchedTexture(material.getDiffuseMap(), FTT_DEFAULT, TRUE, LLGLTexture::BOOST_PREVIEW); -	for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i) +	if (texture)  	{ -		if (mdl->getVolumeFace(i).mNumVertices == 0) +		if (texture->getDiscardLevel() > -1)  		{ -			LL_WARNS() << "Face has no vertices." << LL_ENDL; -			return false; -		} - -		if (mdl->getVolumeFace(i).mNumIndices == 0) -		{ -			LL_WARNS() << "Face has no indices." << LL_ENDL; -			return false; -		} - -		if (!validate_face(mdl->getVolumeFace(i))) -		{ -			return false; +			gGL.getTexUnit(0)->bind(texture, true); +			return texture;  		}  	} -	return true; +	return NULL;  } -BOOL stop_gloderror() -{ -	GLuint error = glodGetError(); - -	if (error != GLOD_NO_ERROR) -	{ -		LL_WARNS() << "GLOD error detected, cannot generate LOD: " << std::hex << error << LL_ENDL; -		return TRUE; -	} - -	return FALSE; -} - -  LLMeshFilePicker::LLMeshFilePicker(LLModelPreview* mp, S32 lod) -	: LLFilePickerThread(LLFilePicker::FFLOAD_COLLADA) +: LLFilePickerThread(LLFilePicker::FFLOAD_COLLADA)  	{  		mMP = mp;  		mLOD = lod; @@ -393,6 +214,29 @@ void LLMeshFilePicker::notify(const std::string& filename)  	mMP->loadModel(mFile, mLOD);  } +void FindModel(LLModelLoader::scene& scene, const std::string& name_to_match, LLModel*& baseModelOut, LLMatrix4& matOut) +{ +    LLModelLoader::scene::iterator base_iter = scene.begin(); +    bool found = false; +    while (!found && (base_iter != scene.end())) +    { +        matOut = base_iter->first; + +        LLModelLoader::model_instance_list::iterator base_instance_iter = base_iter->second.begin(); +        while (!found && (base_instance_iter != base_iter->second.end())) +        { +		    LLModelInstance& base_instance = *base_instance_iter++;					    		     +            LLModel* base_model = base_instance.mModel; +          +            if (base_model && (base_model->mLabel == name_to_match)) +            { +                baseModelOut = base_model; +                return; +            } +        } +        base_iter++; +    } +}  //-----------------------------------------------------------------------------  // LLFloaterModelPreview() @@ -613,6 +457,11 @@ void LLFloaterModelPreview::disableViewOption(const std::string& option)  void LLFloaterModelPreview::loadModel(S32 lod)  {  	mModelPreview->mLoading = true; +	if (lod == LLModel::LOD_PHYSICS) +	{ +		// loading physics from file +		mModelPreview->mPhysicsSearchLOD = lod; +	}  	(new LLMeshFilePicker(mModelPreview, lod))->getFile();  } @@ -791,9 +640,9 @@ void LLFloaterModelPreview::draw()  			childSetTextArg("status", "[STATUS]", getString("status_material_mismatch"));  		}  		else -		if ( mModelPreview->getLoadState() > LLModelLoader::ERROR_PARSING ) -		{		 -			childSetTextArg("status", "[STATUS]", getString(LLModel::getStatusString(mModelPreview->getLoadState() - LLModelLoader::ERROR_PARSING))); +		if ( mModelPreview->getLoadState() > LLModelLoader::ERROR_MODEL ) +		{ +			childSetTextArg("status", "[STATUS]", getString(LLModel::getStatusString(mModelPreview->getLoadState() - LLModelLoader::ERROR_MODEL)));  		}  		else  		if ( mModelPreview->getLoadState() == LLModelLoader::ERROR_PARSING ) @@ -945,9 +794,16 @@ BOOL LLFloaterModelPreview::handleScrollWheel(S32 x, S32 y, S32 clicks)  /*virtual*/  void LLFloaterModelPreview::onOpen(const LLSD& key)  { +	LLModelPreview::sIgnoreLoadedCallback = false;  	requestAgentUploadPermissions();  } +/*virtual*/ +void LLFloaterModelPreview::onClose(bool app_quitting) +{ +	LLModelPreview::sIgnoreLoadedCallback = true; +} +  //static  void LLFloaterModelPreview::onPhysicsParamCommit(LLUICtrl* ctrl, void* data)  { @@ -1308,1815 +1164,6 @@ void LLFloaterModelPreview::onMouseCaptureLostModelPreview(LLMouseHandler* handl  }  //----------------------------------------------------------------------------- -// LLModelLoader -//----------------------------------------------------------------------------- -LLModelLoader::LLModelLoader( std::string filename, S32 lod, LLModelPreview* preview, JointTransformMap& jointMap,  -							  std::deque<std::string>& jointsFromNodes ) -: mJointList( jointMap ) -, mJointsFromNode( jointsFromNodes ) -, LLThread("Model Loader"), mFilename(filename), mLod(lod), mPreview(preview), mFirstTransform(TRUE), mNumOfFetchingTextures(0) -{ -	mJointMap["mPelvis"] = "mPelvis"; -	mJointMap["mTorso"] = "mTorso"; -	mJointMap["mChest"] = "mChest"; -	mJointMap["mNeck"] = "mNeck"; -	mJointMap["mHead"] = "mHead"; -	mJointMap["mSkull"] = "mSkull"; -	mJointMap["mEyeRight"] = "mEyeRight"; -	mJointMap["mEyeLeft"] = "mEyeLeft"; -	mJointMap["mCollarLeft"] = "mCollarLeft"; -	mJointMap["mShoulderLeft"] = "mShoulderLeft"; -	mJointMap["mElbowLeft"] = "mElbowLeft"; -	mJointMap["mWristLeft"] = "mWristLeft"; -	mJointMap["mCollarRight"] = "mCollarRight"; -	mJointMap["mShoulderRight"] = "mShoulderRight"; -	mJointMap["mElbowRight"] = "mElbowRight"; -	mJointMap["mWristRight"] = "mWristRight"; -	mJointMap["mHipRight"] = "mHipRight"; -	mJointMap["mKneeRight"] = "mKneeRight"; -	mJointMap["mAnkleRight"] = "mAnkleRight"; -	mJointMap["mFootRight"] = "mFootRight"; -	mJointMap["mToeRight"] = "mToeRight"; -	mJointMap["mHipLeft"] = "mHipLeft"; -	mJointMap["mKneeLeft"] = "mKneeLeft"; -	mJointMap["mAnkleLeft"] = "mAnkleLeft"; -	mJointMap["mFootLeft"] = "mFootLeft"; -	mJointMap["mToeLeft"] = "mToeLeft"; - -	mJointMap["avatar_mPelvis"] = "mPelvis"; -	mJointMap["avatar_mTorso"] = "mTorso"; -	mJointMap["avatar_mChest"] = "mChest"; -	mJointMap["avatar_mNeck"] = "mNeck"; -	mJointMap["avatar_mHead"] = "mHead"; -	mJointMap["avatar_mSkull"] = "mSkull"; -	mJointMap["avatar_mEyeRight"] = "mEyeRight"; -	mJointMap["avatar_mEyeLeft"] = "mEyeLeft"; -	mJointMap["avatar_mCollarLeft"] = "mCollarLeft"; -	mJointMap["avatar_mShoulderLeft"] = "mShoulderLeft"; -	mJointMap["avatar_mElbowLeft"] = "mElbowLeft"; -	mJointMap["avatar_mWristLeft"] = "mWristLeft"; -	mJointMap["avatar_mCollarRight"] = "mCollarRight"; -	mJointMap["avatar_mShoulderRight"] = "mShoulderRight"; -	mJointMap["avatar_mElbowRight"] = "mElbowRight"; -	mJointMap["avatar_mWristRight"] = "mWristRight"; -	mJointMap["avatar_mHipRight"] = "mHipRight"; -	mJointMap["avatar_mKneeRight"] = "mKneeRight"; -	mJointMap["avatar_mAnkleRight"] = "mAnkleRight"; -	mJointMap["avatar_mFootRight"] = "mFootRight"; -	mJointMap["avatar_mToeRight"] = "mToeRight"; -	mJointMap["avatar_mHipLeft"] = "mHipLeft"; -	mJointMap["avatar_mKneeLeft"] = "mKneeLeft"; -	mJointMap["avatar_mAnkleLeft"] = "mAnkleLeft"; -	mJointMap["avatar_mFootLeft"] = "mFootLeft"; -	mJointMap["avatar_mToeLeft"] = "mToeLeft"; - - -	mJointMap["hip"] = "mPelvis"; -	mJointMap["abdomen"] = "mTorso"; -	mJointMap["chest"] = "mChest"; -	mJointMap["neck"] = "mNeck"; -	mJointMap["head"] = "mHead"; -	mJointMap["figureHair"] = "mSkull"; -	mJointMap["lCollar"] = "mCollarLeft"; -	mJointMap["lShldr"] = "mShoulderLeft"; -	mJointMap["lForeArm"] = "mElbowLeft"; -	mJointMap["lHand"] = "mWristLeft"; -	mJointMap["rCollar"] = "mCollarRight"; -	mJointMap["rShldr"] = "mShoulderRight"; -	mJointMap["rForeArm"] = "mElbowRight"; -	mJointMap["rHand"] = "mWristRight"; -	mJointMap["rThigh"] = "mHipRight"; -	mJointMap["rShin"] = "mKneeRight"; -	mJointMap["rFoot"] = "mFootRight"; -	mJointMap["lThigh"] = "mHipLeft"; -	mJointMap["lShin"] = "mKneeLeft"; -	mJointMap["lFoot"] = "mFootLeft"; - -	if (mPreview) -	{ -		//only try to load from slm if viewer is configured to do so and this is the  -		//initial model load (not an LoD or physics shape) -		mTrySLM = gSavedSettings.getBOOL("MeshImportUseSLM") && mPreview->mUploadData.empty(); -		mPreview->setLoadState(STARTING); -	} -	else -	{ -		mTrySLM = false; -	} - -	assert_main_thread(); -	sActiveLoaderList.push_back(this) ; -} - -LLModelLoader::~LLModelLoader() -{ -	assert_main_thread(); -	sActiveLoaderList.remove(this); -} - -void stretch_extents(LLModel* model, LLMatrix4a& mat, LLVector4a& min, LLVector4a& max, BOOL& first_transform) -{ -	LLVector4a box[] = -	{ -		LLVector4a(-1, 1,-1), -		LLVector4a(-1, 1, 1), -		LLVector4a(-1,-1,-1), -		LLVector4a(-1,-1, 1), -		LLVector4a( 1, 1,-1), -		LLVector4a( 1, 1, 1), -		LLVector4a( 1,-1,-1), -		LLVector4a( 1,-1, 1), -	}; - -	for (S32 j = 0; j < model->getNumVolumeFaces(); ++j) -	{ -		const LLVolumeFace& face = model->getVolumeFace(j); - -		LLVector4a center; -		center.setAdd(face.mExtents[0], face.mExtents[1]); -		center.mul(0.5f); -		LLVector4a size; -		size.setSub(face.mExtents[1],face.mExtents[0]); -		size.mul(0.5f); - -		for (U32 i = 0; i < 8; i++) -		{ -			LLVector4a t; -			t.setMul(size, box[i]); -			t.add(center); - -			LLVector4a v; - -			mat.affineTransform(t, v); - -			if (first_transform) -			{ -				first_transform = FALSE; -				min = max = v; -			} -			else -			{ -				update_min_max(min, max, v); -			} -		} -	} -} - -void stretch_extents(LLModel* model, LLMatrix4& mat, LLVector3& min, LLVector3& max, BOOL& first_transform) -{ -	LLVector4a mina, maxa; -	LLMatrix4a mata; - -	mata.loadu(mat); -	mina.load3(min.mV); -	maxa.load3(max.mV); - -	stretch_extents(model, mata, mina, maxa, first_transform); - -	min.set(mina.getF32ptr()); -	max.set(maxa.getF32ptr()); -} - -void LLModelLoader::run() -{ -	doLoadModel(); -	doOnIdleOneTime(boost::bind(&LLModelLoader::loadModelCallback,this)); -} - -bool LLModelLoader::doLoadModel() -{ -	//first, look for a .slm file of the same name that was modified later -	//than the .dae - -	if (mTrySLM) -	{ -		std::string filename = mFilename; -			 -		std::string::size_type i = filename.rfind("."); -		if (i != std::string::npos) -		{ -			filename.replace(i, filename.size()-1, ".slm"); -			llstat slm_status; -			if (LLFile::stat(filename, &slm_status) == 0) -			{ //slm file exists -				llstat dae_status; -				if (LLFile::stat(mFilename, &dae_status) != 0 || -					dae_status.st_mtime < slm_status.st_mtime) -				{ -					if (loadFromSLM(filename)) -					{ //slm successfully loaded, if this fails, fall through and -						//try loading from dae - -						mLod = -1; //successfully loading from an slm implicitly sets all  -									//LoDs -						return true; -					} -				} -			}	 -		} -	} - -	//no suitable slm exists, load from the .dae file -	DAE dae; -	domCOLLADA* dom = dae.open(mFilename); -	 -	if (!dom) -	{ -		LL_INFOS()<<" Error with dae - traditionally indicates a corrupt file."<<LL_ENDL; -		setLoadState( ERROR_PARSING ); -		return false; -	} -	//Dom version -	daeString domVersion = dae.getDomVersion(); -	std::string sldom(domVersion); -	LL_INFOS()<<"Collada Importer Version: "<<sldom<<LL_ENDL; -	//Dae version -	domVersionType docVersion = dom->getVersion(); -	//0=1.4 -	//1=1.4.1 -	//2=Currently unsupported, however may work -	if (docVersion > 1 )  -	{  -		docVersion = VERSIONTYPE_COUNT; -	} -	LL_INFOS()<<"Dae version "<<colladaVersion[docVersion]<<LL_ENDL; -	 -	 -	daeDatabase* db = dae.getDatabase(); -	 -	daeInt count = db->getElementCount(NULL, COLLADA_TYPE_MESH); -	 -	daeDocument* doc = dae.getDoc(mFilename); -	if (!doc) -	{ -		LL_WARNS() << "can't find internal doc" << LL_ENDL; -		return false; -	} -	 -	daeElement* root = doc->getDomRoot(); -	if (!root) -	{ -		LL_WARNS() << "document has no root" << LL_ENDL; -		return false; -	} -	 -	//Verify some basic properties of the dae -	//1. Basic validity check on controller  -	U32 controllerCount = (int) db->getElementCount( NULL, "controller" ); -	bool result = false; -	for ( int i=0; i<controllerCount; ++i ) -	{ -		domController* pController = NULL; -		db->getElement( (daeElement**) &pController, i , NULL, "controller" ); -		result = mPreview->verifyController( pController ); -		if (!result) -		{ -			setLoadState( ERROR_PARSING ); -			return true; -		} -	} - - -	//get unit scale -	mTransform.setIdentity(); -	 -	domAsset::domUnit* unit = daeSafeCast<domAsset::domUnit>(root->getDescendant(daeElement::matchType(domAsset::domUnit::ID()))); -	 -	if (unit) -	{ -		F32 meter = unit->getMeter(); -		mTransform.mMatrix[0][0] = meter; -		mTransform.mMatrix[1][1] = meter; -		mTransform.mMatrix[2][2] = meter; -	} -	 -	//get up axis rotation -	LLMatrix4 rotation; -	 -	domUpAxisType up = UPAXISTYPE_Y_UP;  // default is Y_UP -	domAsset::domUp_axis* up_axis = -	daeSafeCast<domAsset::domUp_axis>(root->getDescendant(daeElement::matchType(domAsset::domUp_axis::ID()))); -	 -	if (up_axis) -	{ -		up = up_axis->getValue(); -	} -	 -	if (up == UPAXISTYPE_X_UP) -	{ -		rotation.initRotation(0.0f, 90.0f * DEG_TO_RAD, 0.0f); -	} -	else if (up == UPAXISTYPE_Y_UP) -	{ -		rotation.initRotation(90.0f * DEG_TO_RAD, 0.0f, 0.0f); -	} -	 -	rotation *= mTransform; -	mTransform = rotation; -	 -	 -	for (daeInt idx = 0; idx < count; ++idx) -	{ //build map of domEntities to LLModel -		domMesh* mesh = NULL; -		db->getElement((daeElement**) &mesh, idx, NULL, COLLADA_TYPE_MESH); -		 -		if (mesh) -		{ -			LLPointer<LLModel> model = LLModel::loadModelFromDomMesh(mesh); -			 -			if(model->getStatus() != LLModel::NO_ERRORS) -			{ -				setLoadState(ERROR_PARSING + model->getStatus()) ; -				return false; //abort -			} - -			if (model.notNull() && validate_model(model)) -			{ -				mModelList.push_back(model); -				mModel[mesh] = model; -			} -		} -	} -	 -	count = db->getElementCount(NULL, COLLADA_TYPE_SKIN); -	for (daeInt idx = 0; idx < count; ++idx) -	{ //add skinned meshes as instances -		domSkin* skin = NULL; -		db->getElement((daeElement**) &skin, idx, NULL, COLLADA_TYPE_SKIN); -		 -		if (skin) -		{ -			domGeometry* geom = daeSafeCast<domGeometry>(skin->getSource().getElement()); -			 -			if (geom) -			{ -				domMesh* mesh = geom->getMesh(); -				if (mesh) -				{ -					LLModel* model = mModel[mesh]; -					if (model) -					{ -						LLVector3 mesh_scale_vector; -						LLVector3 mesh_translation_vector; -						model->getNormalizedScaleTranslation(mesh_scale_vector, mesh_translation_vector); -						 -						LLMatrix4 normalized_transformation; -						normalized_transformation.setTranslation(mesh_translation_vector); -						 -						LLMatrix4 mesh_scale; -						mesh_scale.initScale(mesh_scale_vector); -						mesh_scale *= normalized_transformation; -						normalized_transformation = mesh_scale; -						 -						glh::matrix4f inv_mat((F32*) normalized_transformation.mMatrix); -						inv_mat = inv_mat.inverse(); -						LLMatrix4 inverse_normalized_transformation(inv_mat.m); -						 -						domSkin::domBind_shape_matrix* bind_mat = skin->getBind_shape_matrix(); -						 -						if (bind_mat) -						{ //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++) -								{ -									skin_info.mBindShapeMatrix.mMatrix[i][j] = dom_value[i + j*4]; -								} -							} -							 -							LLMatrix4 trans = normalized_transformation; -							trans *= skin_info.mBindShapeMatrix; -							skin_info.mBindShapeMatrix = trans;							 -						} -										 -											 -						//Some collada setup for accessing the skeleton -						daeElement* pElement = 0; -						dae.getDatabase()->getElement( &pElement, 0, 0, "skeleton" ); -						 -						//Try to get at the skeletal instance controller -						domInstance_controller::domSkeleton* pSkeleton = daeSafeCast<domInstance_controller::domSkeleton>( pElement ); -						bool missingSkeletonOrScene = false; -						 -						//If no skeleton, do a breadth-first search to get at specific joints -						bool rootNode = false; -						 -						//Need to test for a skeleton that does not have a root node -						//This occurs when your instance controller does not have an associated scene  -						if ( pSkeleton ) -						{ -							daeElement* pSkeletonRootNode = pSkeleton->getValue().getElement(); -							if ( pSkeletonRootNode ) -							{ -								rootNode = true; -							} - -						} -						if ( !pSkeleton || !rootNode ) -						{ -							daeElement* pScene = root->getDescendant("visual_scene"); -							if ( !pScene ) -							{ -								LL_WARNS()<<"No visual scene - unable to parse bone offsets "<<LL_ENDL; -								missingSkeletonOrScene = true; -							} -							else -							{ -								//Get the children at this level -								daeTArray< daeSmartRef<daeElement> > children = pScene->getChildren(); -								S32 childCount = children.getCount(); -								 -								//Process any children that are joints -								//Not all children are joints, some code be ambient lights, cameras, geometry etc.. -								for (S32 i = 0; i < childCount; ++i) -								{ -									domNode* pNode = daeSafeCast<domNode>(children[i]); -									if ( isNodeAJoint( pNode ) ) -									{ -										processJointNode( pNode, mJointList ); -									} -								} -							} -						} -						else -							//Has Skeleton -						{ -							//Get the root node of the skeleton -							daeElement* pSkeletonRootNode = pSkeleton->getValue().getElement(); -							if ( pSkeletonRootNode ) -							{ -								//Once we have the root node - start acccessing it's joint components -								const int jointCnt = mJointMap.size(); -								std::map<std::string, std::string> :: const_iterator jointIt = mJointMap.begin(); -								 -								//Loop over all the possible joints within the .dae - using the allowed joint list in the ctor. -								for ( int i=0; i<jointCnt; ++i, ++jointIt ) -								{ -									//Build a joint for the resolver to work with -									char str[64]={0}; -									sprintf(str,"./%s",(*jointIt).first.c_str() ); -									//LL_WARNS()<<"Joint "<< str <<LL_ENDL; -									 -									//Setup the resolver -                                    daeSIDResolver resolver( pSkeletonRootNode, str ); -									 -                                    //Look for the joint -                                    domNode* pJoint = daeSafeCast<domNode>( resolver.getElement() ); -                                    if ( pJoint ) -                                    { -										//Pull out the translate id and store it in the jointTranslations map -										daeSIDResolver jointResolverA( pJoint, "./translate" ); -										domTranslate* pTranslateA = daeSafeCast<domTranslate>( jointResolverA.getElement() ); -										daeSIDResolver jointResolverB( pJoint, "./location" ); -										domTranslate* pTranslateB = daeSafeCast<domTranslate>( jointResolverB.getElement() ); -										 -										LLMatrix4 workingTransform; -										 -										//Translation via SID -										if ( pTranslateA ) -										{ -											extractTranslation( pTranslateA, workingTransform ); -										} -										else -										if ( pTranslateB ) -										{ -											extractTranslation( pTranslateB, workingTransform ); -										} -										else -										{ -											//Translation via child from element -											daeElement* pTranslateElement = getChildFromElement( pJoint, "translate" ); -											if ( pTranslateElement && pTranslateElement->typeID() != domTranslate::ID() ) -											{ -												LL_WARNS()<< "The found element is not a translate node" <<LL_ENDL; -												missingSkeletonOrScene = true; -											} -											else -											if ( pTranslateElement ) -											{ -												extractTranslationViaElement( pTranslateElement, workingTransform ); -											} -											else -											{ -												extractTranslationViaSID( pJoint, workingTransform ); -											} - -										} -										 -										//Store the joint transform w/respect to it's name. -										mJointList[(*jointIt).second.c_str()] = workingTransform; -                                    } -								} -								 -								//If anything failed in regards to extracting the skeleton, joints or translation id, -								//mention it -								if ( missingSkeletonOrScene  ) -								{ -									LL_WARNS()<< "Partial jointmap found in asset - did you mean to just have a partial map?" << LL_ENDL; -								} -							}//got skeleton? -						} -						 -						 -						domSkin::domJoints* joints = skin->getJoints(); -						 -						domInputLocal_Array& joint_input = joints->getInput_array(); -						 -						for (size_t i = 0; i < joint_input.getCount(); ++i) -						{ -							domInputLocal* input = joint_input.get(i); -							xsNMTOKEN semantic = input->getSemantic(); -							 -							if (strcmp(semantic, COMMON_PROFILE_INPUT_JOINT) == 0) -							{ //found joint source, fill model->mJointMap and model->mSkinInfo.mJointNames -								daeElement* elem = input->getSource().getElement(); -								 -								domSource* source = daeSafeCast<domSource>(elem); -								if (source) -								{ -									 -									 -									domName_array* names_source = source->getName_array(); -									 -									if (names_source) -									{ -										domListOfNames &names = names_source->getValue(); -										 -										for (size_t j = 0; j < names.getCount(); ++j) -										{ -											std::string name(names.get(j)); -											if (mJointMap.find(name) != mJointMap.end()) -											{ -												name = mJointMap[name]; -											} -											model->mSkinInfo.mJointNames.push_back(name); -											model->mSkinInfo.mJointMap[name] = j; -										} -									} -									else -									{ -										domIDREF_array* names_source = source->getIDREF_array(); -										if (names_source) -										{ -											xsIDREFS& names = names_source->getValue(); -											 -											for (size_t j = 0; j < names.getCount(); ++j) -											{ -												std::string name(names.get(j).getID()); -												if (mJointMap.find(name) != mJointMap.end()) -												{ -													name = mJointMap[name]; -												} -												model->mSkinInfo.mJointNames.push_back(name); -												model->mSkinInfo.mJointMap[name] = j; -											} -										} -									} -								} -							} -							else if (strcmp(semantic, COMMON_PROFILE_INPUT_INV_BIND_MATRIX) == 0) -							{ //found inv_bind_matrix array, fill model->mInvBindMatrix -								domSource* source = daeSafeCast<domSource>(input->getSource().getElement()); -								if (source) -								{ -									domFloat_array* t = source->getFloat_array(); -									if (t) -									{ -										domListOfFloats& transform = t->getValue(); -										S32 count = transform.getCount()/16; -										 -										for (S32 k = 0; k < count; ++k) -										{ -											LLMatrix4 mat; -											 -											for (int i = 0; i < 4; i++) -											{ -												for(int j = 0; j < 4; j++) -												{ -													mat.mMatrix[i][j] = transform[k*16 + i + j*4]; -												} -											} -											 -											model->mSkinInfo.mInvBindMatrix.push_back(mat);											 -										} -									} -								} -							} -						} -						 -						//Now that we've parsed the joint array, let's determine if we have a full rig -						//(which means we have all the joint sthat 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).						 -						buildJointToNodeMappingFromScene( root ); -						mPreview->critiqueRigForUploadApplicability( model->mSkinInfo.mJointNames ); -										 -						if ( !missingSkeletonOrScene ) -						{ -							//Set the joint translations on the avatar - if it's a full mapping -							//The joints are reset in the dtor -							if ( mPreview->getRigWithSceneParity() ) -							{	 -								std::map<std::string, std::string> :: const_iterator masterJointIt = mJointMap.begin(); -								std::map<std::string, std::string> :: const_iterator masterJointItEnd = mJointMap.end(); -								for (;masterJointIt!=masterJointItEnd;++masterJointIt ) -								{ -									std::string lookingForJoint = (*masterJointIt).first.c_str(); -									 -									if ( mJointList.find( lookingForJoint ) != mJointList.end() ) -									{ -										//LL_INFOS()<<"joint "<<lookingForJoint.c_str()<<LL_ENDL; -										LLMatrix4 jointTransform = mJointList[lookingForJoint]; -										LLJoint* pJoint = mPreview->getPreviewAvatar()->getJoint( lookingForJoint ); -										if ( pJoint ) -										{    -											LLUUID fake_mesh_id; -											fake_mesh_id.generate(); -											pJoint->addAttachmentPosOverride( jointTransform.getTranslation(), fake_mesh_id, gAgentAvatarp->avString()); -										} -										else -										{ -											//Most likely an error in the asset. -											LL_WARNS()<<"Tried to apply joint position from .dae, but it did not exist in the avatar rig." << LL_ENDL; -										} -									} -								} -							} -						} //missingSkeletonOrScene -						 -						 -						//We need to construct the alternate bind matrix (which contains the new joint positions) -						//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->mSkinInfo.mJointNames.begin(); -						const int jointCnt = model->mSkinInfo.mJointNames.size(); -						for ( int i=0; i<jointCnt; ++i, ++jointIt ) -						{ -							std::string lookingForJoint = (*jointIt).c_str(); -							//Look for the joint xform that we extracted from the skeleton, using the jointIt as the key -							//and store it in the alternate bind matrix -							if ( mJointList.find( lookingForJoint ) != mJointList.end() ) -							{ -								LLMatrix4 jointTransform = mJointList[lookingForJoint]; -								LLMatrix4 newInverse = model->mSkinInfo.mInvBindMatrix[i]; -								newInverse.setTranslation( mJointList[lookingForJoint].getTranslation() ); -								model->mSkinInfo.mAlternateBindMatrix.push_back( newInverse ); -							} -							else -							{ -								LL_WARNS()<<"Possibly misnamed/missing joint [" <<lookingForJoint.c_str()<<" ] "<<LL_ENDL; -							} -						} -						 -						//grab raw position array -						 -						domVertices* verts = mesh->getVertices(); -						if (verts) -						{ -							domInputLocal_Array& inputs = verts->getInput_array(); -							for (size_t i = 0; i < inputs.getCount() && model->mPosition.empty(); ++i) -							{ -								if (strcmp(inputs[i]->getSemantic(), COMMON_PROFILE_INPUT_POSITION) == 0) -								{ -									domSource* pos_source = daeSafeCast<domSource>(inputs[i]->getSource().getElement()); -									if (pos_source) -									{ -										domFloat_array* pos_array = pos_source->getFloat_array(); -										if (pos_array) -										{ -											domListOfFloats& pos = pos_array->getValue(); -											 -											for (size_t j = 0; j < pos.getCount(); j += 3) -											{ -												if (pos.getCount() <= j+2) -												{ -													LL_ERRS() << "Invalid position array size." << LL_ENDL; -												} -												 -												LLVector3 v(pos[j], pos[j+1], pos[j+2]); -												 -												//transform from COLLADA space to volume space -												v = v * inverse_normalized_transformation; -												 -												model->mPosition.push_back(v); -											} -										} -									} -								} -							} -						} -						 -						//grab skin weights array -						domSkin::domVertex_weights* weights = skin->getVertex_weights(); -						if (weights) -						{ -							domInputLocalOffset_Array& inputs = weights->getInput_array(); -							domFloat_array* vertex_weights = NULL; -							for (size_t i = 0; i < inputs.getCount(); ++i) -							{ -								if (strcmp(inputs[i]->getSemantic(), COMMON_PROFILE_INPUT_WEIGHT) == 0) -								{ -									domSource* weight_source = daeSafeCast<domSource>(inputs[i]->getSource().getElement()); -									if (weight_source) -									{ -										vertex_weights = weight_source->getFloat_array(); -									} -								} -							} -							 -							if (vertex_weights) -							{ -								domListOfFloats& w = vertex_weights->getValue(); -								domListOfUInts& vcount = weights->getVcount()->getValue(); -								domListOfInts& v = weights->getV()->getValue(); -								 -								U32 c_idx = 0; -								for (size_t vc_idx = 0; vc_idx < vcount.getCount(); ++vc_idx) -								{ //for each vertex -									daeUInt count = vcount[vc_idx]; -									 -									//create list of weights that influence this vertex -									LLModel::weight_list weight_list; -									 -									for (daeUInt i = 0; i < count; ++i) -									{ //for each weight -										daeInt joint_idx = v[c_idx++]; -										daeInt weight_idx = v[c_idx++]; -										 -										if (joint_idx == -1) -										{ -											//ignore bindings to bind_shape_matrix -											continue; -										} -										 -										F32 weight_value = w[weight_idx]; -										 -										weight_list.push_back(LLModel::JointWeight(joint_idx, weight_value)); -									} -									 -									//sort by joint weight -									std::sort(weight_list.begin(), weight_list.end(), LLModel::CompareWeightGreater()); -									 -									std::vector<LLModel::JointWeight> wght; -									 -									F32 total = 0.f; -									 -									for (U32 i = 0; i < llmin((U32) 4, (U32) weight_list.size()); ++i) -									{ //take up to 4 most significant weights -										if (weight_list[i].mWeight > 0.f) -										{ -											wght.push_back( weight_list[i] ); -											total += weight_list[i].mWeight; -										} -									} -									 -									F32 scale = 1.f/total; -									if (scale != 1.f) -									{ //normalize weights -										for (U32 i = 0; i < wght.size(); ++i) -										{ -											wght[i].mWeight *= scale; -										} -									} -									 -									model->mSkinWeights[model->mPosition[vc_idx]] = wght; -								} -								 -								//add instance to scene for this model -								 -								LLMatrix4 transformation = mTransform; -								// adjust the transformation to compensate for mesh normalization -								 -								LLMatrix4 mesh_translation; -								mesh_translation.setTranslation(mesh_translation_vector); -								mesh_translation *= transformation; -								transformation = mesh_translation; -								 -								LLMatrix4 mesh_scale; -								mesh_scale.initScale(mesh_scale_vector); -								mesh_scale *= transformation; -								transformation = mesh_scale; -								 -								std::map<std::string, LLImportMaterial> materials; -								for (U32 i = 0; i < model->mMaterialList.size(); ++i) -								{ -									materials[model->mMaterialList[i]] = LLImportMaterial(); -								} -								mScene[transformation].push_back(LLModelInstance(model, model->mLabel, transformation, materials)); -								stretch_extents(model, transformation, mExtents[0], mExtents[1], mFirstTransform); -							} -						} -					} -				} -			} -		} -	} -	 -	daeElement* scene = root->getDescendant("visual_scene"); -	 -	if (!scene) -	{ -		LL_WARNS() << "document has no visual_scene" << LL_ENDL; -		setLoadState( ERROR_PARSING ); -		return true; -	} -	 -	setLoadState( DONE ); - -	bool badElement = false; -	 -	processElement( scene, badElement ); -	 -	if ( badElement ) -	{ -		setLoadState( ERROR_PARSING ); -	} -	 -	return true; -} - -void LLModelLoader::setLoadState(U32 state) -{ -	if (mPreview) -	{ -		mPreview->setLoadState(state); -	} -} - -bool LLModelLoader::loadFromSLM(const std::string& filename) -{  -	//only need to populate mScene with data from slm -	llstat stat; - -	if (LLFile::stat(filename, &stat)) -	{ //file does not exist -		return false; -	} - -	S32 file_size = (S32) stat.st_size; -	 -	llifstream ifstream(filename.c_str(), std::ifstream::in | std::ifstream::binary); -	LLSD data; -	LLSDSerialize::fromBinary(data, ifstream, file_size); -	ifstream.close(); - -	//build model list for each LoD -	model_list model[LLModel::NUM_LODS]; - -	if (data["version"].asInteger() != SLM_SUPPORTED_VERSION) -	{  //unsupported version -		return false; -	} - -	LLSD& mesh = data["mesh"]; - -	LLVolumeParams volume_params; -	volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); - -	for (S32 lod = 0; lod < LLModel::NUM_LODS; ++lod) -	{ -		for (U32 i = 0; i < mesh.size(); ++i) -		{ -			std::stringstream str(mesh[i].asString()); -			LLPointer<LLModel> loaded_model = new LLModel(volume_params, (F32) lod); -			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->critiqueRigForUploadApplicability( loaded_model->mSkinInfo.mJointNames );					 -				} -			} -		} -	}	 - -	if (model[LLModel::LOD_HIGH].empty()) -	{ //failed to load high lod -		return false; -	} - -	// Set name. -	std::string name = data["name"]; -	if (!name.empty()) -	{ -		model[LLModel::LOD_HIGH][0]->mLabel = name; -	} -	 - -	//load instance list -	model_instance_list instance_list; - -	LLSD& instance = data["instance"]; - -	for (U32 i = 0; i < instance.size(); ++i) -	{ -		//deserialize instance list -		instance_list.push_back(LLModelInstance(instance[i])); - -		//match up model instance pointers -		S32 idx = instance_list[i].mLocalMeshID; - -		for (U32 lod = 0; lod < LLModel::NUM_LODS; ++lod) -		{ -			if (!model[lod].empty()) -			{ -				instance_list[i].mLOD[lod] = model[lod][idx]; -			} -		} - -		instance_list[i].mModel = model[LLModel::LOD_HIGH][idx]; -	} - - -	//convert instance_list to mScene -	mFirstTransform = TRUE; -	for (U32 i = 0; i < instance_list.size(); ++i) -	{ -		LLModelInstance& cur_instance = instance_list[i]; -		mScene[cur_instance.mTransform].push_back(cur_instance); -		stretch_extents(cur_instance.mModel, cur_instance.mTransform, mExtents[0], mExtents[1], mFirstTransform); -	} -	 -	setLoadState( DONE ); - -	return true; -} - -//static -bool LLModelLoader::isAlive(LLModelLoader* loader) -{ -	if(!loader) -	{ -		return false ; -	} - -	std::list<LLModelLoader*>::iterator iter = sActiveLoaderList.begin() ; -	for(; iter != sActiveLoaderList.end() && (*iter) != loader; ++iter) ; -	 -	return *iter == loader ; -} - -void LLModelLoader::loadModelCallback() -{ -	assert_main_thread(); - -	if (mPreview) -	{ -		mPreview->loadModelCallback(mLod);	 -	} - -	while (!isStopped()) -	{ //wait until this thread is stopped before deleting self -		apr_sleep(100); -	} - -	//doubel check if "this" is valid before deleting it, in case it is aborted during running. -	if(!isAlive(this)) -	{ -		return ; -	} - -	//cleanup model loader -	if (mPreview) -	{ -		mPreview->mModelLoader = NULL; -	} - -	delete this; -} -//----------------------------------------------------------------------------- -// buildJointToNodeMappingFromScene() -//----------------------------------------------------------------------------- -void LLModelLoader::buildJointToNodeMappingFromScene( daeElement* pRoot ) -{ -	daeElement* pScene = pRoot->getDescendant("visual_scene"); -	if ( pScene ) -	{ -		daeTArray< daeSmartRef<daeElement> > children = pScene->getChildren(); -		S32 childCount = children.getCount(); -		for (S32 i = 0; i < childCount; ++i) -		{ -			domNode* pNode = daeSafeCast<domNode>(children[i]); -			processJointToNodeMapping( pNode );			 -		} -	} -} -//----------------------------------------------------------------------------- -// processJointToNodeMapping() -//----------------------------------------------------------------------------- -void LLModelLoader::processJointToNodeMapping( domNode* pNode ) -{ -	if ( isNodeAJoint( pNode ) ) -	{ -		//1.Store the parent -		std::string nodeName = pNode->getName(); -		if ( !nodeName.empty() ) -		{ -			mJointsFromNode.push_front( pNode->getName() ); -		} -		//2. Handle the kiddo's -		processChildJoints( pNode ); -	} -	else -	{ -		//Determine if the're any children wrt to this failed node. -		//This occurs when an armature is exported and ends up being what essentially amounts to -		//as the root for the visual_scene -		if ( pNode )  -		{ -			processChildJoints( pNode ); -		} -		else  -		{ -			LL_INFOS()<<"Node is NULL"<<LL_ENDL; -		} - -	} -} -//----------------------------------------------------------------------------- -// processChildJoint() -//----------------------------------------------------------------------------- -void LLModelLoader::processChildJoints( domNode* pParentNode ) -{	 -	daeTArray< daeSmartRef<daeElement> > childOfChild = pParentNode->getChildren(); -	S32 childOfChildCount = childOfChild.getCount(); -	for (S32 i = 0; i < childOfChildCount; ++i) -	{ -		domNode* pChildNode = daeSafeCast<domNode>( childOfChild[i] ); -		if ( pChildNode ) -		{ -			processJointToNodeMapping( pChildNode ); -		} -	} -} - -//----------------------------------------------------------------------------- -// critiqueRigForUploadApplicability() -//----------------------------------------------------------------------------- -void LLModelPreview::critiqueRigForUploadApplicability( const std::vector<std::string> &jointListFromAsset ) -{ -	critiqueJointToNodeMappingFromScene(); -	 -	//Determines the following use cases for a rig: -	//1. It is suitable for upload with skin weights & joint positions, or -	//2. It is suitable for upload as standard av with just skin weights -	 -	bool isJointPositionUploadOK = isRigSuitableForJointPositionUpload( jointListFromAsset ); -	bool isRigLegacyOK			 = isRigLegacy( jointListFromAsset ); - -	//It's OK that both could end up being true, both default to false -	if ( isJointPositionUploadOK ) -	{ -		setRigValidForJointPositionUpload( true ); -	} - -	if ( isRigLegacyOK)  -	{	 -		setLegacyRigValid( true ); -	} - -} -//----------------------------------------------------------------------------- -// critiqueJointToNodeMappingFromScene() -//----------------------------------------------------------------------------- -void LLModelPreview::critiqueJointToNodeMappingFromScene( void  ) -{ -	//Do the actual nodes back the joint listing from the dae? -	//if yes then this is a fully rigged asset, otherwise it's just a partial rig -	 -	std::deque<std::string>::iterator jointsFromNodeIt = mJointsFromNode.begin(); -	std::deque<std::string>::iterator jointsFromNodeEndIt = mJointsFromNode.end(); -	bool result = true; - -	if ( !mJointsFromNode.empty() ) -	{ -		for ( ;jointsFromNodeIt!=jointsFromNodeEndIt;++jointsFromNodeIt ) -		{ -			std::string name = *jointsFromNodeIt; -			if ( mJointTransformMap.find( name ) != mJointTransformMap.end() ) -			{ -				continue; -			} -			else -			{ -				LL_INFOS()<<"critiqueJointToNodeMappingFromScene is missing a: "<<name<<LL_ENDL; -				result = false;				 -			} -		} -	} -	else -	{ -		result = false; -	} - -	//Determines the following use cases for a rig: -	//1. Full av rig  w/1-1 mapping from the scene and joint array -	//2. Partial rig but w/o parity between the scene and joint array -	if ( result ) -	{		 -		setRigWithSceneParity( true ); -	}	 -} -//----------------------------------------------------------------------------- -// isRigLegacy() -//----------------------------------------------------------------------------- -bool LLModelPreview::isRigLegacy( const std::vector<std::string> &jointListFromAsset ) -{ -	//No joints in asset -	if ( jointListFromAsset.size() == 0 ) -	{ -		return false; -	} - -	bool result = false; - -	std::deque<std::string> :: const_iterator masterJointIt = mMasterLegacyJointList.begin();	 -	std::deque<std::string> :: const_iterator masterJointEndIt = mMasterLegacyJointList.end(); -	 -	std::vector<std::string> :: const_iterator modelJointIt = jointListFromAsset.begin();	 -	std::vector<std::string> :: const_iterator modelJointItEnd = jointListFromAsset.end(); -	 -	for ( ;masterJointIt!=masterJointEndIt;++masterJointIt ) -	{ -		result = false; -		modelJointIt = jointListFromAsset.begin(); - -		for ( ;modelJointIt!=modelJointItEnd; ++modelJointIt ) -		{ -			if ( *masterJointIt == *modelJointIt ) -			{ -				result = true; -				break; -			}			 -		}		 -		if ( !result ) -		{ -			LL_INFOS()<<" Asset did not contain the joint (if you're u/l a fully rigged asset w/joint positions - it is required)." << *masterJointIt<< LL_ENDL; -			break; -		} -	}	 -	return result; -} -//----------------------------------------------------------------------------- -// isRigSuitableForJointPositionUpload() -//----------------------------------------------------------------------------- -bool LLModelPreview::isRigSuitableForJointPositionUpload( const std::vector<std::string> &jointListFromAsset ) -{ -	bool result = false; - -	std::deque<std::string> :: const_iterator masterJointIt = mMasterJointList.begin();	 -	std::deque<std::string> :: const_iterator masterJointEndIt = mMasterJointList.end(); -	 -	std::vector<std::string> :: const_iterator modelJointIt = jointListFromAsset.begin();	 -	std::vector<std::string> :: const_iterator modelJointItEnd = jointListFromAsset.end(); -	 -	for ( ;masterJointIt!=masterJointEndIt;++masterJointIt ) -	{ -		result = false; -		modelJointIt = jointListFromAsset.begin(); - -		for ( ;modelJointIt!=modelJointItEnd; ++modelJointIt ) -		{ -			if ( *masterJointIt == *modelJointIt ) -			{ -				result = true; -				break; -			}			 -		}		 -		if ( !result ) -		{ -			LL_INFOS()<<" Asset did not contain the joint (if you're u/l a fully rigged asset w/joint positions - it is required)." << *masterJointIt<< LL_ENDL; -			break; -		} -	}	 -	return result; -} - - -//called in the main thread -void LLModelLoader::loadTextures() -{ -	BOOL is_paused = isPaused() ; -	pause() ; //pause the loader  - -	for(scene::iterator iter = mScene.begin(); iter != mScene.end(); ++iter) -	{ -		for(U32 i = 0 ; i < iter->second.size(); i++) -		{ -			for(std::map<std::string, LLImportMaterial>::iterator j = iter->second[i].mMaterial.begin(); -				j != iter->second[i].mMaterial.end(); ++j) -			{ -				LLImportMaterial& material = j->second; - -				if(!material.mDiffuseMapFilename.empty()) -				{ -					material.mDiffuseMap =  -						LLViewerTextureManager::getFetchedTextureFromUrl("file://" + material.mDiffuseMapFilename, FTT_LOCAL_FILE, TRUE, LLGLTexture::BOOST_PREVIEW); -					material.mDiffuseMap->setLoadedCallback(LLModelPreview::textureLoadedCallback, 0, TRUE, FALSE, mPreview, NULL, FALSE); -					material.mDiffuseMap->forceToSaveRawImage(0, F32_MAX); -					mNumOfFetchingTextures++ ; -				} -			} -		} -	} - -	if(!is_paused) -	{ -		unpause() ; -	} -} - -//----------------------------------------------------------------------------- -// isNodeAJoint() -//----------------------------------------------------------------------------- -bool LLModelLoader::isNodeAJoint( domNode* pNode ) -{ -	if ( !pNode ) -	{ -		LL_INFOS()<<"Created node is NULL"<<LL_ENDL; -		return false; -	} -	 -	if ( pNode->getName() == NULL ) -	{ -		LL_INFOS()<<"Parsed node has no name "<<LL_ENDL; -		//Attempt to write the node id, if possible (aids in debugging the visual scene) -		if ( pNode->getId() ) -		{ -			LL_INFOS()<<"Parsed node ID: "<<pNode->getId()<<LL_ENDL; -		} -		return false; -	} - -	if ( mJointMap.find( pNode->getName() )  != mJointMap.end() ) -	{ -		return true; -	} - -	return false; -} -//----------------------------------------------------------------------------- -// verifyCount -//----------------------------------------------------------------------------- -bool LLModelPreview::verifyCount( int expected, int result ) -{ -	if ( expected != result ) -	{ -		LL_INFOS()<< "Error: (expected/got)"<<expected<<"/"<<result<<"verts"<<LL_ENDL; -		return false; -	} -	return true; -} -//----------------------------------------------------------------------------- -// verifyController -//----------------------------------------------------------------------------- -bool LLModelPreview::verifyController( domController* pController ) -{	 - -	bool result = true; - -	domSkin* pSkin = pController->getSkin(); - -	if ( pSkin ) -	{ -		xsAnyURI & uri = pSkin->getSource(); -		domElement* pElement = uri.getElement(); - -		if ( !pElement ) -		{ -			LL_INFOS()<<"Can't resolve skin source"<<LL_ENDL; -			return false; -		} - -		daeString type_str = pElement->getTypeName(); -		if ( stricmp(type_str, "geometry") == 0 ) -		{	 -			//Skin is reference directly by geometry and get the vertex count from skin -			domSkin::domVertex_weights* pVertexWeights = pSkin->getVertex_weights(); -			U32 vertexWeightsCount = pVertexWeights->getCount(); -			domGeometry* pGeometry = (domGeometry*) (domElement*) uri.getElement(); -			domMesh* pMesh = pGeometry->getMesh();				 -			 -			if ( pMesh ) -			{ -				//Get vertex count from geometry -				domVertices* pVertices = pMesh->getVertices(); -				if ( !pVertices ) -				{  -					LL_INFOS()<<"No vertices!"<<LL_ENDL; -					return false; -				} - -				if ( pVertices ) -				{ -					xsAnyURI src = pVertices->getInput_array()[0]->getSource(); -					domSource* pSource = (domSource*) (domElement*) src.getElement(); -					U32 verticesCount = pSource->getTechnique_common()->getAccessor()->getCount(); -					result = verifyCount( verticesCount, vertexWeightsCount ); -					if ( !result ) -					{ -						return result; -					} -				} -			}	 - -			U32 vcountCount = (U32) pVertexWeights->getVcount()->getValue().getCount(); -			result = verifyCount( vcountCount, vertexWeightsCount );	 -			if ( !result ) -			{ -				return result; -			} - -			domInputLocalOffset_Array& inputs = pVertexWeights->getInput_array(); -			U32 sum = 0; -			for (size_t i=0; i<vcountCount; i++) -			{ -				sum += pVertexWeights->getVcount()->getValue()[i]; -			} -			result = verifyCount( sum * inputs.getCount(), (domInt) pVertexWeights->getV()->getValue().getCount() ); -		} -	} -	 -	return result; -} - -//----------------------------------------------------------------------------- -// extractTranslation() -//----------------------------------------------------------------------------- -void LLModelLoader::extractTranslation( domTranslate* pTranslate, LLMatrix4& transform ) -{ -	domFloat3 jointTrans = pTranslate->getValue(); -	LLVector3 singleJointTranslation( jointTrans[0], jointTrans[1], jointTrans[2] ); -	transform.setTranslation( singleJointTranslation ); -} -//----------------------------------------------------------------------------- -// extractTranslationViaElement() -//----------------------------------------------------------------------------- -void LLModelLoader::extractTranslationViaElement( daeElement* pTranslateElement, LLMatrix4& transform ) -{ -	if ( pTranslateElement ) -	{ -		domTranslate* pTranslateChild = dynamic_cast<domTranslate*>( pTranslateElement ); -		domFloat3 translateChild = pTranslateChild->getValue(); -		LLVector3 singleJointTranslation( translateChild[0], translateChild[1], translateChild[2] ); -		transform.setTranslation( singleJointTranslation ); -	}	 -} -//----------------------------------------------------------------------------- -// extractTranslationViaSID() -//----------------------------------------------------------------------------- -void LLModelLoader::extractTranslationViaSID( daeElement* pElement, LLMatrix4& transform ) -{ -	if ( pElement ) -	{	 -		daeSIDResolver resolver( pElement, "./transform" ); -		domMatrix* pMatrix = daeSafeCast<domMatrix>( resolver.getElement() ); -		//We are only extracting out the translational component atm -		LLMatrix4 workingTransform; -		if ( pMatrix ) -		{ -			domFloat4x4 domArray = pMatrix->getValue();									 -			for ( int i = 0; i < 4; i++ ) -			{ -				for( int j = 0; j < 4; j++ ) -				{ -					workingTransform.mMatrix[i][j] = domArray[i + j*4]; -				} -			} -			LLVector3 trans = workingTransform.getTranslation(); -			transform.setTranslation( trans );	 -		} -	} -	else -	{ -		LL_WARNS()<<"Element is nonexistent - empty/unsupported node."<<LL_ENDL; -	} -} -//----------------------------------------------------------------------------- -// processJointNode() -//----------------------------------------------------------------------------- -void LLModelLoader::processJointNode( domNode* pNode, JointTransformMap& jointTransforms ) -{ -	if (pNode->getName() == NULL) -	{ -		LL_WARNS() << "nameless node, can't process" << LL_ENDL; -		return; -	} - -	//LL_WARNS()<<"ProcessJointNode# Node:" <<pNode->getName()<<LL_ENDL; - -	//1. handle the incoming node - extract out translation via SID or element - -	LLMatrix4 workingTransform; - -	//Pull out the translate id and store it in the jointTranslations map -	daeSIDResolver jointResolverA( pNode, "./translate" ); -	domTranslate* pTranslateA = daeSafeCast<domTranslate>( jointResolverA.getElement() ); -	daeSIDResolver jointResolverB( pNode, "./location" ); -	domTranslate* pTranslateB = daeSafeCast<domTranslate>( jointResolverB.getElement() ); - -	//Translation via SID was successful -	if ( pTranslateA ) -	{ -		extractTranslation( pTranslateA, workingTransform ); -	} -	else -	if ( pTranslateB ) -	{ -		extractTranslation( pTranslateB, workingTransform ); -	} -	else -	{ -		//Translation via child from element -		daeElement* pTranslateElement = getChildFromElement( pNode, "translate" ); -		if ( !pTranslateElement || pTranslateElement->typeID() != domTranslate::ID() ) -		{ -			//LL_WARNS()<< "The found element is not a translate node" <<LL_ENDL; -			daeSIDResolver jointResolver( pNode, "./matrix" ); -			domMatrix* pMatrix = daeSafeCast<domMatrix>( jointResolver.getElement() ); -			if ( pMatrix ) -			{ -				//LL_INFOS()<<"A matrix SID was however found!"<<LL_ENDL; -				domFloat4x4 domArray = pMatrix->getValue();									 -				for ( int i = 0; i < 4; i++ ) -				{ -					for( int j = 0; j < 4; j++ ) -					{ -						workingTransform.mMatrix[i][j] = domArray[i + j*4]; -					} -				} -			} -			else -			{ -				LL_WARNS()<< "The found element is not translate or matrix node - most likely a corrupt export!" <<LL_ENDL; -			} -		} -		else -		{ -			extractTranslationViaElement( pTranslateElement, workingTransform ); -		} -	} - -	//Store the working transform relative to the nodes name. -	jointTransforms[ pNode->getName() ] = workingTransform; - -	//2. handle the nodes children - -	//Gather and handle the incoming nodes children -	daeTArray< daeSmartRef<daeElement> > childOfChild = pNode->getChildren(); -	S32 childOfChildCount = childOfChild.getCount(); - -	for (S32 i = 0; i < childOfChildCount; ++i) -	{ -		domNode* pChildNode = daeSafeCast<domNode>( childOfChild[i] ); -		if ( pChildNode ) -		{ -			processJointNode( pChildNode, jointTransforms ); -		} -	} -} -//----------------------------------------------------------------------------- -// getChildFromElement() -//----------------------------------------------------------------------------- -daeElement* LLModelLoader::getChildFromElement( daeElement* pElement, std::string const & name ) -{ -    daeElement* pChildOfElement = pElement->getChild( name.c_str() ); -	if ( pChildOfElement ) -	{ -		return pChildOfElement; -	} -	LL_WARNS()<< "Could not find a child [" << name << "] for the element: \"" << pElement->getAttribute("id") << "\"" << LL_ENDL; -    return NULL; -} - -void LLModelLoader::processElement( daeElement* element, bool& badElement ) -{ -	LLMatrix4 saved_transform = mTransform; - -	domTranslate* translate = daeSafeCast<domTranslate>(element); -	if (translate) -	{ -		domFloat3 dom_value = translate->getValue(); - -		LLMatrix4 translation; -		translation.setTranslation(LLVector3(dom_value[0], dom_value[1], dom_value[2])); - -		translation *= mTransform; -		mTransform = translation; -	} - -	domRotate* rotate = daeSafeCast<domRotate>(element); -	if (rotate) -	{ -		domFloat4 dom_value = rotate->getValue(); - -		LLMatrix4 rotation; -		rotation.initRotTrans(dom_value[3] * DEG_TO_RAD, LLVector3(dom_value[0], dom_value[1], dom_value[2]), LLVector3(0, 0, 0)); - -		rotation *= mTransform; -		mTransform = rotation; -	} - -	domScale* scale = daeSafeCast<domScale>(element); -	if (scale) -	{ -		domFloat3 dom_value = scale->getValue(); - - -		LLVector3 scale_vector = LLVector3(dom_value[0], dom_value[1], dom_value[2]); -		scale_vector.abs(); // Set all values positive, since we don't currently support mirrored meshes -		LLMatrix4 scaling; -		scaling.initScale(scale_vector); - -		scaling *= mTransform; -		mTransform = scaling; -	} - -	domMatrix* matrix = daeSafeCast<domMatrix>(element); -	if (matrix) -	{ -		domFloat4x4 dom_value = matrix->getValue(); - -		LLMatrix4 matrix_transform; - -		for (int i = 0; i < 4; i++) -		{ -			for(int j = 0; j < 4; j++) -			{ -				matrix_transform.mMatrix[i][j] = dom_value[i + j*4]; -			} -		} - -		matrix_transform *= mTransform; -		mTransform = matrix_transform; -	} - -	domInstance_geometry* instance_geo = daeSafeCast<domInstance_geometry>(element); -	if (instance_geo) -	{ -		domGeometry* geo = daeSafeCast<domGeometry>(instance_geo->getUrl().getElement()); -		if (geo) -		{ -			domMesh* mesh = daeSafeCast<domMesh>(geo->getDescendant(daeElement::matchType(domMesh::ID()))); -			if (mesh) -			{ -				LLModel* model = mModel[mesh]; -				if (model) -				{ -					LLMatrix4 transformation = mTransform; - -					if (mTransform.determinant() < 0) -					{ //negative scales are not supported -						LL_INFOS() << "Negative scale detected, unsupported transform.  domInstance_geometry: " << LLModel::getElementLabel(instance_geo) << LL_ENDL; -						badElement = true; -					} -					 -					std::map<std::string, LLImportMaterial> materials = getMaterials(model, instance_geo); - -					// adjust the transformation to compensate for mesh normalization -					LLVector3 mesh_scale_vector; -					LLVector3 mesh_translation_vector; -					model->getNormalizedScaleTranslation(mesh_scale_vector, mesh_translation_vector); - -					LLMatrix4 mesh_translation; -					mesh_translation.setTranslation(mesh_translation_vector); -					mesh_translation *= transformation; -					transformation = mesh_translation; - -					LLMatrix4 mesh_scale; -					mesh_scale.initScale(mesh_scale_vector); -					mesh_scale *= transformation; -					transformation = mesh_scale; - -					std::string label = getElementLabel(instance_geo); -					mScene[transformation].push_back(LLModelInstance(model, label, transformation, materials)); - -					stretch_extents(model, transformation, mExtents[0], mExtents[1], mFirstTransform); -				} -			} -		} -		else  -		{ -			LL_INFOS()<<"Unable to resolve geometry URL."<<LL_ENDL; -			badElement = true;			 -		} - -	} - -	domInstance_node* instance_node = daeSafeCast<domInstance_node>(element); -	if (instance_node) -	{ -		daeElement* instance = instance_node->getUrl().getElement(); -		if (instance) -		{ -			processElement(instance,badElement); -		} -	} - -	//process children -	daeTArray< daeSmartRef<daeElement> > children = element->getChildren(); -	int childCount = children.getCount(); -	for (S32 i = 0; i < childCount; i++) -	{ -		processElement(children[i],badElement); -	} - -	domNode* node = daeSafeCast<domNode>(element); -	if (node) -	{ //this element was a node, restore transform before processiing siblings -		mTransform = saved_transform; -	} -} - -std::map<std::string, LLImportMaterial> LLModelLoader::getMaterials(LLModel* model, domInstance_geometry* instance_geo) -{ -	std::map<std::string, LLImportMaterial> materials; -	for (int i = 0; i < model->mMaterialList.size(); i++) -	{ -		LLImportMaterial import_material; - -		domInstance_material* instance_mat = NULL; - -		domBind_material::domTechnique_common* technique = -		daeSafeCast<domBind_material::domTechnique_common>(instance_geo->getDescendant(daeElement::matchType(domBind_material::domTechnique_common::ID()))); - -		if (technique) -		{ -			daeTArray< daeSmartRef<domInstance_material> > inst_materials = technique->getChildrenByType<domInstance_material>(); -			for (int j = 0; j < inst_materials.getCount(); j++) -			{ -				std::string symbol(inst_materials[j]->getSymbol()); - -				if (symbol == model->mMaterialList[i]) // found the binding -				{ -					instance_mat = inst_materials[j]; -				} -			} -		} - -		if (instance_mat) -		{ -			domMaterial* material = daeSafeCast<domMaterial>(instance_mat->getTarget().getElement()); -			if (material) -			{ -				domInstance_effect* instance_effect = -				daeSafeCast<domInstance_effect>(material->getDescendant(daeElement::matchType(domInstance_effect::ID()))); -				if (instance_effect) -				{ -					domEffect* effect = daeSafeCast<domEffect>(instance_effect->getUrl().getElement()); -					if (effect) -					{ -						domProfile_COMMON* profile = -						daeSafeCast<domProfile_COMMON>(effect->getDescendant(daeElement::matchType(domProfile_COMMON::ID()))); -						if (profile) -						{ -							import_material = profileToMaterial(profile); -						} -					} -				} -			} -		} - -		import_material.mBinding = model->mMaterialList[i]; -		materials[model->mMaterialList[i]] = import_material; -	} - -	return materials; -} - -LLImportMaterial LLModelLoader::profileToMaterial(domProfile_COMMON* material) -{ -	LLImportMaterial mat; -	mat.mFullbright = FALSE; - -	daeElement* diffuse = material->getDescendant("diffuse"); -	if (diffuse) -	{ -		domCommon_color_or_texture_type_complexType::domTexture* texture = -		daeSafeCast<domCommon_color_or_texture_type_complexType::domTexture>(diffuse->getDescendant("texture")); -		if (texture) -		{ -			domCommon_newparam_type_Array newparams = material->getNewparam_array(); -			for (S32 i = 0; i < newparams.getCount(); i++) -			{ -				domFx_surface_common* surface = newparams[i]->getSurface(); -				if (surface) -				{ -					domFx_surface_init_common* init = surface->getFx_surface_init_common(); -					if (init) -					{ -						domFx_surface_init_from_common_Array init_from = init->getInit_from_array(); - -						if (init_from.getCount() > i) -						{ -							domImage* image = daeSafeCast<domImage>(init_from[i]->getValue().getElement()); -							if (image) -							{ -								// we only support init_from now - embedded data will come later -								domImage::domInit_from* init = image->getInit_from(); -								if (init) -								{									 -									mat.mDiffuseMapFilename = cdom::uriToNativePath(init->getValue().str()); -									mat.mDiffuseMapLabel = getElementLabel(material); -								} -							} -						} -					} -				} -			} -		} - -		domCommon_color_or_texture_type_complexType::domColor* color = -		daeSafeCast<domCommon_color_or_texture_type_complexType::domColor>(diffuse->getDescendant("color")); -		if (color) -		{ -			domFx_color_common domfx_color = color->getValue(); -			LLColor4 value = LLColor4(domfx_color[0], domfx_color[1], domfx_color[2], domfx_color[3]); -			mat.mDiffuseColor = value; -		} -	} - -	daeElement* emission = material->getDescendant("emission"); -	if (emission) -	{ -		LLColor4 emission_color = getDaeColor(emission); -		if (((emission_color[0] + emission_color[1] + emission_color[2]) / 3.0) > 0.25) -		{ -			mat.mFullbright = TRUE; -		} -	} - -	return mat; -} - -// try to get a decent label for this element -std::string LLModelLoader::getElementLabel(daeElement *element) -{ -	// if we have a name attribute, use it -	std::string name = element->getAttribute("name"); -	if (name.length()) -	{ -		return name; -	} - -	// if we have an ID attribute, use it -	if (element->getID()) -	{ -		return std::string(element->getID()); -	} - -	// if we have a parent, use it -	daeElement* parent = element->getParent(); -	if (parent) -	{ -		// if parent has a name, use it -		std::string name = parent->getAttribute("name"); -		if (name.length()) -		{ -			return name; -		} - -		// if parent has an ID, use it -		if (parent->getID()) -		{ -			return std::string(parent->getID()); -		} -	} - -	// try to use our type -	daeString element_name = element->getElementName(); -	if (element_name) -	{ -		return std::string(element_name); -	} - -	// if all else fails, use "object" -	return std::string("object"); -} - -LLColor4 LLModelLoader::getDaeColor(daeElement* element) -{ -	LLColor4 value; -	domCommon_color_or_texture_type_complexType::domColor* color = -	daeSafeCast<domCommon_color_or_texture_type_complexType::domColor>(element->getDescendant("color")); -	if (color) -	{ -		domFx_color_common domfx_color = color->getValue(); -		value = LLColor4(domfx_color[0], domfx_color[1], domfx_color[2], domfx_color[3]); -	} - -	return value; -} - -//-----------------------------------------------------------------------------  // LLModelPreview  //----------------------------------------------------------------------------- @@ -3125,7 +1172,9 @@ LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp)  , mPelvisZOffset( 0.0f )  , mLegacyRigValid( false )  , mRigValidJointUpload( false ) +, mPhysicsSearchLOD( LLModel::LOD_PHYSICS )  , mResetJoints( false ) +, mModelNoErrors( true )  , mRigParityWithScene( false )  , mLastJointUpdate( false )  { @@ -3170,51 +1219,20 @@ LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp)  	glodInit(); -	//move into joint mapper class -	//1. joints for joint offset verification -	mMasterJointList.push_front("mPelvis"); -	mMasterJointList.push_front("mTorso"); -	mMasterJointList.push_front("mChest"); -	mMasterJointList.push_front("mNeck"); -	mMasterJointList.push_front("mHead"); -	mMasterJointList.push_front("mCollarLeft"); -	mMasterJointList.push_front("mShoulderLeft"); -	mMasterJointList.push_front("mElbowLeft"); -	mMasterJointList.push_front("mWristLeft"); -	mMasterJointList.push_front("mCollarRight"); -	mMasterJointList.push_front("mShoulderRight"); -	mMasterJointList.push_front("mElbowRight"); -	mMasterJointList.push_front("mWristRight"); -	mMasterJointList.push_front("mHipRight"); -	mMasterJointList.push_front("mKneeRight"); -	mMasterJointList.push_front("mFootRight"); -	mMasterJointList.push_front("mHipLeft"); -	mMasterJointList.push_front("mKneeLeft"); -	mMasterJointList.push_front("mFootLeft"); -	//2. legacy joint list - used to verify rigs that will not be using joint offsets -	mMasterLegacyJointList.push_front("mPelvis"); -	mMasterLegacyJointList.push_front("mTorso"); -	mMasterLegacyJointList.push_front("mChest"); -	mMasterLegacyJointList.push_front("mNeck"); -	mMasterLegacyJointList.push_front("mHead"); -	mMasterLegacyJointList.push_front("mHipRight"); -	mMasterLegacyJointList.push_front("mKneeRight"); -	mMasterLegacyJointList.push_front("mFootRight"); -	mMasterLegacyJointList.push_front("mHipLeft"); -	mMasterLegacyJointList.push_front("mKneeLeft"); -	mMasterLegacyJointList.push_front("mFootLeft"); -  	createPreviewAvatar();  }  LLModelPreview::~LLModelPreview()  { -	if (mModelLoader) -	{ -		mModelLoader->mPreview = NULL; -		mModelLoader = NULL; -	} -	//*HACK : *TODO : turn this back on when we understand why this crashes +	// glod apparently has internal mem alignment issues that are angering +	// the heap-check code in windows, these should be hunted down in that +	// TP code, if possible +	// +	// kernel32.dll!HeapFree()  + 0x14 bytes	 +	// msvcr100.dll!free(void * pBlock)  Line 51	C +	// glod.dll!glodGetGroupParameteriv()  + 0x119 bytes	 +	// glod.dll!glodShutdown()  + 0x77 bytes	 +	//  	//glodShutdown();  } @@ -3284,7 +1302,9 @@ U32 LLModelPreview::calcResourceCost()  					   decomp,  					   mFMP->childGetValue("upload_skin").asBoolean(),  					   mFMP->childGetValue("upload_joints").asBoolean(), -					   TRUE); +					   TRUE, +						FALSE, +						instance.mModel->mSubmodelID);  			num_hulls += decomp.mHull.size();  			for (U32 i = 0; i < decomp.mHull.size(); ++i) @@ -3351,29 +1371,12 @@ void LLModelPreview::rebuildUploadData()  	F32 max_scale = 0.f; -	//reorder materials to match mBaseModel -	for (U32 i = 0; i < LLModel::NUM_LODS-1; i++) -	{ -		if (mBaseModel.size() == mModel[i].size()) -		{ -			for (U32 j = 0; j < mBaseModel.size(); ++j) -			{ -				 -				int refFaceCnt = 0; -				int modelFaceCnt = 0; -				 -				if ( !mModel[i][j]->matchMaterialOrder(mBaseModel[j], refFaceCnt, modelFaceCnt ) ) -				{ -					setLoadState( LLModelLoader::ERROR_MATERIALS ); -					mFMP->childDisable( "calculate_btn" ); -				} -			} -		} -	} +	BOOL importerDebug = gSavedSettings.getBOOL("ImporterDebug"); +	BOOL legacyMatching = gSavedSettings.getBOOL("ImporterLegacyMatching");  	for (LLModelLoader::scene::iterator iter = mBaseScene.begin(); iter != mBaseScene.end(); ++iter)  	{ //for each transform in scene -		LLMatrix4 mat = iter->first; +		LLMatrix4 mat		= iter->first;  		// compute position  		LLVector3 position = LLVector3(0, 0, 0) * mat; @@ -3390,38 +1393,171 @@ void LLModelPreview::rebuildUploadData()  		mat *= scale_mat; -		for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) -		{ //for each instance with said transform applied -			LLModelInstance instance = *model_iter; +		for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end();) +		{ //for each instance with said transform applied  +			LLModelInstance instance = *model_iter++;  			LLModel* base_model = instance.mModel; -			if (base_model) +			if (base_model && !requested_name.empty())  			{  				base_model->mRequestedLabel = requested_name;  				base_model->mMetric = metric;  			} -			S32 idx = 0; -			for (idx = 0; idx < mBaseModel.size(); ++idx) -			{  //find reference instance for this model -				if (mBaseModel[idx] == base_model) +			for (int i = LLModel::NUM_LODS - 1; i >= LLModel::LOD_IMPOSTOR; i--) +			{ +				LLModel* lod_model = NULL; +				if (!legacyMatching)  				{ -					break; +					// Fill LOD slots by finding matching meshes by label with name extensions +					// in the appropriate scene for each LOD. This fixes all kinds of issues +					// where the indexed method below fails in spectacular fashion. +					// If you don't take the time to name your LOD and PHYS meshes +					// with the name of their corresponding mesh in the HIGH LOD, +					// then the indexed method will be attempted below. + +					LLMatrix4 transform; + +					std::string name_to_match = instance.mLabel; +					llassert(!name_to_match.empty()); + +					int extensionLOD; +					if (i != LLModel::LOD_PHYSICS || mModel[LLModel::LOD_PHYSICS].empty()) +					{ +						extensionLOD = i; +					} +					else +					{ +						//Physics can be inherited from other LODs or loaded, so we need to adjust what extension we are searching for +						extensionLOD = mPhysicsSearchLOD; +					} + +					std::string toAdd; +					switch (extensionLOD) +					{ +					case LLModel::LOD_IMPOSTOR: toAdd = "_LOD0"; break; +					case LLModel::LOD_LOW:      toAdd = "_LOD1"; break; +					case LLModel::LOD_MEDIUM:   toAdd = "_LOD2"; break; +					case LLModel::LOD_PHYSICS:  toAdd = "_PHYS"; break; +					case LLModel::LOD_HIGH:                      break; +					} + +					if (name_to_match.find(toAdd) == -1) +					{ +						name_to_match += toAdd; +					} + +					FindModel(mScene[i], name_to_match, lod_model, transform); + +					if (!lod_model && i != LLModel::LOD_PHYSICS) +					{ +						if (importerDebug) +						{ +							LL_INFOS() << "Search of" << name_to_match << " in LOD" << i << " list failed. Searching for alternative among LOD lists." << LL_ENDL; +						} + +						int searchLOD = (i > LLModel::LOD_HIGH) ? LLModel::LOD_HIGH : i; +						while ((searchLOD <= LLModel::LOD_HIGH) && !lod_model) +						{ +							std::string name_to_match = instance.mLabel; +							llassert(!name_to_match.empty()); + +							std::string toAdd; +							switch (searchLOD) +							{ +							case LLModel::LOD_IMPOSTOR: toAdd = "_LOD0"; break; +							case LLModel::LOD_LOW:      toAdd = "_LOD1"; break; +							case LLModel::LOD_MEDIUM:   toAdd = "_LOD2"; break; +							case LLModel::LOD_PHYSICS:  toAdd = "_PHYS"; break; +							case LLModel::LOD_HIGH:                      break; +							} + +							if (name_to_match.find(toAdd) == -1) +							{ +								name_to_match += toAdd; +							} + +							// See if we can find an appropriately named model in LOD 'searchLOD' +							// +							FindModel(mScene[searchLOD], name_to_match, lod_model, transform); +							searchLOD++; +						} +					}  				} -			} +				else +				{ +					// Use old method of index-based association +					U32 idx = 0; +					for (idx = 0; idx < mBaseModel.size(); ++idx) +					{ +						// find reference instance for this model +						if (mBaseModel[idx] == base_model) +						{ +							if (importerDebug) +							{ +								LL_INFOS() << "Attempting to use model index " << idx << " for LOD " << i << " of " << instance.mLabel << LL_ENDL; +							} +							break; +						} +					} -			if(idx < mBaseModel.size()) -			{ -				for (U32 i = 0; i < LLModel::NUM_LODS; i++) -				{ //fill LOD slots based on reference model index +					// If the model list for the current LOD includes that index... +					//  					if (mModel[i].size() > idx)  					{ -						instance.mLOD[i] = mModel[i][idx]; +						// Assign that index from the model list for our LOD as the LOD model for this instance +						// +						lod_model = mModel[i][idx]; +						if (importerDebug) +						{ +							LL_INFOS() << "Indexed match of model index " << idx << " at LOD " << i << " to model named " << lod_model->mLabel << LL_ENDL; +						}  					} -					else +					else if (importerDebug)  					{ -						instance.mLOD[i] = NULL; +						LL_INFOS() << "List of models does not include index " << idx << LL_ENDL; +					} +				} + +				if (lod_model) +				{ +					if (importerDebug) +					{ +						if (i == LLModel::LOD_PHYSICS) +						{ +							LL_INFOS() << "Assigning collision for " << instance.mLabel << " to match " << lod_model->mLabel << LL_ENDL; +						} +						else +						{ +							LL_INFOS() << "Assigning LOD" << i << " for " << instance.mLabel << " to found match " << lod_model->mLabel << LL_ENDL; +						} +					} +					instance.mLOD[i] = lod_model; +				} +				else if (importerDebug) +				{ +					LL_INFOS() << "List of models does not include " << instance.mLabel << LL_ENDL; +				} +			} + +			LLModel* high_lod_model = instance.mLOD[LLModel::LOD_HIGH]; +			if (!high_lod_model) +			{ +				setLoadState( LLModelLoader::ERROR_MATERIALS ); +				mFMP->childDisable( "calculate_btn" ); +			} +			else +			{ +				for (U32 i = 0; i < LLModel::NUM_LODS-1; i++) +				{				 +					int refFaceCnt = 0; +					int modelFaceCnt = 0; +					llassert(instance.mLOD[i]); +					if (instance.mLOD[i] && !instance.mLOD[i]->matchMaterialOrder(high_lod_model, refFaceCnt, modelFaceCnt ) ) +					{ +						setLoadState( LLModelLoader::ERROR_MATERIALS ); +						mFMP->childDisable( "calculate_btn" );  					}  				}  			} @@ -3430,6 +1566,34 @@ void LLModelPreview::rebuildUploadData()  		}  	} +	for (U32 lod = 0; lod < LLModel::NUM_LODS-1; lod++) +	{ +		// Search for models that are not included into upload data +		// If we found any, that means something we loaded is not a sub-model. +		for (U32 model_ind = 0; model_ind < mModel[lod].size(); ++model_ind) +		{ +			bool found_model = false; +			for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter) +			{ +				LLModelInstance& instance = *iter; +				if (instance.mLOD[lod] == mModel[lod][model_ind]) +				{ +					found_model = true; +					break; +				} +			} +			if (!found_model && mModel[lod][model_ind] && !mModel[lod][model_ind]->mSubmodelID) +			{ +				if (importerDebug) +				{ +					LL_INFOS() << "Model " << mModel[lod][model_ind]->mLabel << " was not used - mismatching lod models." <<  LL_ENDL; +				} +				setLoadState( LLModelLoader::ERROR_MATERIALS ); +				mFMP->childDisable( "calculate_btn" ); +			} +		} +	} +  	F32 max_import_scale = (DEFAULT_MAX_PRIM_SCALE-0.1f)/max_scale;  	F32 max_axis = llmax(mPreviewScale.mV[0], mPreviewScale.mV[1]); @@ -3496,7 +1660,6 @@ void LLModelPreview::saveUploadData(const std::string& filename, bool save_skinw  			meshes.insert(instance.mModel);  			std::stringstream str; -  			LLModel::Decomposition& decomp =  				instance.mLOD[LLModel::LOD_PHYSICS].notNull() ?   				instance.mLOD[LLModel::LOD_PHYSICS]->mPhysics :  @@ -3509,8 +1672,8 @@ void LLModelPreview::saveUploadData(const std::string& filename, bool save_skinw  				instance.mLOD[LLModel::LOD_LOW],   				instance.mLOD[LLModel::LOD_IMPOSTOR],   				decomp,  -				save_skinweights, save_joint_positions, FALSE, TRUE); - +				save_skinweights, save_joint_positions, +                FALSE, TRUE, instance.mModel->mSubmodelID);  			data["mesh"][instance.mModel->mLocalID] = str.str();  		} @@ -3578,13 +1741,28 @@ void LLModelPreview::loadModel(std::string filename, S32 lod, bool force_disable  		clearGLODGroup();  	} -	mModelLoader = new LLModelLoader(filename, lod, this, mJointTransformMap, mJointsFromNode ); +	mModelLoader = new LLDAELoader( +		filename, +		lod,  +		&LLModelPreview::loadedCallback, +		&LLModelPreview::lookupJointByName, +		&LLModelPreview::loadTextures, +		&LLModelPreview::stateChangedCallback, +		this, +		mJointTransformMap, +		mJointsFromNode, +		gSavedSettings.getU32("ImporterModelLimit"));  	if (force_disable_slm)  	{  		mModelLoader->mTrySLM = false;  	} - +	else +	{ +		//only try to load from slm if viewer is configured to do so and this is the  +		//initial model load (not an LoD or physics shape) +		mModelLoader->mTrySLM = gSavedSettings.getBOOL("MeshImportUseSLM") && mUploadData.empty(); +	}  	mModelLoader->start();  	mFMP->childSetTextArg("status", "[STATUS]", mFMP->getString("status_reading_file")); @@ -3615,6 +1793,7 @@ void LLModelPreview::setPhysicsFromLOD(S32 lod)  	if (lod >= 0 && lod <= 3)  	{ +		mPhysicsSearchLOD = lod;  		mModel[LLModel::LOD_PHYSICS] = mModel[lod];  		mScene[LLModel::LOD_PHYSICS] = mScene[lod];  		mLODFile[LLModel::LOD_PHYSICS].clear(); @@ -3634,11 +1813,14 @@ void LLModelPreview::clearIncompatible(S32 lod)  		return;  	} +	// at this point we don't care about sub-models, +	// different amount of sub-models means face count mismatch, not incompatibility +	U32 lod_size = countRootModels(mModel[lod]);  	for (U32 i = 0; i <= LLModel::LOD_HIGH; i++)  	{ //clear out any entries that aren't compatible with this model  		if (i != lod)  		{ -			if (mModel[i].size() != mModel[lod].size()) +			if (countRootModels(mModel[i]) != lod_size)  			{  				mModel[i].clear();  				mScene[i].clear(); @@ -3673,7 +1855,7 @@ void LLModelPreview::clearGLODGroup()  	}  } -void LLModelPreview::loadModelCallback(S32 lod) +void LLModelPreview::loadModelCallback(S32 loaded_lod)  {  	assert_main_thread(); @@ -3686,12 +1868,18 @@ void LLModelPreview::loadModelCallback(S32 lod)  	if(getLoadState() >= LLModelLoader::ERROR_PARSING)  	{  		mLoading = false ; +		mModelLoader = NULL;  		return ;  	} +	// Copy determinations about rig so UI will reflect them +	// +	setRigValidForJointPositionUpload(mModelLoader->isRigValidForJointPositionUpload()); +	setLegacyRigValid(mModelLoader->isLegacyRigValid()); +  	mModelLoader->loadTextures() ; -	if (lod == -1) +	if (loaded_lod == -1)  	{ //populate all LoDs from model loader scene  		mBaseModel.clear();  		mBaseScene.clear(); @@ -3723,6 +1911,11 @@ void LLModelPreview::loadModelCallback(S32 lod)  						//override displayed model with current LoD  						list_iter->mModel = list_iter->mLOD[lod]; +						if (!list_iter->mModel) +						{ +							continue; +						} +  						//add current model to current LoD's model list (LLModel::mLocalID makes a good vector index)  						S32 idx = list_iter->mModel->mLocalID; @@ -3731,7 +1924,7 @@ void LLModelPreview::loadModelCallback(S32 lod)  							mModel[lod].resize(idx+1);  						} -						mModel[lod][idx] = list_iter->mModel;	 +						mModel[lod][idx] = list_iter->mModel;  						if (!list_iter->mModel->mSkinWeights.empty())  						{  							skin_weights = true; @@ -3774,31 +1967,31 @@ void LLModelPreview::loadModelCallback(S32 lod)  	}  	else  	{ //only replace given LoD -		mModel[lod] = mModelLoader->mModelList; -		mScene[lod] = mModelLoader->mScene; -		mVertexBuffer[lod].clear(); +		mModel[loaded_lod] = mModelLoader->mModelList; +		mScene[loaded_lod] = mModelLoader->mScene; +		mVertexBuffer[loaded_lod].clear(); -		setPreviewLOD(lod); +		setPreviewLOD(loaded_lod); -		if (lod == LLModel::LOD_HIGH) +		if (loaded_lod == LLModel::LOD_HIGH)  		{ //save a copy of the highest LOD for automatic LOD manipulation  			if (mBaseModel.empty())  			{ //first time we've loaded a model, auto-gen LoD  				mGenLOD = true;  			} -			mBaseModel = mModel[lod]; +			mBaseModel = mModel[loaded_lod];  			clearGLODGroup(); -			mBaseScene = mScene[lod]; +			mBaseScene = mScene[loaded_lod];  			mVertexBuffer[5].clear();  		} -		clearIncompatible(lod); +		clearIncompatible(loaded_lod);  		mDirty = true; -		if (lod == LLModel::LOD_HIGH) +		if (loaded_lod == LLModel::LOD_HIGH)  		{  			resetPreviewTarget();  		} @@ -3820,6 +2013,8 @@ void LLModelPreview::loadModelCallback(S32 lod)  	refresh();  	mModelLoadedSignal(); + +	mModelLoader = NULL;  }  void LLModelPreview::resetPreviewTarget() @@ -4168,6 +2363,20 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim  			volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE);  			mModel[lod][mdl_idx] = new LLModel(volume_params, 0.f); +            std::string name = base->mLabel; + +            switch (lod) +            { +                case LLModel::LOD_IMPOSTOR: name += "_LOD0"; break; +                case LLModel::LOD_LOW:      name += "_LOD1"; break; +		        case LLModel::LOD_MEDIUM:   name += "_LOD2"; break; +                case LLModel::LOD_PHYSICS:  name += "_PHYS"; break; +                case LLModel::LOD_HIGH:                      break; +            } + +            mModel[lod][mdl_idx]->mLabel = name; +			mModel[lod][mdl_idx]->mSubmodelID = base->mSubmodelID; +              			GLint* sizes = new GLint[patch_count*2];  			glodGetObjectParameteriv(mObject[base], GLOD_PATCH_SIZES, sizes);  			stop_gloderror(); @@ -4280,17 +2489,6 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim  	{  		shader->bind();  	} - -	/*if (which_lod == -1 && mScene[LLModel::LOD_PHYSICS].empty()) -	 { //build physics scene -	 mScene[LLModel::LOD_PHYSICS] = mScene[LLModel::LOD_LOW]; -	 mModel[LLModel::LOD_PHYSICS] = mModel[LLModel::LOD_LOW]; - -	 for (U32 i = 1; i < mModel[LLModel::LOD_PHYSICS].size(); ++i) -	 { -	 mPhysicsQ.push(mModel[LLModel::LOD_PHYSICS][i]); -	 } -	 }*/  }  void LLModelPreview::updateStatusMessages() @@ -4307,43 +2505,89 @@ void LLModelPreview::updateStatusMessages()  	S32 total_verts[LLModel::NUM_LODS];  	S32 total_submeshes[LLModel::NUM_LODS]; -	for (S32 lod = 0; lod < LLModel::NUM_LODS; ++lod) +    for (U32 i = 0; i < LLModel::NUM_LODS-1; i++) +    { +        total_tris[i] = 0; +	    total_verts[i] = 0; +	    total_submeshes[i] = 0; +    } + +    for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter)  	{ -		//initialize total for this lod to 0 -		total_tris[lod] = total_verts[lod] = total_submeshes[lod] = 0; +		LLModelInstance& instance = *iter; -		for (LLModelLoader::scene::iterator iter = mScene[lod].begin(), endIter = mScene[lod].end(); iter != endIter; ++iter) +        LLModel* model_high_lod = instance.mLOD[LLModel::LOD_HIGH]; +        if (!model_high_lod)  		{ -			for (LLModelLoader::model_instance_list::iterator instance = iter->second.begin(), end_instance = iter->second.end(); instance != end_instance; ++instance) -			{ -				LLModel* model = instance->mModel; -				if (model) -				{ -					 //for each model in the lod -					S32 cur_tris = 0; -					S32 cur_verts = 0; -					S32 cur_submeshes = model->getNumVolumeFaces(); +			setLoadState( LLModelLoader::ERROR_MATERIALS ); +			mFMP->childDisable( "calculate_btn" ); +			continue; +		} -					for (S32 j = 0; j < cur_submeshes; ++j) -					{ //for each submesh (face), add triangles and vertices to current total -						const LLVolumeFace& face = model->getVolumeFace(j); -						cur_tris += face.mNumIndices/3; -						cur_verts += face.mNumVertices; -					} +        for (U32 i = 0; i < LLModel::NUM_LODS-1; i++) +		{ +            LLModel* lod_model = instance.mLOD[i]; +            if (!lod_model) +            { +                setLoadState( LLModelLoader::ERROR_MATERIALS ); +                mFMP->childDisable( "calculate_btn" ); +            } -					//add this model to the lod total -					total_tris[lod] += cur_tris; -					total_verts[lod] += cur_verts; -					total_submeshes[lod] += cur_submeshes; +            int refFaceCnt = 0; +            int modelFaceCnt = 0; -					//store this model's counts to asset data -					tris[lod].push_back(cur_tris); -					verts[lod].push_back(cur_verts); -					submeshes[lod].push_back(cur_submeshes); +            if (!lod_model->matchMaterialOrder(model_high_lod, refFaceCnt, modelFaceCnt ) ) +			{ +                setLoadState( LLModelLoader::ERROR_MATERIALS ); +				mFMP->childDisable( "calculate_btn" ); +			} + +            if (lod_model) +			{ +					//for each model in the lod +				S32 cur_tris = 0; +				S32 cur_verts = 0; +				S32 cur_submeshes = lod_model->getNumVolumeFaces(); + +				for (S32 j = 0; j < cur_submeshes; ++j) +				{ //for each submesh (face), add triangles and vertices to current total +					const LLVolumeFace& face = lod_model->getVolumeFace(j); +					cur_tris += face.mNumIndices/3; +					cur_verts += face.mNumVertices;  				} + +                std::string instance_name = instance.mLabel; + +                BOOL importerDebug = gSavedSettings.getBOOL("ImporterDebug"); +                if (importerDebug) +                { +                    // Useful for debugging generalized complaints below about total submeshes which don't have enough +                    // context to address exactly what needs to be fixed to move towards compliance with the rules. +                    // +                    LL_INFOS() << "Instance " << lod_model->mLabel << " LOD " << i << " Verts: "   << cur_verts     << LL_ENDL; +                    LL_INFOS() << "Instance " << lod_model->mLabel << " LOD " << i << " Tris:  "   << cur_tris      << LL_ENDL; +                    LL_INFOS() << "Instance " << lod_model->mLabel << " LOD " << i << " Faces: "   << cur_submeshes << LL_ENDL; + +                    LLModel::material_list::iterator mat_iter = lod_model->mMaterialList.begin(); +                    while (mat_iter != lod_model->mMaterialList.end()) +                    { +                        LL_INFOS() << "Instance " << lod_model->mLabel << " LOD " << i << " Material " << *(mat_iter) << LL_ENDL; +                        mat_iter++; +                    } +                } + +                //add this model to the lod total +				total_tris[i] += cur_tris; +				total_verts[i] += cur_verts; +				total_submeshes[i] += cur_submeshes; + +				//store this model's counts to asset data +				tris[i].push_back(cur_tris); +				verts[i].push_back(cur_verts); +				submeshes[i].push_back(cur_submeshes);  			}  		} -	} +    }  	if (mMaxTriangleLimit == 0)  	{ @@ -4357,37 +2601,48 @@ void LLModelPreview::updateStatusMessages()  		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()) +			if (mModel[lod][i] && 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; ) +					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); +						U16 index_a = face.mIndices[k+0]; +						U16 index_b = face.mIndices[k+1]; +						U16 index_c = face.mIndices[k+2]; + +						LLVector4a v1; v1.setMul(face.mPositions[index_a], scale); +						LLVector4a v2; v2.setMul(face.mPositions[index_b], scale); +						LLVector4a v3; v3.setMul(face.mPositions[index_c], scale);  						if (ll_is_degenerate(v1,v2,v3))  						{  							has_degenerate = true;  						} +						else +						{ +							k += 3; +						}  					}  				}  			}  		}  	} -	 +  	mFMP->childSetTextArg("submeshes_info", "[SUBMESHES]", llformat("%d", total_submeshes[LLModel::LOD_HIGH]));  	std::string mesh_status_na = mFMP->getString("mesh_status_na");  	S32 upload_status[LLModel::LOD_HIGH+1]; -	bool upload_ok = true; +	mModelNoErrors = true; -	for (S32 lod = 0; lod <= LLModel::LOD_HIGH; ++lod) +	const U32 lod_high = LLModel::LOD_HIGH; +	U32 high_submodel_count = mModel[lod_high].size() - countRootModels(mModel[lod_high]); + +	for (S32 lod = 0; lod <= lod_high; ++lod)  	{  		upload_status[lod] = 0; @@ -4400,7 +2655,7 @@ void LLModelPreview::updateStatusMessages()  		}  		else  		{ -			if (lod == LLModel::LOD_HIGH) +			if (lod == lod_high)  			{  				upload_status[lod] = 2;  				message = "mesh_status_missing_lod"; @@ -4421,8 +2676,6 @@ void LLModelPreview::updateStatusMessages()  			mFMP->childSetValue(lod_vertices_name[lod], mesh_status_na);  		} -		const U32 lod_high = LLModel::LOD_HIGH; -  		if (lod != lod_high)  		{  			if (total_submeshes[lod] && total_submeshes[lod] != total_submeshes[lod_high]) @@ -4430,6 +2683,13 @@ void LLModelPreview::updateStatusMessages()  				message = "mesh_status_submesh_mismatch";  				upload_status[lod] = 2;  			} +			else if (mModel[lod].size() - countRootModels(mModel[lod]) != high_submodel_count) +			{//number of submodels is different, not all faces are matched correctly. +				message = "mesh_status_submesh_mismatch"; +				upload_status[lod] = 2; +				// Note: Submodels in instance were loaded from higher LOD and as result face count +				// returns same value and total_submeshes[lod] is identical to high_lod one. +			}  			else if (!tris[lod].empty() && tris[lod].size() != tris[lod_high].size())  			{ //number of meshes is different  				message = "mesh_status_mesh_mismatch"; @@ -4450,7 +2710,7 @@ void LLModelPreview::updateStatusMessages()  				{  					//too many vertices in this lod  					message = "mesh_status_too_many_vertices"; -					upload_status[lod] = 2; +					upload_status[lod] = 1;  				}  			}  		} @@ -4462,7 +2722,7 @@ void LLModelPreview::updateStatusMessages()  		if (upload_status[lod] >= 2)  		{ -			upload_ok = false; +			mModelNoErrors = false;  		}  		if (lod == mPreviewLOD) @@ -4476,23 +2736,41 @@ void LLModelPreview::updateStatusMessages()  	} -	//make sure no hulls have more than 256 points in them -	for (U32 i = 0; upload_ok && i < mModel[LLModel::LOD_PHYSICS].size(); ++i) +	//warn if hulls have more than 256 points in them +	BOOL physExceededVertexLimit = FALSE; +	for (U32 i = 0; mModelNoErrors && i < mModel[LLModel::LOD_PHYSICS].size(); ++i)  	{  		LLModel* mdl = mModel[LLModel::LOD_PHYSICS][i]; -		for (U32 j = 0; upload_ok && j < mdl->mPhysics.mHull.size(); ++j) +		if (mdl)  		{ -			if (mdl->mPhysics.mHull[j].size() > 256) +			for (U32 j = 0; j < mdl->mPhysics.mHull.size(); ++j)  			{ -				upload_ok = false; +				if (mdl->mPhysics.mHull[j].size() > 256) +				{ +					physExceededVertexLimit = TRUE; +					LL_INFOS() << "Physical model " << mdl->mLabel << " exceeds vertex per hull limitations." << LL_ENDL; +					break; +				}  			}  		}  	} +	mFMP->childSetVisible("physics_status_message_text", physExceededVertexLimit); +	LLIconCtrl* physStatusIcon = mFMP->getChild<LLIconCtrl>("physics_status_message_icon"); +	physStatusIcon->setVisible(physExceededVertexLimit); +	if (physExceededVertexLimit) +	{ +		mFMP->childSetValue("physics_status_message_text", mFMP->getString("phys_status_vertex_limit_exceeded")); +		LLUIImagePtr img = LLUI::getUIImage("ModelImport_Status_Warning"); +		physStatusIcon->setImage(img); +	} -	bool errorStateFromLoader = getLoadState() >= LLModelLoader::ERROR_PARSING ? true : false; +	if (getLoadState() >= LLModelLoader::ERROR_PARSING) +	{ +		mModelNoErrors = false; +		LL_INFOS() << "Loader returned errors, model can't be uploaded" << LL_ENDL; +	} -	bool skinAndRigOk = true;  	bool uploadingSkin		     = mFMP->childGetValue("upload_skin").asBoolean();  	bool uploadingJointPositions = mFMP->childGetValue("upload_joints").asBoolean(); @@ -4500,19 +2778,23 @@ void LLModelPreview::updateStatusMessages()  	{  		if ( uploadingJointPositions && !isRigValidForJointPositionUpload() )  		{ -			skinAndRigOk = false; -		}	 +			mModelNoErrors = false; +			LL_INFOS() << "Invalid rig, there might be issues with uploading Joint positions" << LL_ENDL; +		}  	} -	 -	if(upload_ok && mModelLoader) + +	if(mModelNoErrors && mModelLoader)  	{  		if(!mModelLoader->areTexturesReady() && mFMP->childGetValue("upload_textures").asBoolean())  		{ -			upload_ok = false ; +			// Some textures are still loading, prevent upload until they are done +			mModelNoErrors = false;  		}  	} -	if (!upload_ok || errorStateFromLoader || !skinAndRigOk || has_degenerate) +	// Todo: investigate use of has_degenerate and include into mModelNoErrors upload blocking mechanics +	// current use of has_degenerate won't block upload permanently - later checks will restore the button +	if (!mModelNoErrors || has_degenerate)  	{  		mFMP->childDisable("ok_btn");  	} @@ -4949,23 +3231,23 @@ void LLModelPreview::genBuffers(S32 lod, bool include_skin_weights)  void LLModelPreview::update()  { -	if (mDirty) +    if (mGenLOD)  	{ -		mDirty = false; -		mResourceCost = calcResourceCost(); +		mGenLOD = false; +		genLODs();  		refresh();  		updateStatusMessages();  	} -	if (mGenLOD) +	if (mDirty)  	{ -		mGenLOD = false; -		genLODs(); +		mDirty = false; +		mResourceCost = calcResourceCost();  		refresh();  		updateStatusMessages();  	} -  } +  //-----------------------------------------------------------------------------  // getTranslationForJointOffset()  //----------------------------------------------------------------------------- @@ -4999,8 +3281,77 @@ void LLModelPreview::createPreviewAvatar( void )  	}  	else  	{ -		LL_INFOS()<<"Failed to create preview avatar for upload model window"<<LL_ENDL; +		LL_INFOS() << "Failed to create preview avatar for upload model window" << LL_ENDL; +	} +} + +//static +U32 LLModelPreview::countRootModels(LLModelLoader::model_list models) +{ +	U32 root_models = 0; +	model_list::iterator model_iter = models.begin(); +	while (model_iter != models.end()) +	{ +		LLModel* mdl = *model_iter; +		if (mdl && mdl->mSubmodelID == 0) +		{ +			root_models++; +		} +		model_iter++; +	} +	return root_models; +} + +void LLModelPreview::loadedCallback( +	LLModelLoader::scene& scene, +	LLModelLoader::model_list& model_list, +	S32 lod, +	void* opaque) +{ +	LLModelPreview* pPreview = static_cast< LLModelPreview* >(opaque); +	if (pPreview && !LLModelPreview::sIgnoreLoadedCallback) +	{ +		pPreview->loadModelCallback(lod); +	}	 +} + +void LLModelPreview::stateChangedCallback(U32 state,void* opaque) +{ +	LLModelPreview* pPreview = static_cast< LLModelPreview* >(opaque); +	if (pPreview) +	{ +	 pPreview->setLoadState(state); +	} +} + +LLJoint* LLModelPreview::lookupJointByName(const std::string& str, void* opaque) +{ +	LLModelPreview* pPreview = static_cast< LLModelPreview* >(opaque); +	if (pPreview) +	{ +		return pPreview->getPreviewAvatar()->getJoint(str);  	} +	return NULL; +} + +U32 LLModelPreview::loadTextures(LLImportMaterial& material,void* opaque) +{ +	(void)opaque; + +	if (material.mDiffuseMapFilename.size()) +	{ +		material.mOpaqueData = new LLPointer< LLViewerFetchedTexture >; +		LLPointer< LLViewerFetchedTexture >& tex = (*reinterpret_cast< LLPointer< LLViewerFetchedTexture > * >(material.mOpaqueData)); + +		tex = LLViewerTextureManager::getFetchedTextureFromUrl("file://" + material.mDiffuseMapFilename, FTT_LOCAL_FILE, TRUE, LLGLTexture::BOOST_PREVIEW); +		tex->setLoadedCallback(LLModelPreview::textureLoadedCallback, 0, TRUE, FALSE, opaque, NULL, FALSE); +		tex->forceToSaveRawImage(0, F32_MAX); +		material.setDiffuseMap(tex->getID()); // record tex ID +		return 1; +	} + +	material.mOpaqueData = NULL; +	return 0;	  }  void LLModelPreview::addEmptyFace( LLModel* pTarget ) @@ -5245,24 +3596,6 @@ BOOL LLModelPreview::render()  			}  		} -		//make sure material lists all match -		for (U32 i = 0; i < LLModel::NUM_LODS-1; i++) -		{ -			if (mBaseModel.size() == mModel[i].size()) -			{ -				for (U32 j = 0; j < mBaseModel.size(); ++j) -				{ -					int refFaceCnt = 0; -					int modelFaceCnt = 0; -										 -					if ( !mModel[i][j]->matchMaterialOrder(mBaseModel[j], refFaceCnt, modelFaceCnt ) ) -					{ -						mFMP->childDisable( "calculate_btn" ); -					} -				} -			} -		} -  		if (regen)  		{  			genBuffers(mPreviewLOD, skin_weight); @@ -5276,62 +3609,61 @@ BOOL LLModelPreview::render()  				LLModel* model = instance.mLOD[mPreviewLOD]; -				if (!model) -				{ -					continue; -				} +					if (!model) +					{ +						continue; +					} -				gGL.pushMatrix(); -				LLMatrix4 mat = instance.mTransform; +					gGL.pushMatrix(); +					LLMatrix4 mat = instance.mTransform; -				gGL.multMatrix((GLfloat*) mat.mMatrix); +					gGL.multMatrix((GLfloat*) mat.mMatrix); -				for (U32 i = 0; i < mVertexBuffer[mPreviewLOD][model].size(); ++i) -				{ -					LLVertexBuffer* buffer = mVertexBuffer[mPreviewLOD][model][i]; +					for (U32 i = 0; i < mVertexBuffer[mPreviewLOD][model].size(); ++i) +					{ +						LLVertexBuffer* buffer = mVertexBuffer[mPreviewLOD][model][i]; -					buffer->setBuffer(type_mask & buffer->getTypeMask()); +						buffer->setBuffer(type_mask & buffer->getTypeMask()); -					if (textures) -					{ -						int materialCnt = instance.mModel->mMaterialList.size(); -						if ( i < materialCnt ) +						if (textures)  						{ -							const std::string& binding = instance.mModel->mMaterialList[i];						 -							const LLImportMaterial& material = instance.mMaterial[binding]; +							int materialCnt = instance.mModel->mMaterialList.size(); +							if ( i < materialCnt ) +							{ +								const std::string& binding = instance.mModel->mMaterialList[i];						 +								const LLImportMaterial& material = instance.mMaterial[binding]; -							gGL.diffuseColor4fv(material.mDiffuseColor.mV); +								gGL.diffuseColor4fv(material.mDiffuseColor.mV); -							if (material.mDiffuseMap.notNull()) -							{ -								if (material.mDiffuseMap->getDiscardLevel() > -1) +								// Find the tex for this material, bind it, and add it to our set +								// +								LLViewerFetchedTexture* tex = bindMaterialDiffuseTexture(material); +								if (tex)  								{ -									gGL.getTexUnit(0)->bind(material.mDiffuseMap, true); -									mTextureSet.insert(material.mDiffuseMap.get()); +									mTextureSet.insert(tex);  								}  							}  						} -					} -					else -					{ -						gGL.diffuseColor4f(1,1,1,1); -					} - -					buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); -					gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); -					gGL.diffuseColor3f(0.4f, 0.4f, 0.4f); +						else +						{ +							gGL.diffuseColor4f(1,1,1,1); +						} -					if (edges) -					{ -						glLineWidth(3.f); -						glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);  						buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); -						glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); -						glLineWidth(1.f); +						gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); +						gGL.diffuseColor3f(0.4f, 0.4f, 0.4f); + +						if (edges) +						{ +							glLineWidth(3.f); +							glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); +							buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); +							glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); +							glLineWidth(1.f); +						}  					} +					gGL.popMatrix();  				} -				gGL.popMatrix(); -			}  			if (physics)  			{ @@ -5359,97 +3691,97 @@ BOOL LLModelPreview::render()  						LLModel* model = instance.mLOD[LLModel::LOD_PHYSICS]; -						if (!model) -						{ -							continue; -						} +							if (!model) +							{ +								continue; +							} -						gGL.pushMatrix(); -						LLMatrix4 mat = instance.mTransform; +							gGL.pushMatrix(); +							LLMatrix4 mat = instance.mTransform;  						gGL.multMatrix((GLfloat*) mat.mMatrix); -						bool render_mesh = true; +							bool render_mesh = true; -						LLPhysicsDecomp* decomp = gMeshRepo.mDecompThread; -						if (decomp) -						{ -							LLMutexLock(decomp->mMutex); +							LLPhysicsDecomp* decomp = gMeshRepo.mDecompThread; +							if (decomp) +							{ +								LLMutexLock(decomp->mMutex); -							LLModel::Decomposition& physics = model->mPhysics; +								LLModel::Decomposition& physics = model->mPhysics; -							if (!physics.mHull.empty()) -							{ -								render_mesh = false; +								if (!physics.mHull.empty()) +								{ +									render_mesh = false; -								if (physics.mMesh.empty()) -								{ //build vertex buffer for physics mesh -									gMeshRepo.buildPhysicsMesh(physics); -								} +									if (physics.mMesh.empty()) +									{ //build vertex buffer for physics mesh +										gMeshRepo.buildPhysicsMesh(physics); +									} -								if (!physics.mMesh.empty()) -								{ //render hull instead of mesh -									for (U32 i = 0; i < physics.mMesh.size(); ++i) -									{ -										if (explode > 0.f) +									if (!physics.mMesh.empty()) +									{ //render hull instead of mesh +										for (U32 i = 0; i < physics.mMesh.size(); ++i)  										{ -											gGL.pushMatrix(); +											if (explode > 0.f) +											{ +												gGL.pushMatrix(); -											LLVector3 offset = model->mHullCenter[i]-model->mCenterOfHullCenters; -											offset *= explode; +												LLVector3 offset = model->mHullCenter[i]-model->mCenterOfHullCenters; +												offset *= explode; -											gGL.translatef(offset.mV[0], offset.mV[1], offset.mV[2]); -										} +												gGL.translatef(offset.mV[0], offset.mV[1], offset.mV[2]); +											} -										static std::vector<LLColor4U> hull_colors; +											static std::vector<LLColor4U> hull_colors; -										if (i+1 >= hull_colors.size()) -										{ -											hull_colors.push_back(LLColor4U(rand()%128+127, rand()%128+127, rand()%128+127, 128)); -										} +											if (i+1 >= hull_colors.size()) +											{ +												hull_colors.push_back(LLColor4U(rand()%128+127, rand()%128+127, rand()%128+127, 128)); +											} -										gGL.diffuseColor4ubv(hull_colors[i].mV); -										LLVertexBuffer::drawArrays(LLRender::TRIANGLES, physics.mMesh[i].mPositions, physics.mMesh[i].mNormals); +											gGL.diffuseColor4ubv(hull_colors[i].mV); +											LLVertexBuffer::drawArrays(LLRender::TRIANGLES, physics.mMesh[i].mPositions, physics.mMesh[i].mNormals); -										if (explode > 0.f) -										{ -											gGL.popMatrix(); +											if (explode > 0.f) +											{ +												gGL.popMatrix(); +											}  										}  									}  								}  							} -						} - -						if (render_mesh) -						{ -							if (mVertexBuffer[LLModel::LOD_PHYSICS].empty()) -							{ -								genBuffers(LLModel::LOD_PHYSICS, false); -							} -							for (U32 i = 0; i < mVertexBuffer[LLModel::LOD_PHYSICS][model].size(); ++i) +						 +							if (render_mesh)  							{ -								LLVertexBuffer* buffer = mVertexBuffer[LLModel::LOD_PHYSICS][model][i]; +								if (mVertexBuffer[LLModel::LOD_PHYSICS].empty()) +								{ +									genBuffers(LLModel::LOD_PHYSICS, false); +								} +								for (U32 i = 0; i < mVertexBuffer[LLModel::LOD_PHYSICS][model].size(); ++i) +								{ +									LLVertexBuffer* buffer = mVertexBuffer[LLModel::LOD_PHYSICS][model][i]; -								gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); -								gGL.diffuseColor4f(0.4f, 0.4f, 0.0f, 0.4f); +									gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); +									gGL.diffuseColor4f(0.4f, 0.4f, 0.0f, 0.4f); -								buffer->setBuffer(type_mask & buffer->getTypeMask()); -								buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); +									buffer->setBuffer(type_mask & buffer->getTypeMask()); +									buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); -								gGL.diffuseColor3f(1.f, 1.f, 0.f); +									gGL.diffuseColor3f(1.f, 1.f, 0.f); -								glLineWidth(2.f); -								glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); -								buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); +									glLineWidth(2.f); +									glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); +									buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0); -								glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); -								glLineWidth(1.f); +									glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); +									glLineWidth(1.f); +								}  							} -						} -						gGL.popMatrix(); -					} +							gGL.popMatrix(); +						}  					glLineWidth(3.f);  					glPointSize(8.f); @@ -5561,7 +3893,7 @@ BOOL LLModelPreview::render()  					if (!model->mSkinWeights.empty())  					{ -						for (U32 i = 0; i < mVertexBuffer[mPreviewLOD][model].size(); ++i) +						for (U32 i = 0, e = mVertexBuffer[mPreviewLOD][model].size(); i < e; ++i)  						{  							LLVertexBuffer* buffer = mVertexBuffer[mPreviewLOD][model][i]; @@ -5630,19 +3962,20 @@ BOOL LLModelPreview::render()  								position[j] = v;  							} +							llassert(model->mMaterialList.size() > i);   							const std::string& binding = instance.mModel->mMaterialList[i];  							const LLImportMaterial& material = instance.mMaterial[binding];  							buffer->setBuffer(type_mask & buffer->getTypeMask());  							gGL.diffuseColor4fv(material.mDiffuseColor.mV);  							gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); -							if (material.mDiffuseMap.notNull()) + +							// Find the tex for this material, bind it, and add it to our set +							// +							LLViewerFetchedTexture* tex = bindMaterialDiffuseTexture(material); +							if (tex)  							{ -								if (material.mDiffuseMap->getDiscardLevel() > -1) -								{ -									gGL.getTexUnit(0)->bind(material.mDiffuseMap, true); -									mTextureSet.insert(material.mDiffuseMap.get()); -								} +								mTextureSet.insert(tex);  							}  							buffer->draw(LLRender::TRIANGLES, buffer->getNumIndices(), 0); @@ -5757,14 +4090,14 @@ void LLFloaterModelPreview::onReset(void* user_data)  	LLFloaterModelPreview* fmp = (LLFloaterModelPreview*) user_data;  	fmp->childDisable("reset_btn");  	LLModelPreview* mp = fmp->mModelPreview; -	std::string filename = mp->mLODFile[3];  +	std::string filename = mp->mLODFile[LLModel::LOD_HIGH];   	fmp->resetDisplayOptions();  	//reset model preview  	fmp->initModelPreview();  	mp = fmp->mModelPreview; -	mp->loadModel(filename,3,true); +	mp->loadModel(filename,LLModel::LOD_HIGH,true);  }  //static @@ -5858,7 +4191,7 @@ void LLFloaterModelPreview::toggleCalculateButton(bool visible)  	}  	mUploadBtn->setVisible(!visible); -	mUploadBtn->setEnabled(mHasUploadPerm && !mUploadModelUrl.empty()); +	mUploadBtn->setEnabled(isModelUploadAllowed());  	if (visible)  	{ @@ -5924,7 +4257,7 @@ void LLFloaterModelPreview::handleModelPhysicsFeeReceived()  	childSetTextArg("price_breakdown", "[MODEL]", llformat("%d", result["upload_price_breakdown"]["model"].asInteger()));  	childSetVisible("upload_fee", true);  	childSetVisible("price_breakdown", true); -	mUploadBtn->setEnabled(mHasUploadPerm && !mUploadModelUrl.empty()); +	mUploadBtn->setEnabled(isModelUploadAllowed());  }  void LLFloaterModelPreview::setModelPhysicsFeeErrorStatus(S32 status, const std::string& reason) @@ -5948,6 +4281,16 @@ void LLFloaterModelPreview::onModelUploadFailure()  	mUploadBtn->setEnabled(true);  } +bool LLFloaterModelPreview::isModelUploadAllowed() +{ +	bool allow_upload = mHasUploadPerm && !mUploadModelUrl.empty(); +	if (mModelPreview) +	{ +		allow_upload &= mModelPreview->mModelNoErrors; +	} +	return allow_upload; +} +  S32 LLFloaterModelPreview::DecompRequest::statusCallback(const char* status, S32 p1, S32 p2)  {  	if (mContinue) @@ -5997,8 +4340,8 @@ void LLFloaterModelPreview::onPermissionsReceived(const LLSD& result)  	// BAP HACK: handle "" for case that  MeshUploadFlag cap is broken.  	mHasUploadPerm = (("" == upload_status) || ("valid" == upload_status)); -	//mUploadBtn->setEnabled(mHasUploadPerm); -	mUploadBtn->setEnabled(mHasUploadPerm && !mUploadModelUrl.empty()); +	// isModelUploadAllowed() includes mHasUploadPerm +	mUploadBtn->setEnabled(isModelUploadAllowed());  	getChild<LLTextBox>("warning_title")->setVisible(!mHasUploadPerm);  	getChild<LLTextBox>("warning_message")->setVisible(!mHasUploadPerm);  } diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h index 618748bd4e..7a518c798b 100755 --- a/indra/newview/llfloatermodelpreview.h +++ b/indra/newview/llfloatermodelpreview.h @@ -37,6 +37,8 @@  #include "llviewermenufile.h"  #include "llfloatermodeluploadbase.h" +#include "lldaeloader.h" +  class LLComboBox;  class LLJoint;  class LLViewerJointMesh; @@ -45,103 +47,18 @@ class LLTextBox;  class LLVertexBuffer;  class LLModelPreview;  class LLFloaterModelPreview; +class DAE;  class daeElement;  class domProfile_COMMON;  class domInstance_geometry;  class domNode;  class domTranslate;  class domController; +class domSkin; +class domMesh;  class LLMenuButton;  class LLToggleableMenu; -typedef std::map<std::string, LLMatrix4> JointTransformMap; -typedef std::map<std::string, LLMatrix4>:: iterator JointTransformMapIt; - -const S32 NUM_LOD = 4; - -class LLModelLoader : public LLThread -{ -public: -	typedef enum -	{ -		STARTING = 0, -		READING_FILE, -		CREATING_FACES, -		GENERATING_VERTEX_BUFFERS, -		GENERATING_LOD, -		DONE, -		ERROR_PARSING, //basically loading failed -		ERROR_MATERIALS, -	} eLoadState; - -	U32 mState; -	std::string mFilename; -	S32 mLod; -	LLModelPreview* mPreview; -	LLMatrix4 mTransform; -	BOOL mFirstTransform; -	LLVector3 mExtents[2]; -	bool mTrySLM; -	 -	std::map<daeElement*, LLPointer<LLModel> > mModel; -	 -	typedef std::vector<LLPointer<LLModel> > model_list; -	model_list mModelList; - -	typedef std::vector<LLModelInstance> model_instance_list; -	 -	typedef std::map<LLMatrix4, model_instance_list > scene; - -	scene mScene; - -	typedef std::queue<LLPointer<LLModel> > model_queue; - -	//queue of models that need a physics rep -	model_queue mPhysicsQ; - -	LLModelLoader( std::string filename, S32 lod, LLModelPreview* preview, JointTransformMap& jointMap,  -				   std::deque<std::string>& jointsFromNodes ); -	~LLModelLoader() ; - -	virtual void run(); -	bool doLoadModel(); -	bool loadFromSLM(const std::string& filename); -	void loadModelCallback(); - -	void loadTextures() ; //called in the main thread. -	void processElement(daeElement* element, bool& badElement); -	std::map<std::string, LLImportMaterial> getMaterials(LLModel* model, domInstance_geometry* instance_geo); -	LLImportMaterial profileToMaterial(domProfile_COMMON* material); -	std::string getElementLabel(daeElement *element); -	LLColor4 getDaeColor(daeElement* element); -	 -	daeElement* getChildFromElement( daeElement* pElement, std::string const & name ); -	 -	bool isNodeAJoint( domNode* pNode ); -	void processJointNode( domNode* pNode, std::map<std::string,LLMatrix4>& jointTransforms ); -	void extractTranslation( domTranslate* pTranslate, LLMatrix4& transform ); -	void extractTranslationViaElement( daeElement* pTranslateElement, LLMatrix4& transform ); -	void extractTranslationViaSID( daeElement* pElement, LLMatrix4& transform ); - -	void setLoadState(U32 state); - -	void buildJointToNodeMappingFromScene( daeElement* pRoot ); -	void processJointToNodeMapping( domNode* pNode ); -	void processChildJoints( domNode* pParentNode ); - -	//map of avatar joints as named in COLLADA assets to internal joint names -	std::map<std::string, std::string> mJointMap; -	JointTransformMap& mJointList;	 -	std::deque<std::string>& mJointsFromNode; - -	S32 mNumOfFetchingTextures ; //updated in the main thread -	bool areTexturesReady() { return !mNumOfFetchingTextures; } //called in the main thread. - -private: -	static std::list<LLModelLoader*> sActiveLoaderList; -	static bool isAlive(LLModelLoader* loader) ; -}; -  class LLFloaterModelPreview : public LLFloaterModelUploadBase  {  public: @@ -172,6 +89,7 @@ public:  	BOOL handleScrollWheel(S32 x, S32 y, S32 clicks);   	/*virtual*/ void onOpen(const LLSD& key); +	/*virtual*/ void onClose(bool app_quitting);  	static void onMouseCaptureLostModelPreview(LLMouseHandler*);  	static void setUploadAmount(S32 amount) { sUploadAmount = amount; } @@ -210,6 +128,8 @@ public:  	/*virtual*/ void onModelUploadFailure(); +	bool isModelUploadAllowed(); +  protected:  	friend class LLModelPreview;  	friend class LLMeshFilePicker; @@ -359,21 +279,14 @@ public:  	void setHasPivot( bool val ) { mHasPivot = val; }  	void setModelPivot( const LLVector3& pivot ) { mModelPivot = pivot; } -	//Determines the viability of an asset to be used as an avatar rig (w or w/o joint upload caps) -	void critiqueRigForUploadApplicability( const std::vector<std::string> &jointListFromAsset ); -	void critiqueJointToNodeMappingFromScene( void  );  	//Is a rig valid so that it can be used as a criteria for allowing for uploading of joint positions  	//Accessors for joint position upload friendly rigs  	const bool isRigValidForJointPositionUpload( void ) const { return mRigValidJointUpload; }  	void setRigValidForJointPositionUpload( bool rigValid ) { mRigValidJointUpload = rigValid; } -	bool isRigSuitableForJointPositionUpload( const std::vector<std::string> &jointListFromAsset ); -	//Determines if a rig is a legacy from the joint list -	bool isRigLegacy( const std::vector<std::string> &jointListFromAsset );	 +  	//Accessors for the legacy rigs  	const bool isLegacyRigValid( void ) const { return mLegacyRigValid; } -	void setLegacyRigValid( bool rigValid ) { mLegacyRigValid = rigValid; }	 -	//Verify that a controller matches vertex counts -	bool verifyController( domController* pController ); +	void setLegacyRigValid( bool rigValid ) { mLegacyRigValid = rigValid; }		  	static void	textureLoadedCallback( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* src_aux, S32 discard_level, BOOL final, void* userdata ); @@ -388,6 +301,16 @@ public:  	LLVector3 getTranslationForJointOffset( std::string joint ); +	static bool 		sIgnoreLoadedCallback; + +protected: + +	static void			loadedCallback(LLModelLoader::scene& scene,LLModelLoader::model_list& model_list, S32 lod, void* opaque); +	static void			stateChangedCallback(U32 state, void* opaque); + +	static LLJoint*	lookupJointByName(const std::string&, void* opaque); +	static U32			loadTextures(LLImportMaterial& material, void* opaque); +  private:  	//Utility function for controller vertex compare  	bool verifyCount( int expected, int result ); @@ -395,6 +318,8 @@ private:  	void		createPreviewAvatar( void );  	//Accessor for the dummy avatar  	LLVOAvatar* getPreviewAvatar( void ) { return mPreviewAvatar; } +	// Count amount of original models, excluding sub-models +	static U32 countRootModels(LLModelLoader::model_list models);   protected:  	friend class LLModelLoader; @@ -416,13 +341,15 @@ private:  	LLVector3	mPreviewTarget;  	LLVector3	mPreviewScale;  	S32			mPreviewLOD; +	S32			mPhysicsSearchLOD;  	U32			mResourceCost;  	std::string mLODFile[LLModel::NUM_LODS];  	bool		mLoading;  	U32			mLoadState;  	bool		mResetJoints;  	bool		mRigParityWithScene; -	 +	bool		mModelNoErrors; +  	std::map<std::string, bool> mViewOption;  	//GLOD object parameters (must rebuild object if these change) @@ -459,7 +386,7 @@ private:  	U32 mMaxTriangleLimit;  	LLMeshUploadThread::instance_list mUploadData; -	std::set<LLViewerFetchedTexture* > mTextureSet; +	std::set<LLViewerFetchedTexture * > mTextureSet;  	//map of vertex buffers to models (one vertex buffer in vector per face in model  	std::map<LLModel*, std::vector<LLPointer<LLVertexBuffer> > > mVertexBuffer[LLModel::NUM_LODS+1]; @@ -478,10 +405,9 @@ private:  	bool		mLastJointUpdate; -	std::deque<std::string> mMasterJointList; -	std::deque<std::string> mMasterLegacyJointList; -	std::deque<std::string> mJointsFromNode; -	JointTransformMap		mJointTransformMap; +	JointSet				mJointsFromNode; +	JointTransformMap	mJointTransformMap; +  	LLPointer<LLVOAvatar>	mPreviewAvatar;  }; diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 648056484e..55b94aa141 100755 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -72,6 +72,7 @@  #include "bufferstream.h"  #include "llfasttimer.h"  #include "llcorehttputil.h" +#include "lltrans.h"  #include "boost/lexical_cast.hpp" @@ -492,6 +493,12 @@ void get_vertex_buffer_from_mesh(LLCDMeshData& mesh, LLModel::PhysicsMesh& res,  	}  } +LLViewerFetchedTexture* LLMeshUploadThread::FindViewerTexture(const LLImportMaterial& material) +{ +	LLPointer< LLViewerFetchedTexture > * ppTex = static_cast< LLPointer< LLViewerFetchedTexture > * >(material.mOpaqueData); +	return ppTex ? (*ppTex).get() : NULL; +} +  volatile S32 LLMeshRepoThread::sActiveHeaderRequests = 0;  volatile S32 LLMeshRepoThread::sActiveLODRequests = 0;  U32	LLMeshRepoThread::sMaxConcurrentRequests = 1; @@ -586,16 +593,16 @@ public:  	LLMeshLODHandler(const LLVolumeParams & mesh_params, S32 lod, U32 offset, U32 requested_bytes)  		: LLMeshHandlerBase(offset, requested_bytes),  		  mLOD(lod) -		{ +	{  			mMeshParams = mesh_params;  			LLMeshRepoThread::incActiveLODRequests();  		}  	virtual ~LLMeshLODHandler(); - +	  protected:  	LLMeshLODHandler(const LLMeshLODHandler &);					// Not defined  	void operator=(const LLMeshLODHandler &);					// Not defined - +	  public:  	virtual void processData(LLCore::BufferArray * body, S32 body_offset, U8 * data, S32 data_size);  	virtual void processFailure(LLCore::HttpStatus status); @@ -693,12 +700,16 @@ void log_upload_error(LLCore::HttpStatus status, const LLSD& content,  	args["MESSAGE"] = message;  	args["IDENTIFIER"] = identifier;  	args["LABEL"] = model_name; -	gMeshRepo.uploadError(args);  	// Log details.  	LL_WARNS(LOG_MESH) << "Error in stage:  " << stage  					   << ", Reason:  " << status.toString()  					   << " (" << status.toTerseString() << ")" << LL_ENDL; + +	std::ostringstream details; +	typedef std::set<std::string> mav_errors_set_t; +	mav_errors_set_t mav_errors; +  	if (content.has("error"))  	{  		const LLSD& err = content["error"]; @@ -708,8 +719,11 @@ void log_upload_error(LLCore::HttpStatus status, const LLSD& content,  						   << "', message '" << err["message"].asString()  						   << "', id '" << err["identifier"].asString()  						   << "'" << LL_ENDL; +  		if (err.has("errors"))  		{ +			details << std::endl << std::endl; +  			S32 error_num = 0;  			const LLSD& err_list = err["errors"];  			for (LLSD::array_const_iterator it = err_list.beginArray(); @@ -717,6 +731,13 @@ void log_upload_error(LLCore::HttpStatus status, const LLSD& content,  				 ++it)  			{  				const LLSD& err_entry = *it; +				std::string message = err_entry["message"]; + +				if (message.length() > 0) +				{ +					mav_errors.insert(message); +				} +  				LL_WARNS(LOG_MESH) << "  error[" << error_num << "]:" << LL_ENDL;  				for (LLSD::map_const_iterator map_it = err_entry.beginMap();  					 map_it != err_entry.endMap(); @@ -733,6 +754,21 @@ void log_upload_error(LLCore::HttpStatus status, const LLSD& content,  	{  		LL_WARNS(LOG_MESH) << "Bad response to mesh request, no additional error information available." << LL_ENDL;  	} +	 +	mav_errors_set_t::iterator mav_errors_it = mav_errors.begin(); +	for (; mav_errors_it != mav_errors.end(); ++mav_errors_it) +	{ +		std::string mav_details = "Mav_Details_" + *mav_errors_it; +		details << "Message: '" << *mav_errors_it << "': " << LLTrans::getString(mav_details) << std::endl << std::endl; +	} + +	std::string details_str = details.str(); +	if (details_str.length() > 0) +	{ +		args["DETAILS"] = details_str; +	} + +	gMeshRepo.uploadError(args);  }  LLMeshRepoThread::LLMeshRepoThread() @@ -766,7 +802,7 @@ LLMeshRepoThread::LLMeshRepoThread()  	mHttpLargePolicyClass = app_core_http.getPolicy(LLAppCoreHttp::AP_LARGE_MESH);  } -			 +  LLMeshRepoThread::~LLMeshRepoThread()  {  	LL_INFOS(LOG_MESH) << "Small GETs issued:  " << LLMeshRepository::sHTTPRequestCount @@ -835,16 +871,16 @@ void LLMeshRepoThread::run()  		{  			break;  		} - +		  		if (! mHttpRequestSet.empty())  		{  			// Dispatch all HttpHandler notifications  			mHttpRequest->update(0L);  		}  		sRequestWaterLevel = mHttpRequestSet.size();			// Stats data update - -		// NOTE: order of queue processing intentionally favors LOD requests over header requests +		// NOTE: order of queue processing intentionally favors LOD requests over header requests +  		while (!mLODReqQ.empty() && mHttpRequestSet.size() < sRequestHighWater)  		{  			if (! mMutex) @@ -908,7 +944,7 @@ void LLMeshRepoThread::run()  					mSkinRequests.erase(iter);  					mMutex->unlock(); -					if (!fetchMeshSkinInfo(mesh_id)) +					if (! fetchMeshSkinInfo(mesh_id))  					{  						incomplete.insert(mesh_id);  					} @@ -937,7 +973,7 @@ void LLMeshRepoThread::run()  					mDecompositionRequests.erase(iter);  					mMutex->unlock(); -					if (!fetchMeshDecomposition(mesh_id)) +					if (! fetchMeshDecomposition(mesh_id))  					{  						incomplete.insert(mesh_id);  					} @@ -963,7 +999,7 @@ void LLMeshRepoThread::run()  					mPhysicsShapeRequests.erase(iter);  					mMutex->unlock(); -					if (!fetchMeshPhysicsShape(mesh_id)) +					if (! fetchMeshPhysicsShape(mesh_id))  					{  						incomplete.insert(mesh_id);  					} @@ -1189,7 +1225,7 @@ bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id)  	}  	++LLMeshRepository::sMeshRequestCount; -	bool ret = true ; +	bool ret = true;  	U32 header_size = mMeshHeaderSize[mesh_id];  	if (header_size > 0) @@ -1237,7 +1273,7 @@ bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id)  			constructUrl(mesh_id, &http_url, &cap_version);  			if (!http_url.empty()) -			{				 +			{  				LLMeshSkinInfoHandler * handler = new LLMeshSkinInfoHandler(mesh_id, offset, size);  				LLCore::HttpHandle handle = getByteRange(http_url, cap_version, offset, size, handler);  				if (LLCORE_HTTP_HANDLE_INVALID == handle) @@ -1283,7 +1319,7 @@ bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id)  	++LLMeshRepository::sMeshRequestCount;  	U32 header_size = mMeshHeaderSize[mesh_id]; -	bool ret = true ; +	bool ret = true;  	if (header_size > 0)  	{ @@ -1329,9 +1365,9 @@ bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id)  			int cap_version(2);  			std::string http_url;  			constructUrl(mesh_id, &http_url, &cap_version); - +			  			if (!http_url.empty()) -			{				 +			{  				LLMeshDecompositionHandler * handler = new LLMeshDecompositionHandler(mesh_id, offset, size);  				LLCore::HttpHandle handle = getByteRange(http_url, cap_version, offset, size, handler);  				if (LLCORE_HTTP_HANDLE_INVALID == handle) @@ -1377,7 +1413,7 @@ bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id)  	++LLMeshRepository::sMeshRequestCount;  	U32 header_size = mMeshHeaderSize[mesh_id]; -	bool ret = true ; +	bool ret = true;  	if (header_size > 0)  	{ @@ -1422,9 +1458,9 @@ bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id)  			int cap_version(2);  			std::string http_url;  			constructUrl(mesh_id, &http_url, &cap_version); - +			  			if (!http_url.empty()) -			{				 +			{  				LLMeshPhysicsShapeHandler * handler = new LLMeshPhysicsShapeHandler(mesh_id, offset, size);  				LLCore::HttpHandle handle = getByteRange(http_url, cap_version, offset, size, handler);  				if (LLCORE_HTTP_HANDLE_INVALID == handle) @@ -1513,11 +1549,11 @@ bool LLMeshRepoThread::fetchMeshHeader(const LLVolumeParams& mesh_params)  	}  	//either cache entry doesn't exist or is corrupt, request header from simulator	 -	bool retval = true ; +	bool retval = true;  	int cap_version(2);  	std::string http_url;  	constructUrl(mesh_params.getSculptID(), &http_url, &cap_version); - +	  	if (!http_url.empty())  	{  		//grab first 4KB if we're going to bother with a fetch.  Cache will prevent future fetches if a full mesh fits @@ -1605,9 +1641,9 @@ bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod)  			int cap_version(2);  			std::string http_url;  			constructUrl(mesh_id, &http_url, &cap_version); - +			  			if (!http_url.empty()) -			{				 +			{  				LLMeshLODHandler * handler = new LLMeshLODHandler(mesh_params, lod, offset, size);  				LLCore::HttpHandle handle = getByteRange(http_url, cap_version, offset, size, handler);  				if (LLCORE_HTTP_HANDLE_INVALID == handle) @@ -1879,7 +1915,7 @@ LLMeshUploadThread::LLMeshUploadThread(LLMeshUploadThread::instance_list& data,  	mOrigin += gAgent.getAtAxis() * scale.magVec(); -	mMeshUploadTimeOut = gSavedSettings.getS32("MeshUploadTimeOut") ; +	mMeshUploadTimeOut = gSavedSettings.getS32("MeshUploadTimeOut");  	mHttpRequest = new LLCore::HttpRequest;  	mHttpOptions = new LLCore::HttpOptions; @@ -1947,14 +1983,14 @@ void LLMeshUploadThread::preStart()  void LLMeshUploadThread::discard()  { -	LLMutexLock lock(mMutex) ; +	LLMutexLock lock(mMutex);  	mDiscarded = true;  }  bool LLMeshUploadThread::isDiscarded() const  { -	LLMutexLock lock(mMutex) ; -	return mDiscarded ; +	LLMutexLock lock(mMutex); +	return mDiscarded;  }  void LLMeshUploadThread::run() @@ -2019,6 +2055,14 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures)  	{  		LLMeshUploadData data;  		data.mBaseModel = iter->first; + +		if (data.mBaseModel->mSubmodelID) +		{ +			// These are handled below to insure correct parenting order on creation +			// due to map walking being based on model address (aka random) +			continue; +		} +  		LLModelInstance& first_instance = *(iter->second.begin());  		for (S32 i = 0; i < 5; i++)  		{ @@ -2056,7 +2100,10 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures)  				data.mModel[LLModel::LOD_IMPOSTOR],   				decomp,  				mUploadSkin, -				mUploadJoints); +				mUploadJoints, +				FALSE, +				FALSE, +				data.mBaseModel->mSubmodelID);  			data.mAssetData = ostr.str();  			std::string str = ostr.str(); @@ -2090,17 +2137,26 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures)  			instance_entry["scale"] = ll_sd_from_vector3(scale);  			instance_entry["material"] = LL_MCODE_WOOD; -			instance_entry["physics_shape_type"] = (U8)(LLViewerObject::PHYSICS_SHAPE_CONVEX_HULL); +			instance_entry["physics_shape_type"] = data.mModel[LLModel::LOD_PHYSICS].notNull() ? (U8)(LLViewerObject::PHYSICS_SHAPE_PRIM) : (U8)(LLViewerObject::PHYSICS_SHAPE_CONVEX_HULL);  			instance_entry["mesh"] = mesh_index[data.mBaseModel];  			instance_entry["face_list"] = LLSD::emptyArray(); -			S32 end = llmin((S32)data.mBaseModel->mMaterialList.size(), data.mBaseModel->getNumVolumeFaces()) ; +			// We want to be able to allow more than 8 materials... +			// +			S32 end = llmin((S32)instance.mMaterial.size(), instance.mModel->getNumVolumeFaces()) ; +  			for (S32 face_num = 0; face_num < end; face_num++)  			{  				LLImportMaterial& material = instance.mMaterial[data.mBaseModel->mMaterialList[face_num]];  				LLSD face_entry = LLSD::emptyMap(); -				LLViewerFetchedTexture *texture = material.mDiffuseMap.get(); + +				LLViewerFetchedTexture *texture = NULL; + +				if (material.mDiffuseMapFilename.size()) +				{ +					texture = FindViewerTexture(material); +				}  				if ((texture != NULL) &&  					(textures.find(texture) == textures.end())) @@ -2115,9 +2171,171 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures)  					{											  						LLPointer<LLImageJ2C> upload_file =  							LLViewerTextureList::convertToUploadFile(texture->getSavedRawImage()); + +						if (!upload_file.isNull() && upload_file->getDataSize()) +						{  						texture_str.write((const char*) upload_file->getData(), upload_file->getDataSize());  					}  				} +				} + +				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 != 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["diffuse_color"] = 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++; +		} +	} + +	for (instance_map::iterator iter = mInstance.begin(); iter != mInstance.end(); ++iter) +	{ +		LLMeshUploadData data; +		data.mBaseModel = iter->first; + +		if (!data.mBaseModel->mSubmodelID) +		{ +			// These were handled above already... +			// +			continue; +		} + +		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. +			if (model_name.empty()) +			{ +				model_name = data.mBaseModel->getName(); +			} + +			if (model_metric.empty()) +			{ +				model_metric = data.mBaseModel->getMetric(); +			} + +			std::stringstream ostr; +			 +			LLModel::Decomposition& decomp = +				data.mModel[LLModel::LOD_PHYSICS].notNull() ?  +				data.mModel[LLModel::LOD_PHYSICS]->mPhysics :  +				data.mBaseModel->mPhysics; + +			decomp.mBaseHull = mHullMap[data.mBaseModel]; + +			LLSD mesh_header = LLModel::writeModel( +				ostr,   +				data.mModel[LLModel::LOD_PHYSICS], +				data.mModel[LLModel::LOD_HIGH], +				data.mModel[LLModel::LOD_MEDIUM], +				data.mModel[LLModel::LOD_LOW], +				data.mModel[LLModel::LOD_IMPOSTOR],  +				decomp, +				mUploadSkin, +				mUploadJoints, +				FALSE, +				FALSE, +				data.mBaseModel->mSubmodelID); + +			data.mAssetData = ostr.str(); +			std::string str = ostr.str(); + +			res["mesh_list"][mesh_num] = LLSD::Binary(str.begin(),str.end());  +			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; +		 +			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); +		 +			instance_entry["material"] = LL_MCODE_WOOD; +			instance_entry["physics_shape_type"] = (U8)(LLViewerObject::PHYSICS_SHAPE_NONE); +			instance_entry["mesh"] = mesh_index[data.mBaseModel]; + +			instance_entry["face_list"] = LLSD::emptyArray(); + +			// We want to be able to allow more than 8 materials... +			// +			S32 end = llmin((S32)instance.mMaterial.size(), instance.mModel->getNumVolumeFaces()) ; + +			for (S32 face_num = 0; face_num < end; face_num++) +			{ +				LLImportMaterial& material = instance.mMaterial[data.mBaseModel->mMaterialList[face_num]]; +				LLSD face_entry = LLSD::emptyMap(); + +				LLViewerFetchedTexture *texture = NULL; + +				if (material.mDiffuseMapFilename.size()) +				{ +					texture = FindViewerTexture(material); +				} + +				if ((texture != NULL) && +					(textures.find(texture) == textures.end())) +				{ +					textures.insert(texture); +				} + +				std::stringstream texture_str; +				if (texture != NULL && include_textures && mUploadTextures) +				{ +					if(texture->hasSavedRawImage()) +					{											 +						LLPointer<LLImageJ2C> upload_file = +							LLViewerTextureList::convertToUploadFile(texture->getSavedRawImage()); + +						if (!upload_file.isNull() && upload_file->getDataSize()) +						{ +						texture_str.write((const char*) upload_file->getData(), upload_file->getDataSize()); +					} +				} +				}  				if (texture != NULL &&  					mUploadTextures && @@ -2205,7 +2423,7 @@ void LLMeshUploadThread::generateHulls()  		}  	} -	if(has_valid_requests) +	if (has_valid_requests)  	{  		// *NOTE:  Interesting livelock condition on shutdown.  If there  		// is an upload request in generateHulls() when shutdown starts, @@ -2310,7 +2528,7 @@ void LLMeshUploadThread::requestWholeModelFee()  	else  	{  		U32 sleep_time(10); - +		  		mHttpRequest->update(0);  		while (! LLApp::isQuitting() && ! finished() && ! isDiscarded())  		{ @@ -2405,7 +2623,7 @@ void LLMeshUploadThread::onCompleted(LLCore::HttpHandle handle, LLCore::HttpResp  		// model fee case  		LLWholeModelFeeObserver* observer(mFeeObserverHandle.get());  		mWholeModelUploadURL.clear(); - +		  		if (! status)  		{  			LL_WARNS(LOG_MESH) << "Fee request failed.  Reason:  " << reason @@ -2435,7 +2653,7 @@ void LLMeshUploadThread::onCompleted(LLCore::HttpHandle handle, LLCore::HttpResp  				LLCoreHttpUtil::responseToLLSD(response, true, body);  			}  			dump_llsd_to_file(body, make_dump_name("whole_model_fee_response_", dump_num)); - +		  			if (body["state"].asString() == "upload")  			{  				mWholeModelUploadURL = body["uploader"].asString(); @@ -2506,7 +2724,7 @@ void LLMeshRepoThread::notifyLoadedMeshes()  		LODRequest req = mUnavailableQ.front();  		mUnavailableQ.pop();  		mMutex->unlock(); -		 +  		update_metrics = true;  		gMeshRepo.notifyMeshUnavailable(req.mMeshParams, req.mLOD);  	} @@ -2642,7 +2860,7 @@ void LLMeshRepository::cacheOutgoingMesh(LLMeshUploadData& data, LLSD& header)  void LLMeshHandlerBase::onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response)  {  	mProcessed = true; -	 +  	unsigned int retries(0U);  	response->getRetries(NULL, &retries);  	LLMeshRepository::sHTTPRetryCount += retries; @@ -2698,7 +2916,7 @@ void LLMeshHandlerBase::onCompleted(LLCore::HttpHandle handle, LLCore::HttpRespo  				// 200 case, typically  				offset = 0;  			} - +		  			// *DEBUG:  To test validation below  			// offset += 1; @@ -2814,7 +3032,7 @@ void LLMeshHeaderHandler::processData(LLCore::BufferArray * /* body */, S32 /* b  				const std::string & lod_name = header_lod[i];  				lod_bytes = llmax(lod_bytes, header[lod_name]["offset"].asInteger()+header[lod_name]["size"].asInteger());  			} - +		  			// 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["physics_convex"]["offset"].asInteger() + header["physics_convex"]["size"].asInteger()); @@ -2822,7 +3040,7 @@ void LLMeshHeaderHandler::processData(LLCore::BufferArray * /* body */, S32 /* b  			S32 header_bytes = (S32) gMeshRepo.mThread->mMeshHeaderSize[mesh_id];  			S32 bytes = lod_bytes + header_bytes;  - +		  			// It's possible for the remote asset to have more data than is needed for the local cache  			// only allocate as much space in the VFS as is needed for the local cache  			data_size = llmin(data_size, bytes); @@ -2834,11 +3052,11 @@ void LLMeshHeaderHandler::processData(LLCore::BufferArray * /* body */, S32 /* b  				++LLMeshRepository::sCacheWrites;  				file.write(data, data_size); - +			  				// zero out the rest of the file   				U8 block[MESH_HEADER_SIZE];  				memset(block, 0, sizeof(block)); -	 +  				while (bytes-file.tell() > sizeof(block))  				{  					file.write(block, sizeof(block)); @@ -2864,8 +3082,8 @@ LLMeshLODHandler::~LLMeshLODHandler()  			gMeshRepo.mThread->lockAndLoadMeshLOD(mMeshParams, mLOD);  		}  		LLMeshRepoThread::decActiveLODRequests(); -		}  	} +}  void LLMeshLODHandler::processFailure(LLCore::HttpStatus status)  { @@ -2883,7 +3101,7 @@ void LLMeshLODHandler::processData(LLCore::BufferArray * /* body */, S32 /* body  {  	if ((! MESH_LOD_PROCESS_FAILED) && gMeshRepo.mThread->lodReceived(mMeshParams, mLOD, data, data_size))  	{ -		//good fetch from sim, write to VFS for caching +		// good fetch from sim, write to VFS for caching  		LLVFile file(gVFS, mMeshParams.getSculptID(), LLAssetType::AT_MESH, LLVFile::WRITE);  		S32 offset = mOffset; @@ -2928,7 +3146,7 @@ void LLMeshSkinInfoHandler::processData(LLCore::BufferArray * /* body */, S32 /*  {  	if ((! MESH_SKIN_INFO_PROCESS_FAILED) && gMeshRepo.mThread->skinInfoReceived(mMeshID, data, data_size))  	{ -		//good fetch from sim, write to VFS for caching +		// good fetch from sim, write to VFS for caching  		LLVFile file(gVFS, mMeshID, LLAssetType::AT_MESH, LLVFile::WRITE);  		S32 offset = mOffset; @@ -3252,7 +3470,7 @@ void LLMeshRepository::notifyLoadedMeshes()  													 REQUEST2_LOW_WATER_MIN,  													 REQUEST2_LOW_WATER_MAX);  	} - +	  	//clean up completed upload threads  	for (std::vector<LLMeshUploadThread*>::iterator iter = mUploads.begin(); iter != mUploads.end(); )  	{ @@ -3329,7 +3547,7 @@ void LLMeshRepository::notifyLoadedMeshes()  	//call completed callbacks on finished decompositions  	mDecompThread->notifyCompleted(); -	 +  	// For major operations, attempt to get the required locks  	// without blocking and punt if they're not available.  The  	// longest run of holdoffs is kept in sMaxLockHoldoffs just @@ -3348,12 +3566,12 @@ void LLMeshRepository::notifyLoadedMeshes()  			return;  		}  		hold_offs = 0; - +		  		if (gAgent.getRegion())  		{  			// Update capability urls  			static std::string region_name("never name a region this"); - +			  			if (gAgent.getRegion()->getName() != region_name && gAgent.getRegion()->capabilitiesReceived())  			{  				region_name = gAgent.getRegion()->getName(); @@ -3369,7 +3587,7 @@ void LLMeshRepository::notifyLoadedMeshes()  									<< LL_ENDL;  			}  		} - +		  		//popup queued error messages from background threads  		while (!mUploadErrorQ.empty())  		{ @@ -3724,7 +3942,7 @@ LLSD& LLMeshRepoThread::getMeshHeader(const LLUUID& mesh_id)  void LLMeshRepository::uploadModel(std::vector<LLModelInstance>& data, LLVector3& scale, bool upload_textures, -									bool upload_skin, bool upload_joints, std::string upload_url, bool do_upload, +								   bool upload_skin, bool upload_joints, std::string upload_url, bool do_upload,  								   LLHandle<LLWholeModelFeeObserver> fee_observer, LLHandle<LLWholeModelUploadObserver> upload_observer)  {  	LLMeshUploadThread* thread = new LLMeshUploadThread(data, scale, upload_textures, upload_skin, upload_joints, upload_url,  @@ -3795,37 +4013,6 @@ void LLMeshUploadThread::decomposeMeshMatrix(LLMatrix4& transformation,  	result_rot = quat_rotation;   } -bool LLImportMaterial::operator<(const LLImportMaterial &rhs) const -{ -	if (mDiffuseMap != rhs.mDiffuseMap) -	{ -		return mDiffuseMap < rhs.mDiffuseMap; -	} - -	if (mDiffuseMapFilename != rhs.mDiffuseMapFilename) -	{ -		return mDiffuseMapFilename < rhs.mDiffuseMapFilename; -	} - -	if (mDiffuseMapLabel != rhs.mDiffuseMapLabel) -	{ -		return mDiffuseMapLabel < rhs.mDiffuseMapLabel; -	} - -	if (mDiffuseColor != rhs.mDiffuseColor) -	{ -		return mDiffuseColor < rhs.mDiffuseColor; -	} - -	if (mBinding != rhs.mBinding) -	{ -		return mBinding < rhs.mBinding; -	} - -	return mFullbright < rhs.mFullbright; -} - -  void LLMeshRepository::updateInventory(inventory_data data)  {  	LLMutexLock lock(mMeshMutex); @@ -4223,7 +4410,7 @@ void LLPhysicsDecomp::doDecompositionSingleHull()  	setMeshData(mesh, true);  	LLCDResult ret = decomp->buildSingleHull() ; -	if(ret) +	if (ret)  	{  		LL_WARNS(LOG_MESH) << "Could not execute decomposition stage when attempting to create single hull." << LL_ENDL;  		make_box(mCurRequest); @@ -4411,60 +4598,6 @@ void LLPhysicsDecomp::Request::setStatusMessage(const std::string& msg)  	mStatusMessage = msg;  } -LLModelInstance::LLModelInstance(LLSD& data) -{ -	mLocalMeshID = data["mesh_id"].asInteger(); -	mLabel = data["label"].asString(); -	mTransform.setValue(data["transform"]); - -	for (U32 i = 0; i < data["material"].size(); ++i) -	{ -		LLImportMaterial mat(data["material"][i]); -		mMaterial[mat.mBinding] = mat; -	} -} - - -LLSD LLModelInstance::asLLSD() -{	 -	LLSD ret; - -	ret["mesh_id"] = mModel->mLocalID; -	ret["label"] = mLabel; -	ret["transform"] = mTransform.getValue(); -	 -	U32 i = 0; -	for (std::map<std::string, LLImportMaterial>::iterator iter = mMaterial.begin(); iter != mMaterial.end(); ++iter) -	{ -		ret["material"][i++] = iter->second.asLLSD(); -	} - -	return ret; -} - -LLImportMaterial::LLImportMaterial(LLSD& data) -{ -	mDiffuseMapFilename = data["diffuse"]["filename"].asString(); -	mDiffuseMapLabel = data["diffuse"]["label"].asString(); -	mDiffuseColor.setValue(data["diffuse"]["color"]); -	mFullbright = data["fullbright"].asBoolean(); -	mBinding = data["binding"].asString(); -} - - -LLSD LLImportMaterial::asLLSD() -{ -	LLSD ret; - -	ret["diffuse"]["filename"] = mDiffuseMapFilename; -	ret["diffuse"]["label"] = mDiffuseMapLabel; -	ret["diffuse"]["color"] = mDiffuseColor.getValue(); -	ret["fullbright"] = mFullbright; -	ret["binding"] = mBinding; - -	return ret; -} -  void LLMeshRepository::buildPhysicsMesh(LLModel::Decomposition& decomp)  {  	decomp.mMesh.resize(decomp.mHull.size()); diff --git a/indra/newview/llmeshrepository.h b/indra/newview/llmeshrepository.h index 39280bea3a..688cd01a87 100755 --- a/indra/newview/llmeshrepository.h +++ b/indra/newview/llmeshrepository.h @@ -90,54 +90,6 @@ public:  	}  }; -class LLImportMaterial -{ -public: -	LLPointer<LLViewerFetchedTexture> mDiffuseMap; -	std::string mDiffuseMapFilename; -	std::string mDiffuseMapLabel; -	std::string mBinding; -	LLColor4 mDiffuseColor; -	bool mFullbright; - -	bool operator<(const LLImportMaterial ¶ms) const; - -	LLImportMaterial()  -		: mFullbright(false)  -	{  -		mDiffuseColor.set(1,1,1,1); -	} - -	LLImportMaterial(LLSD& data); - -	LLSD asLLSD(); -}; - -class LLModelInstance  -{ -public: -	LLPointer<LLModel> mModel; -	LLPointer<LLModel> mLOD[5]; -	 -	std::string mLabel; - -	LLUUID mMeshID; -	S32 mLocalMeshID; - -	LLMatrix4 mTransform; -	std::map<std::string, LLImportMaterial> mMaterial; - -	LLModelInstance(LLModel* model, const std::string& label, LLMatrix4& transform, std::map<std::string, LLImportMaterial>& materials) -		: mModel(model), mLabel(label), mTransform(transform), mMaterial(materials) -	{ -		mLocalMeshID = -1; -	} - -	LLModelInstance(LLSD& data); - -	LLSD asLLSD(); -}; -  class LLPhysicsDecomp : public LLThread  {  public: @@ -483,6 +435,8 @@ public:  	// Inherited from LLCore::HttpHandler  	virtual void onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response); +        LLViewerFetchedTexture* FindViewerTexture(const LLImportMaterial& material); +  private:  	LLHandle<LLWholeModelFeeObserver> mFeeObserverHandle;  	LLHandle<LLWholeModelUploadObserver> mUploadObserverHandle; diff --git a/indra/newview/skins/default/xui/en/floater_model_preview.xml b/indra/newview/skins/default/xui/en/floater_model_preview.xml index a4acd1df78..7183b2f1f9 100755 --- a/indra/newview/skins/default/xui/en/floater_model_preview.xml +++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml @@ -31,6 +31,7 @@    <string name="mesh_status_too_many_vertices">Level of detail has too many vertices.</string>    <string name="mesh_status_missing_lod">Missing required level of detail.</string>    <string name="mesh_status_invalid_material_list">LOD materials are not a subset of reference model.</string> +  <string name="phys_status_vertex_limit_exceeded">Some physical hulls exceed vertex limitations.</string>    <string name="layer_all">All</string> <!-- Text to display in physics layer combo box for "all layers" -->    <string name="decomposing">Analyzing...</string>    <string name="simplifying">Simplifying...</string> @@ -66,7 +67,7 @@            follows="top|left"            layout="topleft"            height="19" -          max_length_bytes="64" +          max_length_bytes="63"            name="description_form"            prevalidate_callback="ascii"            top_pad="5" @@ -1027,19 +1028,19 @@                    bg_alpha_color="0 0 0 0"                    bg_opaque_color="0 0 0 0.3"                    follows="left|top" -                  height="16" +                  height="19"                    layout="topleft"                    left="18"                    name="physics info" -                  top_pad="15" -                  width="589"> +                  top_pad="12" +                  width="319">                      <text                        follows="top|left"                        height="15"                        layout="topleft"                        left="0"                        text_color="White" -                      top_pad="0" +                      top_pad="3"                        name="results_text"                        width="50">                        Results: @@ -1077,6 +1078,33 @@                        Hulls: [HULLS]                      </text>                  </panel> +                <panel +                 bg_alpha_color="0 0 0 0" +                 bg_opaque_color="0 0 0 0.3" +                 follows="left|top" +                 height="19" +                 layout="topleft" +                 left_pad="5" +                 top_delta="0" +                 name="physics message" +                 width="270"> +                     <icon +                      follows="left|top" +                      height="16" +                      left="0" +                      layout="topleft" +                      name="physics_status_message_icon" +                      top_pad="0" +                      width="16" /> +                     <text +                      follows="left|top" +                      height="15" +                      layout="topleft" +                      left_pad="2" +                      name="physics_status_message_text" +                      width="252" +                      top_delta="3"/> +                </panel>          </panel>        <!-- MODIFIERS PANEL -->       <panel diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index cfe56e6a95..7055fa94d1 100755 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -8015,9 +8015,8 @@ Select residents to share with.      name="MeshUploadError"      icon="alert.tga"      type="alert"> -    [LABEL] failed to upload: [MESSAGE] [IDENTIFIER]  - -See the log file for details. +      [LABEL] failed to upload: [MESSAGE] [IDENTIFIER] +[DETAILS]See SecondLife.log for details    </notification>    <notification diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index ca38a9bc3f..c26f8174ed 100755 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -4075,5 +4075,17 @@ Try enclosing path to the editor with double quotes.    <string name="loading_chat_logs">      Loading...    </string> -   -  </strings> + +  <string name="Mav_Details_MAV_FOUND_DEGENERATE_TRIANGLES"> +      The physics shape contains triangles which are too small. Try simplifying the physics model. +  </string> + +  <string name="Mav_Details_MAV_CONFIRMATION_DATA_MISMATCH"> +      The physics shape contains bad confirmation data. Try to correct the physics model. +  </string> + +  <string name="Mav_Details_MAV_UNKNOWN_VERSION"> +      The physics shape does not have correct version. Set the correct version for the physics model. +  </string> + +</strings> | 
