diff options
24 files changed, 4860 insertions, 3569 deletions
| diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index 763f5a3521..8dbb18aa08 100755 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -35,6 +35,7 @@ set(llcommon_SOURCE_FILES      llbase32.cpp      llbase64.cpp      llbitpack.cpp +    llcallbacklist.cpp      llcommon.cpp      llcommonutils.cpp      llcoros.cpp @@ -126,6 +127,7 @@ set(llcommon_HEADER_FILES      llbase64.h      llbitpack.h      llboost.h +    llcallbacklist.h      llcommon.h      llcommonutils.h      llcoros.h diff --git a/indra/llcommon/llcallbacklist.cpp b/indra/llcommon/llcallbacklist.cpp new file mode 100644 index 0000000000..541ff75ee4 --- /dev/null +++ b/indra/llcommon/llcallbacklist.cpp @@ -0,0 +1,230 @@ +/**  + * @file llcallbacklist.cpp + * @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$ + */ + +#include "llcallbacklist.h" +#include "lleventtimer.h" +#include "llerrorlegacy.h" + +// Globals +// +LLCallbackList gIdleCallbacks; + +// +// Member functions +// + +LLCallbackList::LLCallbackList() +{ +	// nothing +} + +LLCallbackList::~LLCallbackList() +{ +} + + +void LLCallbackList::addFunction( callback_t func, void *data) +{ +	if (!func) +	{ +		return; +	} + +	// only add one callback per func/data pair +	// +	if (containsFunction(func)) +	{ +		return; +	} +	 +	callback_pair_t t(func, data); +	mCallbackList.push_back(t); +} + +bool LLCallbackList::containsFunction( callback_t func, void *data) +{ +	callback_pair_t t(func, data); +	callback_list_t::iterator iter = find(func,data); +	if (iter != mCallbackList.end()) +	{ +		return TRUE; +	} +	else +	{ +		return FALSE; +	} +} + + +bool LLCallbackList::deleteFunction( callback_t func, void *data) +{ +	callback_list_t::iterator iter = find(func,data); +	if (iter != mCallbackList.end()) +	{ +		mCallbackList.erase(iter); +		return TRUE; +	} +	else +	{ +		return FALSE; +	} +} + +inline  +LLCallbackList::callback_list_t::iterator +LLCallbackList::find(callback_t func, void *data) +{ +	callback_pair_t t(func, data); +	return std::find(mCallbackList.begin(), mCallbackList.end(), t); +} + +void LLCallbackList::deleteAllFunctions() +{ +	mCallbackList.clear(); +} + + +void LLCallbackList::callFunctions() +{ +	for (callback_list_t::iterator iter = mCallbackList.begin(); iter != mCallbackList.end();  ) +	{ +		callback_list_t::iterator curiter = iter++; +		curiter->first(curiter->second); +	} +} + +// Shim class to allow arbitrary boost::bind +// expressions to be run as one-time idle callbacks. +class OnIdleCallbackOneTime +{ +public: +	OnIdleCallbackOneTime(nullary_func_t callable): +		mCallable(callable) +	{ +	} +	static void onIdle(void *data) +	{ +		gIdleCallbacks.deleteFunction(onIdle, data); +		OnIdleCallbackOneTime* self = reinterpret_cast<OnIdleCallbackOneTime*>(data); +		self->call(); +		delete self; +	} +	void call() +	{ +		mCallable(); +	} +private: +	nullary_func_t mCallable; +}; + +void doOnIdleOneTime(nullary_func_t callable) +{ +	OnIdleCallbackOneTime* cb_functor = new OnIdleCallbackOneTime(callable); +	gIdleCallbacks.addFunction(&OnIdleCallbackOneTime::onIdle,cb_functor); +} + +// Shim class to allow generic boost functions to be run as +// recurring idle callbacks.  Callable should return true when done, +// false to continue getting called. +class OnIdleCallbackRepeating +{ +public: +	OnIdleCallbackRepeating(bool_func_t callable): +		mCallable(callable) +	{ +	} +	// Will keep getting called until the callable returns true. +	static void onIdle(void *data) +	{ +		OnIdleCallbackRepeating* self = reinterpret_cast<OnIdleCallbackRepeating*>(data); +		bool done = self->call(); +		if (done) +		{ +			gIdleCallbacks.deleteFunction(onIdle, data); +			delete self; +		} +	} +	bool call() +	{ +		return mCallable(); +	} +private: +	bool_func_t mCallable; +}; + +void doOnIdleRepeating(bool_func_t callable) +{ +	OnIdleCallbackRepeating* cb_functor = new OnIdleCallbackRepeating(callable); +	gIdleCallbacks.addFunction(&OnIdleCallbackRepeating::onIdle,cb_functor); +} + +class NullaryFuncEventTimer: public LLEventTimer +{ +public: +	NullaryFuncEventTimer(nullary_func_t callable, F32 seconds): +		LLEventTimer(seconds), +		mCallable(callable) +	{ +	} + +private: +	BOOL tick() +	{ +		mCallable(); +		return TRUE; +	} + +	nullary_func_t mCallable; +}; + +// Call a given callable once after specified interval. +void doAfterInterval(nullary_func_t callable, F32 seconds) +{ +	new NullaryFuncEventTimer(callable, seconds); +} + +class BoolFuncEventTimer: public LLEventTimer +{ +public: +	BoolFuncEventTimer(bool_func_t callable, F32 seconds): +		LLEventTimer(seconds), +		mCallable(callable) +	{ +	} +private: +	BOOL tick() +	{ +		return mCallable(); +	} + +	bool_func_t mCallable; +}; + +// Call a given callable every specified number of seconds, until it returns true. +void doPeriodically(bool_func_t callable, F32 seconds) +{ +	new BoolFuncEventTimer(callable, seconds); +} diff --git a/indra/newview/llcallbacklist.h b/indra/llcommon/llcallbacklist.h index 0516c9cdb4..89716cd74c 100755..100644 --- a/indra/newview/llcallbacklist.h +++ b/indra/llcommon/llcallbacklist.h @@ -28,27 +28,34 @@  #define LL_LLCALLBACKLIST_H  #include "llstl.h" +#include <boost/function.hpp> +#include <list>  class LLCallbackList  {  public:  	typedef void (*callback_t)(void*); + +	typedef std::pair< callback_t,void* >	callback_pair_t; +	// NOTE: It is confirmed that we DEPEND on the order provided by using a list :( +	// +	typedef std::list< callback_pair_t >	callback_list_t;   	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 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; + +	inline callback_list_t::iterator find(callback_t func, void *data); +  	callback_list_t	mCallbackList;  }; diff --git a/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h index 7d1d541a4b..1dca8ee507 100755 --- a/indra/llcommon/llmemory.h +++ b/indra/llcommon/llmemory.h @@ -28,6 +28,7 @@  #include "linden_common.h"  #include "llunits.h" +#include "stdtypes.h"  #if !LL_WINDOWS  #include <stdint.h>  #endif @@ -59,7 +60,7 @@ class LLMutex ;  LL_COMMON_API void ll_assert_aligned_func(uintptr_t ptr,U32 alignment);  #ifdef SHOW_ASSERT -#define ll_assert_aligned(ptr,alignment) ll_assert_aligned_func(reinterpret_cast<uintptr_t>(ptr),((U32)alignment)) +#define ll_assert_aligned(ptr,alignment) ll_assert_aligned_func(uintptr_t(ptr),((U32)alignment))  #else  #define ll_assert_aligned(ptr,alignment)  #endif @@ -69,13 +70,13 @@ LL_COMMON_API void ll_assert_aligned_func(uintptr_t ptr,U32 alignment);  template <typename T> T* LL_NEXT_ALIGNED_ADDRESS(T* address)   {   	return reinterpret_cast<T*>( -		(reinterpret_cast<uintptr_t>(address) + 0xF) & ~0xF); +		(uintptr_t(address) + 0xF) & ~0xF);  }  template <typename T> T* LL_NEXT_ALIGNED_ADDRESS_64(T* address)   {   	return reinterpret_cast<T*>( -		(reinterpret_cast<uintptr_t>(address) + 0x3F) & ~0x3F); +		(uintptr_t(address) + 0x3F) & ~0x3F);  }  #if LL_LINUX || LL_DARWIN @@ -102,7 +103,7 @@ inline void* ll_aligned_malloc_fallback( size_t size, int align )  #else  	void* mem = malloc( size + (align - 1) + sizeof(void*) );  	char* aligned = ((char*)mem) + sizeof(void*); -	aligned += align - ((uintptr_t)aligned & (align - 1)); +	aligned += align - (uintptr_t(aligned) & (align - 1));  	((void**)aligned)[-1] = mem;  	return aligned; diff --git a/indra/llcommon/llmutex.h b/indra/llcommon/llmutex.h index 3659a319a2..ea535cee86 100644 --- a/indra/llcommon/llmutex.h +++ b/indra/llcommon/llmutex.h @@ -33,6 +33,10 @@  #define MUTEX_DEBUG (LL_DEBUG || LL_RELEASE_WITH_DEBUG_INFO) +#if MUTEX_DEBUG +#include <map> +#endif +  struct apr_thread_mutex_t;  struct apr_pool_t;  struct apr_thread_cond_t; diff --git a/indra/llcommon/llstl.h b/indra/llcommon/llstl.h index 02f10fa2ba..0435cb8a08 100755 --- a/indra/llcommon/llstl.h +++ b/indra/llcommon/llstl.h @@ -27,6 +27,7 @@  #ifndef LL_LLSTL_H  #define LL_LLSTL_H +#include "stdtypes.h"  #include <functional>  #include <algorithm>  #include <map> @@ -272,6 +273,7 @@ inline T get_if_there(const std::map<K,T>& inmap, const K& key, T default_value)  	}  }; +// Useful for replacing the removeObj() functionality of LLDynamicArray  // Example:  //  for (std::vector<T>::iterator iter = mList.begin(); iter != mList.end(); )  //  { @@ -530,7 +532,7 @@ bool before(const std::type_info* lhs, const std::type_info* rhs)      return strcmp(lhs->name(), rhs->name()) < 0;  #else  // not Linux, or gcc 4.4+      // Just use before(), as we normally would -    return lhs->before(*rhs); +    return lhs->before(*rhs) ? true : false;  #endif  } diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h index 2f38ae7203..23c7f5d7af 100755 --- a/indra/llmath/llvolume.h +++ b/indra/llmath/llvolume.h @@ -968,6 +968,7 @@ protected:  	~LLVolume(); // use unref  public: +	typedef std::vector<LLVolumeFace> face_list_t;  	struct FaceParams  	{ @@ -1040,6 +1041,10 @@ public:  																				// conversion if *(LLVolume*) to LLVolume&  	const LLVolumeFace &getVolumeFace(const S32 f) const {return mVolumeFaces[f];} // DO NOT DELETE VOLUME WHILE USING THIS REFERENCE, OR HOLD A POINTER TO THIS VOLUMEFACE +	LLVolumeFace &getVolumeFace(const S32 f) {return mVolumeFaces[f];} // DO NOT DELETE VOLUME WHILE USING THIS REFERENCE, OR HOLD A POINTER TO THIS VOLUMEFACE + +	face_list_t& getVolumeFaces() { return mVolumeFaces; } +  	U32					mFaceMask;			// bit array of which faces exist in this volume  	LLVector3			mLODScaleBias;		// vector for biasing LOD based on scale @@ -1077,7 +1082,6 @@ public:  	BOOL mGenerateSingleFace; -	typedef std::vector<LLVolumeFace> face_list_t;  	face_list_t mVolumeFaces;  public: diff --git a/indra/llmath/m4math.cpp b/indra/llmath/m4math.cpp index 6a1b4143cf..d89c482804 100755 --- a/indra/llmath/m4math.cpp +++ b/indra/llmath/m4math.cpp @@ -274,6 +274,19 @@ const LLMatrix4&	LLMatrix4::invert(void)  	return *this;  } +// Convenience func for simplifying comparison-heavy code by +// intentionally stomping values in [-FLT_EPS,FLT_EPS] to 0.0f +// +void LLMatrix4::condition(void) +{ +	U32 i; +	U32 j; +	for (i = 0; i < 3;i++) +		for (j = 0; j < 3;j++) +			mMatrix[i][j] = ((mMatrix[i][j] > -FLT_EPSILON) +							  && (mMatrix[i][j] < FLT_EPSILON)) ? 0.0f : mMatrix[i][j]; +} +  LLVector4 LLMatrix4::getFwdRow4() const  {  	return LLVector4(mMatrix[VX][VX], mMatrix[VX][VY], mMatrix[VX][VZ], mMatrix[VX][VW]); diff --git a/indra/llmath/m4math.h b/indra/llmath/m4math.h index a7dce10397..a77c5bc76d 100755 --- a/indra/llmath/m4math.h +++ b/indra/llmath/m4math.h @@ -180,6 +180,11 @@ public:  	const LLMatrix4& setTranslation(const LLVector4 &translation);  	const LLMatrix4& setTranslation(const LLVector3 &translation); +	// Convenience func for simplifying comparison-heavy code by +	// intentionally stomping values [-FLT_EPS,FLT_EPS] to 0.0 +	// +	void condition(void); +  	///////////////////////////  	//  	// Get properties of a matrix diff --git a/indra/llprimitive/CMakeLists.txt b/indra/llprimitive/CMakeLists.txt index d1475cf734..75ce624a58 100755 --- a/indra/llprimitive/CMakeLists.txt +++ b/indra/llprimitive/CMakeLists.txt @@ -8,6 +8,7 @@ include(LLMath)  include(LLMessage)  include(LLXML)  include(LLPhysicsExtensions) +include(LLCharacter)  include_directories(      ${LLCOMMON_INCLUDE_DIRS} @@ -16,6 +17,7 @@ include_directories(      ${LLXML_INCLUDE_DIRS}      ${LIBS_PREBUILT_DIR}/include/collada      ${LIBS_PREBUILT_DIR}/include/collada/1.4 +    ${LLCHARACTER_INCLUDE_DIRS}      )  include_directories(SYSTEM      ${LLCOMMON_SYSTEM_INCLUDE_DIRS} @@ -24,11 +26,13 @@ include_directories(SYSTEM      )  set(llprimitive_SOURCE_FILES +    lldaeloader.cpp      llmaterialid.cpp      llmaterial.cpp      llmaterialtable.cpp      llmediaentry.cpp      llmodel.cpp +    llmodelloader.cpp      llprimitive.cpp      llprimtexturelist.cpp      lltextureanim.cpp @@ -40,16 +44,17 @@ set(llprimitive_SOURCE_FILES  set(llprimitive_HEADER_FILES      CMakeLists.txt - +    lldaeloader.h      legacy_object_types.h -    lllslconstants.h      llmaterial.h      llmaterialid.h      llmaterialtable.h      llmediaentry.h      llmodel.h +    llmodelloader.h      llprimitive.h      llprimtexturelist.h +    lllslconstants.h      lltextureanim.h      lltextureentry.h      lltreeparams.h @@ -72,6 +77,7 @@ target_link_libraries(llprimitive      ${LLMESSAGE_LIBRARIES}      ${LLXML_LIBRARIES}      ${LLPHYSICSEXTENSIONS_LIBRARIES} +    ${LLCHARACTER_LIBRARIES}      ) diff --git a/indra/llprimitive/lldaeloader.cpp b/indra/llprimitive/lldaeloader.cpp new file mode 100644 index 0000000000..ff71d52138 --- /dev/null +++ b/indra/llprimitive/lldaeloader.cpp @@ -0,0 +1,2347 @@ +/** + * @file lldaeloader.cpp + * @brief LLDAELoader class implementation + * + * $LicenseInfo:firstyear=2013&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2013, 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$ + */ + +#if LL_MSVC +#pragma warning (disable : 4263) +#pragma warning (disable : 4264) +#endif +#include "dae.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 <boost/lexical_cast.hpp> + +#include "lldaeloader.h" +#include "llsdserialize.h" +#include "lljoint.h" + +#include "glh/glh_linear.h" +#include "llmatrix4a.h" + +std::string colladaVersion[VERSIONTYPE_COUNT+1] =  +{ +	"1.4.0", +	"1.4.1", +	"Unsupported" +}; + +bool get_dom_sources(const domInputLocalOffset_Array& inputs, S32& pos_offset, S32& tc_offset, S32& norm_offset, S32 &idx_stride, +	domSource* &pos_source, domSource* &tc_source, domSource* &norm_source) +{ +	idx_stride = 0; + +	for (U32 j = 0; j < inputs.getCount(); ++j) +	{ +		idx_stride = llmax((S32) inputs[j]->getOffset(), idx_stride); + +		if (strcmp(COMMON_PROFILE_INPUT_VERTEX, inputs[j]->getSemantic()) == 0) +		{ //found vertex array +			const domURIFragmentType& uri = inputs[j]->getSource(); +			daeElementRef elem = uri.getElement(); +			domVertices* vertices = (domVertices*) elem.cast(); +			if ( !vertices ) +			{ +				return false; +			} + +			domInputLocal_Array& v_inp = vertices->getInput_array(); + + +			for (U32 k = 0; k < v_inp.getCount(); ++k) +			{ +				if (strcmp(COMMON_PROFILE_INPUT_POSITION, v_inp[k]->getSemantic()) == 0) +				{ +					pos_offset = inputs[j]->getOffset(); + +					const domURIFragmentType& uri = v_inp[k]->getSource(); +					daeElementRef elem = uri.getElement(); +					pos_source = (domSource*) elem.cast(); +				} + +				if (strcmp(COMMON_PROFILE_INPUT_NORMAL, v_inp[k]->getSemantic()) == 0) +				{ +					norm_offset = inputs[j]->getOffset(); + +					const domURIFragmentType& uri = v_inp[k]->getSource(); +					daeElementRef elem = uri.getElement(); +					norm_source = (domSource*) elem.cast(); +				} +			} +		} + +		if (strcmp(COMMON_PROFILE_INPUT_NORMAL, inputs[j]->getSemantic()) == 0) +		{ +			//found normal array for this triangle list +			norm_offset = inputs[j]->getOffset(); +			const domURIFragmentType& uri = inputs[j]->getSource(); +			daeElementRef elem = uri.getElement(); +			norm_source = (domSource*) elem.cast(); +		} +		else if (strcmp(COMMON_PROFILE_INPUT_TEXCOORD, inputs[j]->getSemantic()) == 0) +		{ //found texCoords +			tc_offset = inputs[j]->getOffset(); +			const domURIFragmentType& uri = inputs[j]->getSource(); +			daeElementRef elem = uri.getElement(); +			tc_source = (domSource*) elem.cast(); +		} +	} + +	idx_stride += 1; + +	return true; +} + +LLModel::EModelStatus load_face_from_dom_triangles(std::vector<LLVolumeFace>& face_list, std::vector<std::string>& materials, domTrianglesRef& tri) +{ +	LLVolumeFace face; +	std::vector<LLVolumeFace::VertexData> verts; +	std::vector<U16> indices; +	 +	const domInputLocalOffset_Array& inputs = tri->getInput_array(); + +	S32 pos_offset = -1; +	S32 tc_offset = -1; +	S32 norm_offset = -1; + +	domSource* pos_source = NULL; +	domSource* tc_source = NULL; +	domSource* norm_source = NULL; + +	S32 idx_stride = 0; + +	if ( !get_dom_sources(inputs, pos_offset, tc_offset, norm_offset, idx_stride, pos_source, tc_source, norm_source) || !pos_source ) +	{ +		return LLModel::BAD_ELEMENT; +	} + +	 +	domPRef p = tri->getP(); +	domListOfUInts& idx = p->getValue(); +	 +	domListOfFloats  dummy ; +	domListOfFloats& v = pos_source ? pos_source->getFloat_array()->getValue() : dummy ; +	domListOfFloats& tc = tc_source ? tc_source->getFloat_array()->getValue() : dummy ; +	domListOfFloats& n = norm_source ? norm_source->getFloat_array()->getValue() : dummy ; + +	if (pos_source) +	{ +		face.mExtents[0].set(v[0], v[1], v[2]); +		face.mExtents[1].set(v[0], v[1], v[2]); +	} +	 +	LLVolumeFace::VertexMapData::PointMap point_map; +	 +	for (U32 i = 0; i < idx.getCount(); i += idx_stride) +	{ +		LLVolumeFace::VertexData cv; +		if (pos_source) +		{ +			cv.setPosition(LLVector4a(v[idx[i+pos_offset]*3+0], +								v[idx[i+pos_offset]*3+1], +								v[idx[i+pos_offset]*3+2])); +		} + +		if (tc_source) +		{ +			cv.mTexCoord.setVec(tc[idx[i+tc_offset]*2+0], +								tc[idx[i+tc_offset]*2+1]); +		} +		 +		if (norm_source) +		{ +			cv.setNormal(LLVector4a(n[idx[i+norm_offset]*3+0], +								n[idx[i+norm_offset]*3+1], +								n[idx[i+norm_offset]*3+2])); +		} +		 +		BOOL found = FALSE; +			 +		LLVolumeFace::VertexMapData::PointMap::iterator point_iter; +		point_iter = point_map.find(LLVector3(cv.getPosition().getF32ptr())); +		 +		if (point_iter != point_map.end()) +		{ +			for (U32 j = 0; j < point_iter->second.size(); ++j) +			{ +				// We have a matching loc +				// +				if ((point_iter->second)[j] == cv) +				{ +					U16 shared_index	= (point_iter->second)[j].mIndex; + +					// Don't share verts within the same tri, degenerate +					// +					if ((indices.size() % 3) && (indices[indices.size()-1] != shared_index)) +					{ +						found = true; +						indices.push_back(shared_index); +					} +					break; +				} +			} +		} + +		if (!found) +		{ +			update_min_max(face.mExtents[0], face.mExtents[1], cv.getPosition()); +			verts.push_back(cv); +			if (verts.size() >= 65535) +			{ +				//llerrs << "Attempted to write model exceeding 16-bit index buffer limitation." << LL_ENDL; +				return LLModel::VERTEX_NUMBER_OVERFLOW ; +			} +			U16 index = (U16) (verts.size()-1); +			indices.push_back(index); + +			LLVolumeFace::VertexMapData d; +			d.setPosition(cv.getPosition()); +			d.mTexCoord = cv.mTexCoord; +			d.setNormal(cv.getNormal()); +			d.mIndex = index; +			if (point_iter != point_map.end()) +			{ +				point_iter->second.push_back(d); +			} +			else +			{ +				point_map[LLVector3(d.getPosition().getF32ptr())].push_back(d); +			} +		} + +		if (indices.size()%3 == 0 && verts.size() >= 65532) +			{ +				face_list.push_back(face); +				face_list.rbegin()->fillFromLegacyData(verts, indices); +				LLVolumeFace& new_face = *face_list.rbegin(); +				if (!norm_source) +				{ +					//ll_aligned_free_16(new_face.mNormals); +					new_face.mNormals = NULL; +				} + +				if (!tc_source) +				{ +					//ll_aligned_free_16(new_face.mTexCoords); +					new_face.mTexCoords = NULL; +				} + +				face = LLVolumeFace(); +				point_map.clear(); +			} +	} + +	if (!verts.empty()) +	{ +		std::string material; + +		if (tri->getMaterial()) +		{ +			material = std::string(tri->getMaterial()); +		} +		 +		materials.push_back(material); +		face_list.push_back(face); + +		face_list.rbegin()->fillFromLegacyData(verts, indices); +		LLVolumeFace& new_face = *face_list.rbegin(); +		if (!norm_source) +		{ +			//ll_aligned_free_16(new_face.mNormals); +			new_face.mNormals = NULL; +		} + +		if (!tc_source) +		{ +			//ll_aligned_free_16(new_face.mTexCoords); +			new_face.mTexCoords = NULL; +		} +	} + +	return LLModel::NO_ERRORS ; +} + +LLModel::EModelStatus load_face_from_dom_polylist(std::vector<LLVolumeFace>& face_list, std::vector<std::string>& materials, domPolylistRef& poly) +{ +	domPRef p = poly->getP(); +	domListOfUInts& idx = p->getValue(); + +	if (idx.getCount() == 0) +	{ +		return LLModel::NO_ERRORS ; +	} + +	const domInputLocalOffset_Array& inputs = poly->getInput_array(); + + +	domListOfUInts& vcount = poly->getVcount()->getValue(); +	 +	S32 pos_offset = -1; +	S32 tc_offset = -1; +	S32 norm_offset = -1; + +	domSource* pos_source = NULL; +	domSource* tc_source = NULL; +	domSource* norm_source = NULL; + +	S32 idx_stride = 0; + +	if (!get_dom_sources(inputs, pos_offset, tc_offset, norm_offset, idx_stride, pos_source, tc_source, norm_source)) +	{ +		return LLModel::BAD_ELEMENT; +	} + +	LLVolumeFace face; + +	std::vector<U16> indices; +	std::vector<LLVolumeFace::VertexData> verts; + +	domListOfFloats v; +	domListOfFloats tc; +	domListOfFloats n; + +	if (pos_source) +	{ +		v = pos_source->getFloat_array()->getValue(); +		face.mExtents[0].set(v[0], v[1], v[2]); +		face.mExtents[1].set(v[0], v[1], v[2]); +	} + +	if (tc_source) +	{ +		tc = tc_source->getFloat_array()->getValue(); +	} + +	if (norm_source) +	{ +		n = norm_source->getFloat_array()->getValue(); +	} +	 +	LLVolumeFace::VertexMapData::PointMap point_map; + +	U32 cur_idx = 0; +	for (U32 i = 0; i < vcount.getCount(); ++i) +	{ //for each polygon +		U32 first_index = 0; +		U32 last_index = 0; +		for (U32 j = 0; j < vcount[i]; ++j) +		{ //for each vertex + +			LLVolumeFace::VertexData cv; + +			if (pos_source) +			{ +				cv.getPosition().set(v[idx[cur_idx+pos_offset]*3+0], +									v[idx[cur_idx+pos_offset]*3+1], +									v[idx[cur_idx+pos_offset]*3+2]); +				if (!cv.getPosition().isFinite3()) +				{ +					LL_WARNS() << "Found NaN while loading position data from DAE-Model, invalid model." << LL_ENDL; +					return LLModel::BAD_ELEMENT; +				} +			} + +			if (tc_source) +			{ +				cv.mTexCoord.setVec(tc[idx[cur_idx+tc_offset]*2+0], +									tc[idx[cur_idx+tc_offset]*2+1]); +			} +			 +			if (norm_source) +			{ +				cv.getNormal().set(n[idx[cur_idx+norm_offset]*3+0], +									n[idx[cur_idx+norm_offset]*3+1], +									n[idx[cur_idx+norm_offset]*3+2]); + +				if (!cv.getNormal().isFinite3()) +				{ +					LL_WARNS() << "Found NaN while loading normals from DAE-Model, invalid model." << LL_ENDL; +					return LLModel::BAD_ELEMENT; +				} +			} +			 +			cur_idx += idx_stride; +			 +			BOOL found = FALSE; +				 +			LLVolumeFace::VertexMapData::PointMap::iterator point_iter; +			LLVector3 pos3(cv.getPosition().getF32ptr()); +			point_iter = point_map.find(pos3); +			 +			if (point_iter != point_map.end()) +			{ +				for (U32 k = 0; k < point_iter->second.size(); ++k) +				{ +					if ((point_iter->second)[k] == cv) +					{ +						found = TRUE; +						U32 index = (point_iter->second)[k].mIndex; +						if (j == 0) +						{ +							first_index = index; +						} +						else if (j == 1) +						{ +							last_index = index; +						} +						else +						{ +							// if these are the same, we have a very, very skinny triangle (coincident verts on one or more edges) +							// +							llassert((first_index != last_index) && (last_index != index) && (first_index != index)); +							indices.push_back(first_index); +							indices.push_back(last_index); +							indices.push_back(index); +							last_index = index; +						} + +						break; +					} +				} +			} + +			if (!found) +			{ +				update_min_max(face.mExtents[0], face.mExtents[1], cv.getPosition()); +				verts.push_back(cv); +				if (verts.size() >= 65535) +				{ +					//llerrs << "Attempted to write model exceeding 16-bit index buffer limitation." << LL_ENDL; +					return LLModel::VERTEX_NUMBER_OVERFLOW ; +				} +				U16 index = (U16) (verts.size()-1); +			 +				if (j == 0) +				{ +					first_index = index; +				} +				else if (j == 1) +				{ +					last_index = index; +				} +				else +				{ +					// detect very skinny degenerate triangles with collapsed edges +					// +					llassert((first_index != last_index) && (last_index != index) && (first_index != index)); +					indices.push_back(first_index); +					indices.push_back(last_index); +					indices.push_back(index); +					last_index = index; +				}	 + +				LLVolumeFace::VertexMapData d; +				d.setPosition(cv.getPosition()); +				d.mTexCoord = cv.mTexCoord; +				d.setNormal(cv.getNormal()); +				d.mIndex = index; +				if (point_iter != point_map.end()) +				{ +					point_iter->second.push_back(d); +				} +				else +				{ +					point_map[pos3].push_back(d); +				} +			} + +			if (indices.size()%3 == 0 && indices.size() >= 65532) +			{ +				face_list.push_back(face); +				face_list.rbegin()->fillFromLegacyData(verts, indices); +				LLVolumeFace& new_face = *face_list.rbegin(); +				if (!norm_source) +				{ +					//ll_aligned_free_16(new_face.mNormals); +					new_face.mNormals = NULL; +				} + +				if (!tc_source) +				{ +					//ll_aligned_free_16(new_face.mTexCoords); +					new_face.mTexCoords = NULL; +				} + +				face = LLVolumeFace(); +				verts.clear(); +				indices.clear(); +				point_map.clear(); +			} +		} +	} + +	if (!verts.empty()) +	{ +		std::string material; + +		if (poly->getMaterial()) +		{ +			material = std::string(poly->getMaterial()); +		} +	 +		materials.push_back(material); +		face_list.push_back(face); +		face_list.rbegin()->fillFromLegacyData(verts, indices); + +		LLVolumeFace& new_face = *face_list.rbegin(); +		if (!norm_source) +		{ +			//ll_aligned_free_16(new_face.mNormals); +			new_face.mNormals = NULL; +		} + +		if (!tc_source) +		{ +			//ll_aligned_free_16(new_face.mTexCoords); +			new_face.mTexCoords = NULL; +		} +	} + +	return LLModel::NO_ERRORS ; +} + +LLModel::EModelStatus load_face_from_dom_polygons(std::vector<LLVolumeFace>& face_list, std::vector<std::string>& materials, domPolygonsRef& poly) +{ +	LLVolumeFace face; +	std::vector<U16> indices; +	std::vector<LLVolumeFace::VertexData> verts; + +	const domInputLocalOffset_Array& inputs = poly->getInput_array(); + +	S32 v_offset = -1; +	S32 n_offset = -1; +	S32 t_offset = -1; + +	domListOfFloats* v = NULL; +	domListOfFloats* n = NULL; +	domListOfFloats* t = NULL; +	 +	U32 stride = 0; +	for (U32 i = 0; i < inputs.getCount(); ++i) +	{ +		stride = llmax((U32) inputs[i]->getOffset()+1, stride); + +		if (strcmp(COMMON_PROFILE_INPUT_VERTEX, inputs[i]->getSemantic()) == 0) +		{ //found vertex array +			v_offset = inputs[i]->getOffset(); + +			const domURIFragmentType& uri = inputs[i]->getSource(); +			daeElementRef elem = uri.getElement(); +			domVertices* vertices = (domVertices*) elem.cast(); +			if (!vertices) +			{ +				return LLModel::BAD_ELEMENT; +			} +			domInputLocal_Array& v_inp = vertices->getInput_array(); + +			for (U32 k = 0; k < v_inp.getCount(); ++k) +			{ +				if (strcmp(COMMON_PROFILE_INPUT_POSITION, v_inp[k]->getSemantic()) == 0) +				{ +					const domURIFragmentType& uri = v_inp[k]->getSource(); +					daeElementRef elem = uri.getElement(); +					domSource* src = (domSource*) elem.cast(); +					if (!src) +					{ +						return LLModel::BAD_ELEMENT; +					} +					v = &(src->getFloat_array()->getValue()); +				} +			} +		} +		else if (strcmp(COMMON_PROFILE_INPUT_NORMAL, inputs[i]->getSemantic()) == 0) +		{ +			n_offset = inputs[i]->getOffset(); +			//found normal array for this triangle list +			const domURIFragmentType& uri = inputs[i]->getSource(); +			daeElementRef elem = uri.getElement(); +			domSource* src = (domSource*) elem.cast(); +			if (!src) +			{ +				return LLModel::BAD_ELEMENT; +			} +			n = &(src->getFloat_array()->getValue()); +		} +		else if (strcmp(COMMON_PROFILE_INPUT_TEXCOORD, inputs[i]->getSemantic()) == 0 && inputs[i]->getSet() == 0) +		{ //found texCoords +			t_offset = inputs[i]->getOffset(); +			const domURIFragmentType& uri = inputs[i]->getSource(); +			daeElementRef elem = uri.getElement(); +			domSource* src = (domSource*) elem.cast(); +			if (!src) +			{ +				return LLModel::BAD_ELEMENT; +			} +			t = &(src->getFloat_array()->getValue()); +		} +	} + +	domP_Array& ps = poly->getP_array(); + +	//make a triangle list in <verts> +	for (U32 i = 0; i < ps.getCount(); ++i) +	{ //for each polygon +		domListOfUInts& idx = ps[i]->getValue(); +		for (U32 j = 0; j < idx.getCount()/stride; ++j) +		{ //for each vertex +			if (j > 2) +			{ +				U32 size = verts.size(); +				LLVolumeFace::VertexData v0 = verts[size-3]; +				LLVolumeFace::VertexData v1 = verts[size-1]; + +				verts.push_back(v0); +				verts.push_back(v1); +			} + +			LLVolumeFace::VertexData vert; + + +			if (v) +			{ +				U32 v_idx = idx[j*stride+v_offset]*3; +				v_idx = llclamp(v_idx, (U32) 0, (U32) v->getCount()); +				vert.getPosition().set(v->get(v_idx), +								v->get(v_idx+1), +								v->get(v_idx+2)); +			} +			 +			//bounds check n and t lookups because some FBX to DAE converters +			//use negative indices and empty arrays to indicate data does not exist +			//for a particular channel +			if (n && n->getCount() > 0) +			{ +				U32 n_idx = idx[j*stride+n_offset]*3; +				n_idx = llclamp(n_idx, (U32) 0, (U32) n->getCount()); +				vert.getNormal().set(n->get(n_idx), +								n->get(n_idx+1), +								n->get(n_idx+2)); +			} +			else +			{ +				vert.getNormal().clear(); +			} + +			 +			if (t && t->getCount() > 0) +			{ +				U32 t_idx = idx[j*stride+t_offset]*2; +				t_idx = llclamp(t_idx, (U32) 0, (U32) t->getCount()); +				vert.mTexCoord.setVec(t->get(t_idx), +								t->get(t_idx+1));								 +			} +			else +			{ +				vert.mTexCoord.clear(); +			} + +						 +			verts.push_back(vert); +		} +	} + +	if (verts.empty()) +	{ +		return LLModel::NO_ERRORS; +	} + +	face.mExtents[0] = verts[0].getPosition(); +	face.mExtents[1] = verts[0].getPosition(); +	 +	//create a map of unique vertices to indices +	std::map<LLVolumeFace::VertexData, U32> vert_idx; + +	U32 cur_idx = 0; +	for (U32 i = 0; i < verts.size(); ++i) +	{ +		std::map<LLVolumeFace::VertexData, U32>::iterator iter = vert_idx.find(verts[i]); +		if (iter == vert_idx.end()) +		{ +			vert_idx[verts[i]] = cur_idx++; +		} +	} + +	//build vertex array from map +	std::vector<LLVolumeFace::VertexData> new_verts; +	new_verts.resize(vert_idx.size()); + +	for (std::map<LLVolumeFace::VertexData, U32>::iterator iter = vert_idx.begin(); iter != vert_idx.end(); ++iter) +	{ +		new_verts[iter->second] = iter->first; +		update_min_max(face.mExtents[0], face.mExtents[1], iter->first.getPosition()); +	} + +	//build index array from map +	indices.resize(verts.size()); + +	for (U32 i = 0; i < verts.size(); ++i) +	{ +		indices[i] = vert_idx[verts[i]]; +		llassert(!i || (indices[i-1] != indices[i])); +	} + +	// DEBUG just build an expanded triangle list +	/*for (U32 i = 0; i < verts.size(); ++i) +	{ +		indices.push_back((U16) i); +		update_min_max(face.mExtents[0], face.mExtents[1], verts[i].getPosition()); +	}*/ + +    if (!new_verts.empty()) +	{ +		std::string material; + +		if (poly->getMaterial()) +		{ +			material = std::string(poly->getMaterial()); +		} + +		materials.push_back(material); +		face_list.push_back(face); +		face_list.rbegin()->fillFromLegacyData(new_verts, indices); + +		LLVolumeFace& new_face = *face_list.rbegin(); +		if (!n) +		{ +			//ll_aligned_free_16(new_face.mNormals); +			new_face.mNormals = NULL; +		} + +		if (!t) +		{ +			//ll_aligned_free_16(new_face.mTexCoords); +			new_face.mTexCoords = NULL; +		} +	} + +	return LLModel::NO_ERRORS ; +} + +//----------------------------------------------------------------------------- +// LLDAELoader +//----------------------------------------------------------------------------- +LLDAELoader::LLDAELoader( +	std::string				filename, +	S32						lod, +	load_callback_t		load_cb, +	joint_lookup_func_t	joint_lookup_func, +	texture_load_func_t	texture_load_func, +	state_callback_t		state_cb, +	void*						opaque_userdata, +	JointTransformMap&	jointMap, +	JointSet&				jointsFromNodes ) +: LLModelLoader( +		filename, +		lod, +		load_cb, +		joint_lookup_func, +		texture_load_func, +		state_cb, +		opaque_userdata, +		jointMap, +		jointsFromNodes) +{ +} + +LLDAELoader::~LLDAELoader() +{ +} + +struct ModelSort +{ +	bool operator()(const LLPointer< LLModel >& lhs, const LLPointer< LLModel >& rhs) +	{ +        if (lhs->mSubmodelID < rhs->mSubmodelID) +        { +            return true; +        } +		return LLStringUtil::compareInsensitive(lhs->mLabel, rhs->mLabel) < 0; +	} +}; + +bool LLDAELoader::OpenFile(const std::string& filename) +{ +	//no suitable slm exists, load from the .dae file +	DAE dae; +	domCOLLADA* dom = dae.open(filename); +	 +	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 = 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; + +	mTransform.condition();	 + +	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) +		{ + +			std::vector<LLModel*> models; + +			loadModelsFromDomMesh(mesh, models); + +			std::vector<LLModel*>::iterator i; +			i = models.begin(); +			while (i != models.end()) +			{ +				LLModel* mdl = *i; +				if(mdl->getStatus() != LLModel::NO_ERRORS) +				{ +					setLoadState(ERROR_PARSING + mdl->getStatus()) ; +					return false; //abort +				} + +				if (mdl && validate_model(mdl)) +				{ +					mModelList.push_back(mdl); +					mModelsMap[mesh].push_back(mdl); +				} +				i++; +			} +		} +	} + +	std::sort(mModelList.begin(), mModelList.end(), ModelSort()); + +	model_list::iterator model_iter = mModelList.begin(); +	while (model_iter != mModelList.end()) +	{ +		LL_INFOS() << "Importing " << (*model_iter)->mLabel << LL_ENDL; +		std::vector<std::string>::iterator mat_iter = (*model_iter)->mMaterialList.begin(); +		while (mat_iter != (*model_iter)->mMaterialList.end()) +		{ +			LL_INFOS() << (*model_iter)->mLabel << " references " << (*mat_iter) << LL_ENDL; +			mat_iter++; +		} +		model_iter++; +	} + +	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) +				{ +					std::vector< LLPointer< LLModel > >::iterator i = mModelsMap[mesh].begin(); +					while (i != mModelsMap[mesh].end()) +					{ +						LLPointer<LLModel> mdl = *i; +						LLDAELoader::processDomModel(mdl, &dae, root, mesh, skin); +						i++; +					} +				} +			} +		} +	} + +	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, &dae ); +	 +	if ( badElement ) +	{ +		setLoadState( ERROR_PARSING ); +	} +	 +	return true; +} + +void LLDAELoader::processDomModel(LLModel* model, DAE* dae, daeElement* root, domMesh* mesh, domSkin* skin) +{ +	llassert(model && dae && mesh && skin); + +	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(); +				JointMap :: 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 ); +		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 ( getRigWithSceneParity() ) +			{	 +				JointMap :: const_iterator masterJointIt = mJointMap.begin(); +				JointMap :: 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 = mJointLookupFunc(lookingForJoint,mOpaqueData); +						if ( pJoint ) +						{    +							pJoint->storeCurrentXform( jointTransform.getTranslation() );												 +						} +						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; +		transformation.initScale(mesh_scale_vector); +		transformation.setTranslation(mesh_translation_vector); +		transformation *= mTransform; + +		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); +	} +} + +//----------------------------------------------------------------------------- +// buildJointToNodeMappingFromScene() +//----------------------------------------------------------------------------- +void LLDAELoader::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 LLDAELoader::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 LLDAELoader::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 ); +		} +	} +} + +//----------------------------------------------------------------------------- +// isNodeAJoint() +//----------------------------------------------------------------------------- +bool LLDAELoader::isNodeAJoint( domNode* pNode ) +{ +	if ( !pNode ) +	{ +		LL_INFOS()<<"Created node is NULL"<<LL_ENDL; +		return false; +	} +	 +	return LLModelLoader::isNodeAJoint(pNode->getName()); +} +//----------------------------------------------------------------------------- +// verifyCount +//----------------------------------------------------------------------------- +bool LLDAELoader::verifyCount( int expected, int result ) +{ +	if ( expected != result ) +	{ +		LL_INFOS()<< "Error: (expected/got)"<<expected<<"/"<<result<<"verts"<<LL_ENDL; +		return false; +	} +	return true; +} +//----------------------------------------------------------------------------- +// verifyController +//----------------------------------------------------------------------------- +bool LLDAELoader::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 LLDAELoader::extractTranslation( domTranslate* pTranslate, LLMatrix4& transform ) +{ +	domFloat3 jointTrans = pTranslate->getValue(); +	LLVector3 singleJointTranslation( jointTrans[0], jointTrans[1], jointTrans[2] ); +	transform.setTranslation( singleJointTranslation ); +} +//----------------------------------------------------------------------------- +// extractTranslationViaElement() +//----------------------------------------------------------------------------- +void LLDAELoader::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 LLDAELoader::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 LLDAELoader::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* LLDAELoader::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 LLDAELoader::processElement( daeElement* element, bool& badElement, DAE* dae ) +{ +	LLMatrix4 saved_transform; +	bool pushed_mat = false; + +	domNode* node = daeSafeCast<domNode>(element); +	if (node) +	{ +		pushed_mat = true; +		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; +		mTransform.condition(); +	} + +	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; +		mTransform.condition(); +	} + +	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; +		mTransform.condition(); +	} + +	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]; +			} +		} + +		mTransform *= matrix_transform; +		mTransform.condition(); +	} + +	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) +			{ + +				std::vector< LLPointer< LLModel > >::iterator i = mModelsMap[mesh].begin();				 +				while (i != mModelsMap[mesh].end()) +				{ +					LLModel* model = *i; + +					LLMatrix4 transformation = mTransform; +				 +					if (mTransform.determinant() < 0) +					{ //negative scales are not supported +						LL_INFOS() << "Negative scale detected, unsupported transform.  domInstance_geometry: " << getElementLabel(instance_geo) << LL_ENDL; +						badElement = true; +					} + +					LLModelLoader::material_map materials = getMaterials(model, instance_geo, dae); + +					// 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; + +					if (transformation.determinant() < 0) +					{ //negative scales are not supported +						LL_INFOS() << "Negative scale detected, unsupported post-normalization transform.  domInstance_geometry: " << getElementLabel(instance_geo) << LL_ENDL; +						badElement = true; +					} + +					std::string label = getElementLabel(instance_geo); +                    +                    llassert(!label.empty()); + +                    if (model->mSubmodelID) +                    { +                        // CHECK FOR _LODX and _PHYS here to ensure we bolt the submodel 'salt' at the right loc +                        // +                        if ((label.find("_LOD") != -1) || (label.find("_PHYS") != -1)) +                        { +                            std::string labelStart; +                            std::string markup; +                            size_t underscore_offset = label.rfind('_'); +                            if (underscore_offset != -1) +                            { +                                markup = label.substr(underscore_offset + 1, 4); +                                label.erase(label.begin() + underscore_offset, label.end()); +                                label +=(char)((int)'a' + model->mSubmodelID); +                                label += "_"; +                                label += markup; +                            } +                            else +                            { +                                label +=(char)((int)'a' + model->mSubmodelID); +                            }                             +                        } +                        else +                        { +                            label += (char)((int)'a' + model->mSubmodelID); +                        } +                    } + +                    model->mLabel = label; +                    +					mScene[transformation].push_back(LLModelInstance(model, label, transformation, materials)); +					stretch_extents(model, transformation, mExtents[0], mExtents[1], mFirstTransform); +					i++; +				} +			} +		} +		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, dae); +		} +	} + +	//process children +	daeTArray< daeSmartRef<daeElement> > children = element->getChildren(); +	int childCount = children.getCount(); +	for (S32 i = 0; i < childCount; i++) +	{ +		processElement(children[i],badElement, dae); +	} + +	if (pushed_mat) +	{ //this element was a node, restore transform before processiing siblings +		mTransform = saved_transform; +	} +} + +std::map<std::string, LLImportMaterial> LLDAELoader::getMaterials(LLModel* model, domInstance_geometry* instance_geo, DAE* dae) +{ +	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]; +					break; +				} +			} +		} + +		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, dae); +						} +					} +				} +			} +		} + +		import_material.mBinding = model->mMaterialList[i]; +		materials[model->mMaterialList[i]] = import_material; +	} + +	return materials; +} + +LLImportMaterial LLDAELoader::profileToMaterial(domProfile_COMMON* material, DAE* dae) +{ +	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(); +			if (newparams.getCount()) +			{ + +				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); +									} +								} +							} +						} +					} +				} +			} +			else if (texture->getTexture()) +			{ +				domImage* image = NULL; +				dae->getDatabase()->getElement((daeElement**) &image, 0, texture->getTexture(), COLLADA_TYPE_IMAGE); +				if (image) +				{ +					// we only support init_from now - embedded data will come later +					domImage::domInit_from* init = image->getInit_from(); +					if (init) +					{ +						std::string image_path_value = cdom::uriToNativePath(init->getValue().str()); + +#if LL_WINDOWS +						// Work-around DOM tendency to resort to UNC names which are only confusing for downstream... +						// +						std::string::iterator i = image_path_value.begin(); +						while (*i == '\\') +							i++; +						mat.mDiffuseMapFilename.assign(i, image_path_value.end()); +#else +						mat.mDiffuseMapFilename = image_path_value; +#endif +						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 LLDAELoader::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(); +	std::string index_string; +	if (parent) +	{ +		size_t ind = 0; +		parent->getChildren().find(element, ind); +		index_string = "_" + boost::lexical_cast<std::string>(ind); + +		// if parent has a name, use it +		std::string name = parent->getAttribute("name"); +		if (name.length()) +		{ +			return name + index_string; +		} + +		// if parent has an ID, use it +		if (parent->getID()) +		{ +			return std::string(parent->getID()) + index_string; +		} +	} + +	// try to use our type +	daeString element_name = element->getElementName(); +	if (element_name) +	{ +		return std::string(element_name) + index_string; +	} + +	// if all else fails, use "object" +	return std::string("object") + index_string; +} + +LLColor4 LLDAELoader::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; +} + +bool LLDAELoader::addVolumeFacesFromDomMesh(LLModel* pModel,domMesh* mesh) +{ +	LLModel::EModelStatus status = LLModel::NO_ERRORS; +	domTriangles_Array& tris = mesh->getTriangles_array(); + +	for (U32 i = 0; i < tris.getCount(); ++i) +	{ +		domTrianglesRef& tri = tris.get(i); + +		status = load_face_from_dom_triangles(pModel->getVolumeFaces(), pModel->getMaterialList(), tri); + +		if(status != LLModel::NO_ERRORS) +		{ +			pModel->ClearFacesAndMaterials(); +			return false; +		} +	} + +	domPolylist_Array& polys = mesh->getPolylist_array(); +	for (U32 i = 0; i < polys.getCount(); ++i) +	{ +		domPolylistRef& poly = polys.get(i); +		status = load_face_from_dom_polylist(pModel->getVolumeFaces(), pModel->getMaterialList(), poly); + +		if(status != LLModel::NO_ERRORS) +		{ +			pModel->ClearFacesAndMaterials(); +			return false; +		} +	} + +	domPolygons_Array& polygons = mesh->getPolygons_array(); + +	for (U32 i = 0; i < polygons.getCount(); ++i) +	{ +		domPolygonsRef& poly = polygons.get(i); +		status = load_face_from_dom_polygons(pModel->getVolumeFaces(), pModel->getMaterialList(), poly); + +		if(status != LLModel::NO_ERRORS) +		{ +			pModel->ClearFacesAndMaterials(); +			return false; +		} +	} + +	return (status == LLModel::NO_ERRORS); +} + +//static  +LLModel* LLDAELoader::loadModelFromDomMesh(domMesh *mesh) +{ +	LLVolumeParams volume_params; +	volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); +	LLModel* ret = new LLModel(volume_params, 0.f);  +	createVolumeFacesFromDomMesh(ret, mesh); +    if (ret->mLabel.empty()) +    { +	    ret->mLabel = getElementLabel(mesh); +    } +    return ret; +} + +//static diff version supports creating multiple models when material counts spill +// over the 8 face server-side limit +// +bool LLDAELoader::loadModelsFromDomMesh(domMesh* mesh, std::vector<LLModel*>& models_out) +{ + +	LLVolumeParams volume_params; +	volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); + +	models_out.clear(); + +	LLModel* ret = new LLModel(volume_params, 0.f);  + +    ret->mLabel = getElementLabel(mesh);     + +    llassert(!ret->mLabel.empty()); + +	// Like a monkey, ready to be shot into space +	// +	ret->ClearFacesAndMaterials(); + +	// Get the whole set of volume faces +	// +	addVolumeFacesFromDomMesh(ret, mesh); + +	U32 volume_faces = ret->getNumVolumeFaces(); + +	// Side-steps all manner of issues when splitting models +	// and matching lower LOD materials to base models +	// +	ret->sortVolumeFacesByMaterialName(); + +	bool normalized = false; + +    int submodelID = 0; +	LLVolume::face_list_t remainder; +	do  +	{ +		// Insure we do this once with the whole gang and not per-model +		// +		if (!normalized && !mNoNormalize) +		{			 +			normalized = true; +			ret->normalizeVolumeFaces(); +		} + +		ret->trimVolumeFacesToSize(LL_SCULPT_MESH_MAX_FACES, &remainder); + +		if (!mNoOptimize) +		{ +			ret->optimizeVolumeFaces(); +		} + +		volume_faces = remainder.size(); + +		models_out.push_back(ret); + +		// If we have left-over volume faces, create another model +		// to absorb them... +		// +		if (volume_faces) +		{ +			LLModel* next = new LLModel(volume_params, 0.f); +			next->mSubmodelID = ++submodelID; +			next->getVolumeFaces() = remainder; +			next->mNormalizedScale = ret->mNormalizedScale; +			next->mNormalizedTranslation = ret->mNormalizedTranslation; +			if ( ret->mMaterialList.size() > LL_SCULPT_MESH_MAX_FACES) +			{ +				next->mMaterialList.assign(ret->mMaterialList.begin() + LL_SCULPT_MESH_MAX_FACES, ret->mMaterialList.end()); +			} +			ret = next; +		} + +		remainder.clear(); + +	} while (volume_faces);	 + +	return true; +} + +bool LLDAELoader::createVolumeFacesFromDomMesh(LLModel* pModel, domMesh* mesh) +{ +	if (mesh) +	{ +		pModel->ClearFacesAndMaterials(); + +		addVolumeFacesFromDomMesh(pModel, mesh); + +		if (pModel->getNumVolumeFaces() > 0) +		{ +			pModel->normalizeVolumeFaces(); +			pModel->optimizeVolumeFaces(); + +			if (pModel->getNumVolumeFaces() > 0) +			{ +				return true; +			} +		} +	} +	else +	{	 +		LL_WARNS() << "no mesh found" << LL_ENDL; +	} + +	return false; +} diff --git a/indra/llprimitive/lldaeloader.h b/indra/llprimitive/lldaeloader.h new file mode 100644 index 0000000000..e71c407909 --- /dev/null +++ b/indra/llprimitive/lldaeloader.h @@ -0,0 +1,103 @@ +/** + * @file lldaeloader.h + * @brief LLDAELoader class definition + * + * $LicenseInfo:firstyear=2013&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2013, 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_LLDAELOADER_H +#define LL_LLDAELOADER_H + +#include "llmodelloader.h" + +class DAE; +class daeElement; +class domProfile_COMMON; +class domInstance_geometry; +class domNode; +class domTranslate; +class domController; +class domSkin; +class domMesh; + +class LLDAELoader : public LLModelLoader +{ +public: +	typedef std::map<std::string, LLImportMaterial>							material_map; +	typedef std::map<daeElement*, std::vector<LLPointer<LLModel> > >	dae_model_map; +	dae_model_map	mModelsMap; + +	LLDAELoader( +		std::string									filename, +		S32											lod,  +		LLModelLoader::load_callback_t		load_cb, +		LLModelLoader::joint_lookup_func_t	joint_lookup_func, +		LLModelLoader::texture_load_func_t	texture_load_func, +		LLModelLoader::state_callback_t		state_cb, +		void*											opaque_userdata, +		JointTransformMap&						jointMap, +		JointSet&									jointsFromNodes); +	virtual ~LLDAELoader() ; + +	virtual bool OpenFile(const std::string& filename); + +protected: + +	void processElement(daeElement* element, bool& badElement, DAE* dae); +	void processDomModel(LLModel* model, DAE* dae, daeElement* pRoot, domMesh* mesh, domSkin* skin); + +	material_map getMaterials(LLModel* model, domInstance_geometry* instance_geo, DAE* dae); +	LLImportMaterial profileToMaterial(domProfile_COMMON* material, DAE* dae);	 +	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 buildJointToNodeMappingFromScene( daeElement* pRoot ); +	void processJointToNodeMapping( domNode* pNode ); +	void processChildJoints( domNode* pParentNode ); + +	bool verifyCount( int expected, int result ); + +	//Verify that a controller matches vertex counts +	bool verifyController( domController* pController ); + +	static bool addVolumeFacesFromDomMesh(LLModel* model, domMesh* mesh); +	static bool createVolumeFacesFromDomMesh(LLModel* model, domMesh *mesh); + +	static LLModel* loadModelFromDomMesh(domMesh* mesh); + +	// Loads a mesh breaking it into one or more models as necessary +	// to get around volume face limitations while retaining >8 materials +	// +	bool loadModelsFromDomMesh(domMesh* mesh, std::vector<LLModel*>& models_out); + +	static std::string getElementLabel(daeElement *element);	 + +private: + +}; +#endif  // LL_LLDAELLOADER_H diff --git a/indra/llprimitive/llmodel.cpp b/indra/llprimitive/llmodel.cpp index aa8dd7697c..d82075f9a4 100755 --- a/indra/llprimitive/llmodel.cpp +++ b/indra/llprimitive/llmodel.cpp @@ -31,18 +31,6 @@  #include "llconvexdecomposition.h"  #include "llsdserialize.h"  #include "llvector4a.h" -#if LL_MSVC -#pragma warning (disable : 4263) -#pragma warning (disable : 4264) -#endif -#include "dae.h" -#include "dae/daeErrorHandler.h" -#include "dom/domConstants.h" -#include "dom/domMesh.h" -#if LL_MSVC -#pragma warning (default : 4263) -#pragma warning (default : 4264) -#endif  #ifdef LL_USESYSTEMLIBS  # include <zlib.h> @@ -50,8 +38,6 @@  # include "zlib/zlib.h"  #endif - -  std::string model_names[] =  {  	"lowest_lod", @@ -65,7 +51,7 @@ const int MODEL_NAMES_LENGTH = sizeof(model_names) / sizeof(std::string);  LLModel::LLModel(LLVolumeParams& params, F32 detail)  	: LLVolume(params, detail), mNormalizedScale(1,1,1), mNormalizedTranslation(0,0,0) -	, mPelvisOffset( 0.0f ), mStatus(NO_ERRORS) +	, mPelvisOffset( 0.0f ), mStatus(NO_ERRORS), mSubmodelID(0)  {  	mDecompID = -1;  	mLocalID = -1; @@ -79,923 +65,112 @@ LLModel::~LLModel()  	}  } - -bool get_dom_sources(const domInputLocalOffset_Array& inputs, S32& pos_offset, S32& tc_offset, S32& norm_offset, S32 &idx_stride, -					 domSource* &pos_source, domSource* &tc_source, domSource* &norm_source) +//static +std::string LLModel::getStatusString(U32 status)  { -	idx_stride = 0; +	const static std::string status_strings[(S32)INVALID_STATUS] = {"status_no_error", "status_vertex_number_overflow","bad_element"}; -	for (U32 j = 0; j < inputs.getCount(); ++j) +	if(status < INVALID_STATUS)  	{ -		idx_stride = llmax((S32) inputs[j]->getOffset(), idx_stride); - -		if (strcmp(COMMON_PROFILE_INPUT_VERTEX, inputs[j]->getSemantic()) == 0) -		{ //found vertex array -			const domURIFragmentType& uri = inputs[j]->getSource(); -			daeElementRef elem = uri.getElement(); -			domVertices* vertices = (domVertices*) elem.cast(); -			if ( !vertices ) -			{ -				return false; -			} -				 -			domInputLocal_Array& v_inp = vertices->getInput_array(); -			 -			 -			for (U32 k = 0; k < v_inp.getCount(); ++k) -			{ -				if (strcmp(COMMON_PROFILE_INPUT_POSITION, v_inp[k]->getSemantic()) == 0) -				{ -					pos_offset = inputs[j]->getOffset(); - -					const domURIFragmentType& uri = v_inp[k]->getSource(); -					daeElementRef elem = uri.getElement(); -					pos_source = (domSource*) elem.cast(); -				} -				 -				if (strcmp(COMMON_PROFILE_INPUT_NORMAL, v_inp[k]->getSemantic()) == 0) -				{ -					norm_offset = inputs[j]->getOffset(); - -					const domURIFragmentType& uri = v_inp[k]->getSource(); -					daeElementRef elem = uri.getElement(); -					norm_source = (domSource*) elem.cast(); -				} -			} -		} - -		if (strcmp(COMMON_PROFILE_INPUT_NORMAL, inputs[j]->getSemantic()) == 0) +		if(status_strings[status] == std::string())  		{ -			//found normal array for this triangle list -			norm_offset = inputs[j]->getOffset(); -			const domURIFragmentType& uri = inputs[j]->getSource(); -			daeElementRef elem = uri.getElement(); -			norm_source = (domSource*) elem.cast(); +			//LL_ERRS() << "No valid status string for this status: " << (U32)status << LL_ENDL();  		} -		else if (strcmp(COMMON_PROFILE_INPUT_TEXCOORD, inputs[j]->getSemantic()) == 0) -		{ //found texCoords -			tc_offset = inputs[j]->getOffset(); -			const domURIFragmentType& uri = inputs[j]->getSource(); -			daeElementRef elem = uri.getElement(); -			tc_source = (domSource*) elem.cast(); -		} -	} - -	idx_stride += 1; -	 -	return true; -} - -LLModel::EModelStatus load_face_from_dom_triangles(std::vector<LLVolumeFace>& face_list, std::vector<std::string>& materials, domTrianglesRef& tri) -{ -	LLVolumeFace face; -	std::vector<LLVolumeFace::VertexData> verts; -	std::vector<U16> indices; -	 -	const domInputLocalOffset_Array& inputs = tri->getInput_array(); - -	S32 pos_offset = -1; -	S32 tc_offset = -1; -	S32 norm_offset = -1; - -	domSource* pos_source = NULL; -	domSource* tc_source = NULL; -	domSource* norm_source = NULL; - -	S32 idx_stride = 0; - -	if ( !get_dom_sources(inputs, pos_offset, tc_offset, norm_offset, idx_stride, pos_source, tc_source, norm_source) || !pos_source ) -	{ -		LL_WARNS() << "Could not find dom sources for basic geo data; invalid model." << LL_ENDL; -		return LLModel::BAD_ELEMENT; +		return status_strings[status] ;  	} -	if (!pos_source) -	{ -		LL_WARNS() << "Unable to process mesh without position data; invalid model;  invalid model." << LL_ENDL; -		return LLModel::BAD_ELEMENT; -	} -	 -	domPRef p = tri->getP(); -	domListOfUInts& idx = p->getValue(); -	 -	domListOfFloats  dummy ; -	domListOfFloats& v = (pos_source && pos_source->getFloat_array()) ? pos_source->getFloat_array()->getValue() : dummy ; -	domListOfFloats& tc = (tc_source && tc_source->getFloat_array()) ? tc_source->getFloat_array()->getValue() : dummy ; -	domListOfFloats& n = (norm_source && norm_source->getFloat_array()) ? norm_source->getFloat_array()->getValue() : dummy ; +	//LL_ERRS() << "Invalid model status: " << (U32)status << LL_ENDL(); -	LLVolumeFace::VertexMapData::PointMap point_map; -		 -	U32 index_count  = idx.getCount(); -	U32 vertex_count = (pos_source &&  pos_source->getFloat_array())	? v.getCount()	: 0; -	U32 tc_count     = (tc_source && tc_source->getFloat_array()) 		? tc.getCount()	: 0; -	U32 norm_count   = (norm_source && norm_source->getFloat_array()) 	? n.getCount(): 0; +	return std::string() ; +} -	if ((vertex_count == 0)) -	{ -		LL_WARNS() << "Unable to process mesh with empty position array; invalid model." << LL_ENDL; -		return LLModel::BAD_ELEMENT; -	} -	face.mExtents[0].set(v[0], v[1], v[2]); -	face.mExtents[1].set(v[0], v[1], v[2]); +void LLModel::offsetMesh( const LLVector3& pivotPoint ) +{ +	LLVector4a pivot( pivotPoint[VX], pivotPoint[VY], pivotPoint[VZ] ); -	for (U32 i = 0; i < index_count; i += idx_stride) -	{ -		LLVolumeFace::VertexData cv; -		if (pos_source) -		{ -			// guard against model data specifiying out of range indices or verts -			// -			if (((i + pos_offset) > index_count) -			 || ((idx[i+pos_offset]*3+2) > vertex_count)) -			{ -				LL_WARNS() << "Out of range index data; invalid model." << LL_ENDL; -				return LLModel::BAD_ELEMENT; -			} - -			cv.setPosition(LLVector4a(v[idx[i+pos_offset]*3+0], -								v[idx[i+pos_offset]*3+1], -								v[idx[i+pos_offset]*3+2])); - -			if (!cv.getPosition().isFinite3()) -			{ -				LL_WARNS() << "Nan positional data, invalid model." << LL_ENDL; -				return LLModel::BAD_ELEMENT; -			} -		} - -		if (tc_source) -		{ -			// guard against model data specifiying out of range indices or tcs -			// - -			if (((i + tc_offset) > index_count) -			 || ((idx[i+tc_offset]*2+1) > tc_count)) -			{ -				LL_WARNS() << "Out of range TC indices." << LL_ENDL; -				return LLModel::BAD_ELEMENT; -			} - -			cv.mTexCoord.setVec(tc[idx[i+tc_offset]*2+0], -								tc[idx[i+tc_offset]*2+1]); - -			if (!cv.mTexCoord.isFinite()) -			{ -				LL_WARNS() << "Found NaN while loading tex coords from DAE-Model, invalid model." << LL_ENDL; -				return LLModel::BAD_ELEMENT; -			} -		} -		 -		if (norm_source) -		{ -			// guard against model data specifiying out of range indices or norms -			// -			if (((i + norm_offset) > index_count) -				|| ((idx[i+norm_offset]*3+2) > norm_count)) -			{ -				LL_WARNS() << "Found out of range norm indices, invalid model." << LL_ENDL; -				return LLModel::BAD_ELEMENT; -			} - -			cv.setNormal(LLVector4a(n[idx[i+norm_offset]*3+0], -								n[idx[i+norm_offset]*3+1], -								n[idx[i+norm_offset]*3+2])); - -			if (!cv.getNormal().isFinite3()) -			{ -				LL_WARNS() << "Found NaN while loading normals from DAE-Model, invalid model." << LL_ENDL; -				return LLModel::BAD_ELEMENT; -			} -		} -		 -		BOOL found = FALSE; -			 -		LLVolumeFace::VertexMapData::PointMap::iterator point_iter; -		point_iter = point_map.find(LLVector3(cv.getPosition().getF32ptr())); -		 -		if (point_iter != point_map.end()) -		{ -			for (U32 j = 0; j < point_iter->second.size(); ++j) -			{ -				if ((point_iter->second)[j] == cv) -				{ -					found = TRUE; -					indices.push_back((point_iter->second)[j].mIndex); -					break; -				} -			} -		} - -		if (!found) -		{ -			update_min_max(face.mExtents[0], face.mExtents[1], cv.getPosition()); -			verts.push_back(cv); -			if (verts.size() >= 65535) -			{ -				//LL_ERRS() << "Attempted to write model exceeding 16-bit index buffer limitation." << LL_ENDL; -				return LLModel::VERTEX_NUMBER_OVERFLOW ; -			} -			U16 index = (U16) (verts.size()-1); -			indices.push_back(index); - -			LLVolumeFace::VertexMapData d; -			d.setPosition(cv.getPosition()); -			d.mTexCoord = cv.mTexCoord; -			d.setNormal(cv.getNormal()); -			d.mIndex = index; -			if (point_iter != point_map.end()) -			{ -				point_iter->second.push_back(d); -			} -			else -			{ -				point_map[LLVector3(d.getPosition().getF32ptr())].push_back(d); -			} -		} - -		if (indices.size()%3 == 0 && verts.size() >= 65532) -		{ -			face_list.push_back(face); -			face_list.rbegin()->fillFromLegacyData(verts, indices); -			LLVolumeFace& new_face = *face_list.rbegin(); -			if (!norm_source) -			{ -				//ll_aligned_free_16(new_face.mNormals); -				new_face.mNormals = NULL; -			} - -			if (!tc_source) -			{ -				//ll_aligned_free_16(new_face.mTexCoords); -				new_face.mTexCoords = NULL; -			} - -			face = LLVolumeFace(); -			point_map.clear(); -		} -	} - -	if (!verts.empty()) +	for (std::vector<LLVolumeFace>::iterator faceIt = mVolumeFaces.begin(); faceIt != mVolumeFaces.end(); )  	{ -		std::string material; - -		if (tri->getMaterial()) -		{ -			material = std::string(tri->getMaterial()); -		} +		std::vector<LLVolumeFace>:: iterator currentFaceIt = faceIt++; +		LLVolumeFace& face = *currentFaceIt; +		LLVector4a *pos = (LLVector4a*) face.mPositions; -		materials.push_back(material); -		face_list.push_back(face); - -		face_list.rbegin()->fillFromLegacyData(verts, indices); -		LLVolumeFace& new_face = *face_list.rbegin(); -		if (!norm_source) -		{ -			//ll_aligned_free_16(new_face.mNormals); -			new_face.mNormals = NULL; -		} - -		if (!tc_source) +		for (U32 i=0; i<face.mNumVertices; ++i )  		{ -			//ll_aligned_free_16(new_face.mTexCoords); -			new_face.mTexCoords = NULL; +			pos[i].add( pivot );  		}  	} - -	return LLModel::NO_ERRORS ;  } -LLModel::EModelStatus load_face_from_dom_polylist(std::vector<LLVolumeFace>& face_list, std::vector<std::string>& materials, domPolylistRef& poly) +void LLModel::optimizeVolumeFaces()  { -	domPRef p = poly->getP(); -	domListOfUInts& idx = p->getValue(); - -	if (idx.getCount() == 0) -	{ -		return LLModel::NO_ERRORS ; -	} - -	const domInputLocalOffset_Array& inputs = poly->getInput_array(); - - -	domListOfUInts& vcount = poly->getVcount()->getValue(); -	 -	S32 pos_offset = -1; -	S32 tc_offset = -1; -	S32 norm_offset = -1; - -	domSource* pos_source = NULL; -	domSource* tc_source = NULL; -	domSource* norm_source = NULL; - -	S32 idx_stride = 0; - -	if (!get_dom_sources(inputs, pos_offset, tc_offset, norm_offset, idx_stride, pos_source, tc_source, norm_source)) -	{ -		LL_WARNS() << "Could not get DOM sources for basic geo data, invalid model." << LL_ENDL; -		return LLModel::BAD_ELEMENT; -	} - -	LLVolumeFace face; - -	std::vector<U16> indices; -	std::vector<LLVolumeFace::VertexData> verts; - -	domListOfFloats v; -	domListOfFloats tc; -	domListOfFloats n; - -	if (pos_source) -	{ -		v = pos_source->getFloat_array()->getValue(); -		face.mExtents[0].set(v[0], v[1], v[2]); -		face.mExtents[1].set(v[0], v[1], v[2]); -	} - -	if (tc_source) -	{ -		tc = tc_source->getFloat_array()->getValue(); -	} - -	if (norm_source) -	{ -		n = norm_source->getFloat_array()->getValue(); -	} -	 -	LLVolumeFace::VertexMapData::PointMap point_map; - -	U32 index_count  = idx.getCount(); -	U32 vertex_count = pos_source  ? v.getCount()  : 0; -	U32 tc_count     = tc_source   ? tc.getCount() : 0; -	U32 norm_count   = norm_source ? n.getCount()  : 0; - -	U32 cur_idx = 0; -	for (U32 i = 0; i < vcount.getCount(); ++i) -	{ //for each polygon -		U32 first_index = 0; -		U32 last_index = 0; -		for (U32 j = 0; j < vcount[i]; ++j) -		{ //for each vertex - -			LLVolumeFace::VertexData cv; - -			if (pos_source) -			{ -				// guard against model data specifiying out of range indices or verts -				// -				if (((cur_idx + pos_offset) > index_count) -				 || ((idx[cur_idx+pos_offset]*3+2) > vertex_count)) -				{ -					LL_WARNS() << "Out of range position indices, invalid model." << LL_ENDL; -					return LLModel::BAD_ELEMENT; -				} - -				cv.getPosition().set(v[idx[cur_idx+pos_offset]*3+0], -									v[idx[cur_idx+pos_offset]*3+1], -									v[idx[cur_idx+pos_offset]*3+2]); - -				if (!cv.getPosition().isFinite3()) -				{ -					LL_WARNS() << "Found NaN while loading positions from DAE-Model, invalid model." << LL_ENDL; -					return LLModel::BAD_ELEMENT; -				} - -			} - -			if (tc_source) -			{ -				// guard against model data specifiying out of range indices or tcs -				// -				if (((cur_idx + tc_offset) > index_count) -				 || ((idx[cur_idx+tc_offset]*2+1) > tc_count)) -				{ -					LL_WARNS() << "Out of range TC indices, invalid model." << LL_ENDL; -					return LLModel::BAD_ELEMENT; -				} - -				cv.mTexCoord.setVec(tc[idx[cur_idx+tc_offset]*2+0], -									tc[idx[cur_idx+tc_offset]*2+1]); - -				if (!cv.mTexCoord.isFinite()) -				{ -					LL_WARNS() << "Found NaN while loading tex coords from DAE-Model, invalid model." << LL_ENDL; -					return LLModel::BAD_ELEMENT; -				} -			} -			 -			if (norm_source) -			{ -				// guard against model data specifiying out of range indices or norms -				// -				if (((cur_idx + norm_offset) > index_count) -				 || ((idx[cur_idx+norm_offset]*3+2) > norm_count)) -				{ -					LL_WARNS() << "Out of range norm indices, invalid model." << LL_ENDL; -					return LLModel::BAD_ELEMENT; -				} - -				cv.getNormal().set(n[idx[cur_idx+norm_offset]*3+0], -									n[idx[cur_idx+norm_offset]*3+1], -									n[idx[cur_idx+norm_offset]*3+2]); - -				if (!cv.getNormal().isFinite3()) -				{ -					LL_WARNS() << "Found NaN while loading normals from DAE-Model, invalid model." << LL_ENDL; -					return LLModel::BAD_ELEMENT; -				} -			} -			 -			cur_idx += idx_stride; -			 -			BOOL found = FALSE; -				 -			LLVolumeFace::VertexMapData::PointMap::iterator point_iter; -			LLVector3 pos3(cv.getPosition().getF32ptr()); -			point_iter = point_map.find(pos3); -			 -			if (point_iter != point_map.end()) -			{ -				for (U32 k = 0; k < point_iter->second.size(); ++k) -				{ -					if ((point_iter->second)[k] == cv) -					{ -						found = TRUE; -						U32 index = (point_iter->second)[k].mIndex; -						if (j == 0) -						{ -							first_index = index; -						} -						else if (j == 1) -						{ -							last_index = index; -						} -						else -						{ -							indices.push_back(first_index); -							indices.push_back(last_index); -							indices.push_back(index); -							last_index = index; -						} - -						break; -					} -				} -			} - -			if (!found) -			{ -				update_min_max(face.mExtents[0], face.mExtents[1], cv.getPosition()); -				verts.push_back(cv); -				if (verts.size() >= 65535) -				{ -					//LL_ERRS() << "Attempted to write model exceeding 16-bit index buffer limitation." << LL_ENDL; -					return LLModel::VERTEX_NUMBER_OVERFLOW ; -				} -				U16 index = (U16) (verts.size()-1); -			 -				if (j == 0) -				{ -					first_index = index; -				} -				else if (j == 1) -				{ -					last_index = index; -				} -				else -				{ -					indices.push_back(first_index); -					indices.push_back(last_index); -					indices.push_back(index); -					last_index = index; -				}	 - -				LLVolumeFace::VertexMapData d; -				d.setPosition(cv.getPosition()); -				d.mTexCoord = cv.mTexCoord; -				d.setNormal(cv.getNormal()); -				d.mIndex = index; -				if (point_iter != point_map.end()) -				{ -					point_iter->second.push_back(d); -				} -				else -				{ -					point_map[pos3].push_back(d); -				} -			} - -			if (indices.size()%3 == 0 && indices.size() >= 65532) -			{ -				face_list.push_back(face); -				face_list.rbegin()->fillFromLegacyData(verts, indices); -				LLVolumeFace& new_face = *face_list.rbegin(); -				if (!norm_source) -				{ -					//ll_aligned_free_16(new_face.mNormals); -					new_face.mNormals = NULL; -				} - -				if (!tc_source) -				{ -					//ll_aligned_free_16(new_face.mTexCoords); -					new_face.mTexCoords = NULL; -				} - -				face = LLVolumeFace(); -				verts.clear(); -				indices.clear(); -				point_map.clear(); -			} -		} -	} - -	if (!verts.empty()) +	for (U32 i = 0; i < getNumVolumeFaces(); ++i)  	{ -		std::string material; - -		if (poly->getMaterial()) -		{ -			material = std::string(poly->getMaterial()); -		} -	 -		materials.push_back(material); -		face_list.push_back(face); -		face_list.rbegin()->fillFromLegacyData(verts, indices); - -		LLVolumeFace& new_face = *face_list.rbegin(); -		if (!norm_source) -		{ -			//ll_aligned_free_16(new_face.mNormals); -			new_face.mNormals = NULL; -		} - -		if (!tc_source) -		{ -			//ll_aligned_free_16(new_face.mTexCoords); -			new_face.mTexCoords = NULL; -		} +		mVolumeFaces[i].optimize();  	} - -	return LLModel::NO_ERRORS ;  } -LLModel::EModelStatus load_face_from_dom_polygons(std::vector<LLVolumeFace>& face_list, std::vector<std::string>& materials, domPolygonsRef& poly) +struct MaterialBinding  { -	LLVolumeFace face; -	std::vector<U16> indices; -	std::vector<LLVolumeFace::VertexData> verts; - -	const domInputLocalOffset_Array& inputs = poly->getInput_array(); - -	S32 v_offset = -1; -	S32 n_offset = -1; -	S32 t_offset = -1; - -	domListOfFloats* v = NULL; -	domListOfFloats* n = NULL; -	domListOfFloats* t = NULL; -	 -	U32 stride = 0; -	for (U32 i = 0; i < inputs.getCount(); ++i) -	{ -		stride = llmax((U32) inputs[i]->getOffset()+1, stride); - -		if (strcmp(COMMON_PROFILE_INPUT_VERTEX, inputs[i]->getSemantic()) == 0) -		{ //found vertex array -			v_offset = inputs[i]->getOffset(); - -			const domURIFragmentType& uri = inputs[i]->getSource(); -			daeElementRef elem = uri.getElement(); -			domVertices* vertices = (domVertices*) elem.cast(); -			if (!vertices) -			{ -				LL_WARNS() << "Could not find vertex source, invalid model." << LL_ENDL; -				return LLModel::BAD_ELEMENT; -			} -			domInputLocal_Array& v_inp = vertices->getInput_array(); - -			for (U32 k = 0; k < v_inp.getCount(); ++k) -			{ -				if (strcmp(COMMON_PROFILE_INPUT_POSITION, v_inp[k]->getSemantic()) == 0) -				{ -					const domURIFragmentType& uri = v_inp[k]->getSource(); -					daeElementRef elem = uri.getElement(); -					domSource* src = (domSource*) elem.cast(); -					if (!src) -					{ -						LL_WARNS() << "Could not find DOM source, invalid model." << LL_ENDL; -						return LLModel::BAD_ELEMENT; -					} -					v = &(src->getFloat_array()->getValue()); -				} -			} -		} -		else if (strcmp(COMMON_PROFILE_INPUT_NORMAL, inputs[i]->getSemantic()) == 0) -		{ -			n_offset = inputs[i]->getOffset(); -			//found normal array for this triangle list -			const domURIFragmentType& uri = inputs[i]->getSource(); -			daeElementRef elem = uri.getElement(); -			domSource* src = (domSource*) elem.cast(); -			if (!src) -			{ -				LL_WARNS() << "Could not find DOM source, invalid model." << LL_ENDL; -				return LLModel::BAD_ELEMENT; -			} -			n = &(src->getFloat_array()->getValue()); -		} -		else if (strcmp(COMMON_PROFILE_INPUT_TEXCOORD, inputs[i]->getSemantic()) == 0 && inputs[i]->getSet() == 0) -		{ //found texCoords -			t_offset = inputs[i]->getOffset(); -			const domURIFragmentType& uri = inputs[i]->getSource(); -			daeElementRef elem = uri.getElement(); -			domSource* src = (domSource*) elem.cast(); -			if (!src) -			{ -				LL_WARNS() << "Could not find DOM source, invalid model." << LL_ENDL; -				return LLModel::BAD_ELEMENT; -			} -			t = &(src->getFloat_array()->getValue()); -		} -	} - -	domP_Array& ps = poly->getP_array(); - -	//make a triangle list in <verts> -	for (U32 i = 0; i < ps.getCount(); ++i) -	{ //for each polygon -		domListOfUInts& idx = ps[i]->getValue(); -		for (U32 j = 0; j < idx.getCount()/stride; ++j) -		{ //for each vertex -			if (j > 2) -			{ -				U32 size = verts.size(); -				LLVolumeFace::VertexData v0 = verts[size-3]; -				LLVolumeFace::VertexData v1 = verts[size-1]; - -				verts.push_back(v0); -				verts.push_back(v1); -			} - -			LLVolumeFace::VertexData vert; - - -			if (v) -			{ -				U32 v_idx = idx[j*stride+v_offset]*3; -				v_idx = llclamp(v_idx, (U32) 0, (U32) v->getCount()); -				vert.getPosition().set(v->get(v_idx), -								v->get(v_idx+1), -								v->get(v_idx+2)); - -				if (!vert.getPosition().isFinite3()) -				{ -					LL_WARNS() << "Found NaN while loading position data from DAE-Model, invalid model." << LL_ENDL; -					return LLModel::BAD_ELEMENT; -				} -			} -			 -			//bounds check n and t lookups because some FBX to DAE converters -			//use negative indices and empty arrays to indicate data does not exist -			//for a particular channel -			if (n && n->getCount() > 0) -			{ -				U32 n_idx = idx[j*stride+n_offset]*3; -				n_idx = llclamp(n_idx, (U32) 0, (U32) n->getCount()); -				vert.getNormal().set(n->get(n_idx), -								n->get(n_idx+1), -								n->get(n_idx+2)); - -				if (!vert.getNormal().isFinite3()) -				{ -					LL_WARNS() << "Found NaN while loading normals from DAE-Model, invalid model." << LL_ENDL; -					return LLModel::BAD_ELEMENT; -				} -			} -			else -			{ -				vert.getNormal().clear(); -			} - -			 -			if (t && t->getCount() > 0) -			{ -				U32 t_idx = idx[j*stride+t_offset]*2; -				t_idx = llclamp(t_idx, (U32) 0, (U32) t->getCount()); -				vert.mTexCoord.setVec(t->get(t_idx), -								t->get(t_idx+1));								 - -				if (!vert.mTexCoord.isFinite()) -				{ -					LL_WARNS() << "Found NaN while loading tex coords from DAE-Model, invalid model." << LL_ENDL; -					return LLModel::BAD_ELEMENT; -				} -			} -			else -			{ -				vert.mTexCoord.clear(); -			} - -						 -			verts.push_back(vert); -		} -	} - -	if (verts.empty()) -	{ -		return LLModel::NO_ERRORS; -	} - -	face.mExtents[0] = verts[0].getPosition(); -	face.mExtents[1] = verts[0].getPosition(); -	 -	//create a map of unique vertices to indices -	std::map<LLVolumeFace::VertexData, U32> vert_idx; - -	U32 cur_idx = 0; -	for (U32 i = 0; i < verts.size(); ++i) -	{ -		std::map<LLVolumeFace::VertexData, U32>::iterator iter = vert_idx.find(verts[i]); -		if (iter == vert_idx.end()) -		{ -			vert_idx[verts[i]] = cur_idx++; -		} -	} - -	//build vertex array from map -	std::vector<LLVolumeFace::VertexData> new_verts; -	new_verts.resize(vert_idx.size()); - -	for (std::map<LLVolumeFace::VertexData, U32>::iterator iter = vert_idx.begin(); iter != vert_idx.end(); ++iter) -	{ -		new_verts[iter->second] = iter->first; -		update_min_max(face.mExtents[0], face.mExtents[1], iter->first.getPosition()); -	} - -	//build index array from map -	indices.resize(verts.size()); - -	for (U32 i = 0; i < verts.size(); ++i) -	{ -		indices[i] = vert_idx[verts[i]]; -	} - -	// DEBUG just build an expanded triangle list -	/*for (U32 i = 0; i < verts.size(); ++i) -	{ -		indices.push_back((U16) i); -		update_min_max(face.mExtents[0], face.mExtents[1], verts[i].getPosition()); -	}*/ - -    if (!new_verts.empty()) -	{ -		std::string material; - -		if (poly->getMaterial()) -		{ -			material = std::string(poly->getMaterial()); -		} - -		materials.push_back(material); -		face_list.push_back(face); -		face_list.rbegin()->fillFromLegacyData(new_verts, indices); - -		LLVolumeFace& new_face = *face_list.rbegin(); -		if (!n) -		{ -			//ll_aligned_free_16(new_face.mNormals); -			new_face.mNormals = NULL; -		} - -		if (!t) -		{ -			//ll_aligned_free_16(new_face.mTexCoords); -			new_face.mTexCoords = NULL; -		} -	} - -	return LLModel::NO_ERRORS ; -} +	int				index; +	std::string		matName; +}; -//static -std::string LLModel::getStatusString(U32 status) +struct MaterialSort  { -	const static std::string status_strings[(S32)INVALID_STATUS] = {"status_no_error", "status_vertex_number_overflow","bad_element"}; - -	if(status < INVALID_STATUS) +	bool operator()(const MaterialBinding& lhs, const MaterialBinding& rhs)  	{ -		if(status_strings[status] == std::string()) -		{ -			LL_ERRS() << "No valid status string for this status: " << (U32)status << LL_ENDL ; -		} -		return status_strings[status] ; +		return LLStringUtil::compareInsensitive(lhs.matName, rhs.matName) < 0;  	} +}; -	LL_ERRS() << "Invalid model status: " << (U32)status << LL_ENDL ; - -	return std::string() ; -} - -void LLModel::addVolumeFacesFromDomMesh(domMesh* mesh) +void LLModel::sortVolumeFacesByMaterialName()  { -	domTriangles_Array& tris = mesh->getTriangles_array(); -		 -	for (U32 i = 0; i < tris.getCount(); ++i) -	{ -		domTrianglesRef& tri = tris.get(i); +	std::vector<MaterialBinding> bindings; +	bindings.resize(mVolumeFaces.size()); -		mStatus = load_face_from_dom_triangles(mVolumeFaces, mMaterialList, tri); -		 -		if(mStatus != NO_ERRORS) +	for (int i = 0; i < bindings.size(); i++) +	{ +		bindings[i].index = i; +		if(i < mMaterialList.size())  		{ -			mVolumeFaces.clear() ; -			mMaterialList.clear() ; -			return ; //abort +			bindings[i].matName = mMaterialList[i];  		}  	} +	std::sort(bindings.begin(), bindings.end(), MaterialSort()); +	std::vector< LLVolumeFace > new_faces; -	domPolylist_Array& polys = mesh->getPolylist_array(); -	for (U32 i = 0; i < polys.getCount(); ++i) +	// remap the faces to be in the same order the mats now are... +	// +	new_faces.resize(bindings.size()); +	for (int i = 0; i < bindings.size(); i++)  	{ -		domPolylistRef& poly = polys.get(i); -		mStatus = load_face_from_dom_polylist(mVolumeFaces, mMaterialList, poly); - -		if(mStatus != NO_ERRORS) +		new_faces[i] = mVolumeFaces[bindings[i].index]; +		if(i < mMaterialList.size())  		{ -			mVolumeFaces.clear() ; -			mMaterialList.clear() ; -			return ; //abort +			mMaterialList[i] = bindings[i].matName;  		}  	} -	 -	domPolygons_Array& polygons = mesh->getPolygons_array(); -	 -	for (U32 i = 0; i < polygons.getCount(); ++i) -	{ -		domPolygonsRef& poly = polygons.get(i); -		mStatus = load_face_from_dom_polygons(mVolumeFaces, mMaterialList, poly); -		if(mStatus != NO_ERRORS) -		{ -			mVolumeFaces.clear() ; -			mMaterialList.clear() ; -			return ; //abort -		} -	} -  +	mVolumeFaces = new_faces;	  } -BOOL LLModel::createVolumeFacesFromDomMesh(domMesh* mesh) +void LLModel::trimVolumeFacesToSize(U32 new_count, LLVolume::face_list_t* remainder)  { -	if (mesh) -	{ -		mVolumeFaces.clear(); -		mMaterialList.clear(); +	llassert(new_count <= LL_SCULPT_MESH_MAX_FACES); -		addVolumeFacesFromDomMesh(mesh); -		 -		if (getNumVolumeFaces() > 0) -		{ -			normalizeVolumeFaces(); -			optimizeVolumeFaces(); -			 -			if (getNumVolumeFaces() > 0) -			{ -				return TRUE; -			} -		} -	} -	else -	{	 -		LL_WARNS() << "no mesh found" << LL_ENDL; -	} -	 -	return FALSE; -} - -void LLModel::offsetMesh( const LLVector3& pivotPoint ) -{ -	LLVector4a pivot( pivotPoint[VX], pivotPoint[VY], pivotPoint[VZ] ); -	 -	for (std::vector<LLVolumeFace>::iterator faceIt = mVolumeFaces.begin(); faceIt != mVolumeFaces.end(); ) +	if (new_count && (getNumVolumeFaces() > new_count))  	{ -		std::vector<LLVolumeFace>:: iterator currentFaceIt = faceIt++; -		LLVolumeFace& face = *currentFaceIt; -		LLVector4a *pos = (LLVector4a*) face.mPositions; -		 -		for (U32 i=0; i<face.mNumVertices; ++i ) +		// Copy out remaining volume faces for alternative handling, if provided +		// +		if (remainder)  		{ -			pos[i].add( pivot ); -		} -	} -} +			(*remainder).assign(mVolumeFaces.begin() + new_count, mVolumeFaces.end()); +		}		 -void LLModel::optimizeVolumeFaces() -{ -	for (U32 i = 0; i < getNumVolumeFaces(); ++i) -	{ -		mVolumeFaces[i].optimize(); +		// Trim down to the final set of volume faces (now stuffed to the gills!) +		// +		mVolumeFaces.resize(new_count);  	}  } @@ -1009,11 +184,6 @@ void LLModel::optimizeVolumeFaces()  // within the unit cube.  void LLModel::normalizeVolumeFaces()  { - -	// ensure we don't have too many faces -	if (mVolumeFaces.size() > LL_SCULPT_MESH_MAX_FACES) -		mVolumeFaces.resize(LL_SCULPT_MESH_MAX_FACES); -	  	if (!mVolumeFaces.empty())  	{  		LLVector4a min, max; @@ -1480,68 +650,10 @@ void LLModel::generateNormals(F32 angle_cutoff)  	}  } -//static -std::string LLModel::getElementLabel(daeElement *element) -{ // try to get a decent label for this 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"); -} - -//static  -LLModel* LLModel::loadModelFromDomMesh(domMesh *mesh) -{ -	LLVolumeParams volume_params; -	volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); -	LLModel* ret = new LLModel(volume_params, 0.f);  -	ret->createVolumeFacesFromDomMesh(mesh); -	ret->mLabel = getElementLabel(mesh); -	return ret; -}  std::string LLModel::getName() const  { -	if (!mRequestedLabel.empty()) -		return mRequestedLabel; -	else -		return mLabel; +    return mRequestedLabel.empty() ? mLabel : mRequestedLabel;  }  //static @@ -1556,7 +668,8 @@ LLSD LLModel::writeModel(  	BOOL upload_skin,  	BOOL upload_joints,  	BOOL nowrite, -	BOOL as_slm) +	BOOL as_slm, +	int submodel_id)  {  	LLSD mdl; @@ -1585,6 +698,14 @@ LLSD LLModel::writeModel(  			model[LLModel::LOD_PHYSICS] = NULL;  		}  	} +	else if (submodel_id) +	{ +		const LLModel::Decomposition fake_decomp; +		mdl["secondary"] = true; +        mdl["submodel_id"] = submodel_id; +		mdl["physics_convex"] = fake_decomp.asLLSD(); +		model[LLModel::LOD_PHYSICS] = NULL; +	}  	if (as_slm)  	{ //save material list names @@ -1596,7 +717,7 @@ LLSD LLModel::writeModel(  	for (U32 idx = 0; idx < MODEL_NAMES_LENGTH; ++idx)  	{ -		if (model[idx] && model[idx]->getNumVolumeFaces() > 0) +		if (model[idx] && (model[idx]->getNumVolumeFaces() > 0) && model[idx]->getVolumeFace(0).mPositions != NULL)  		{  			LLVector3 min_pos = LLVector3(model[idx]->getVolumeFace(0).mPositions[0].getF32ptr());  			LLVector3 max_pos = min_pos; @@ -1829,6 +950,11 @@ LLSD LLModel::writeModelToStream(std::ostream& ostr, LLSD& mdl, BOOL nowrite, BO  		}  	} +        if (mdl.has("submodel_id")) +        { //write out submodel id +        header["submodel_id"] = (LLSD::Integer)mdl["submodel_id"]; +        } +  	std::string out[MODEL_NAMES_LENGTH];  	for (S32 i = 0; i < MODEL_NAMES_LENGTH; i++) @@ -2012,7 +1138,9 @@ bool LLModel::loadModel(std::istream& is)  		}  	} -	std::string nm[] =  +	mSubmodelID = header.has("submodel_id") ? header["submodel_id"].asInteger() : false; + +	std::string lod_name[] =   	{  		"lowest_lod",  		"low_lod", @@ -2025,8 +1153,8 @@ bool LLModel::loadModel(std::istream& is)  	S32 lod = llclamp((S32) mDetail, 0, MODEL_LODS); -	if (header[nm[lod]]["offset"].asInteger() == -1 ||  -		header[nm[lod]]["size"].asInteger() == 0 ) +	if (header[lod_name[lod]]["offset"].asInteger() == -1 ||  +		header[lod_name[lod]]["size"].asInteger() == 0 )  	{ //cannot load requested LOD  		LL_WARNS() << "LoD data is invalid!" << LL_ENDL;  		return false; @@ -2035,23 +1163,23 @@ bool LLModel::loadModel(std::istream& is)  	bool has_skin = header["skin"]["offset"].asInteger() >=0 &&  					header["skin"]["size"].asInteger() > 0; -	if (lod == LLModel::LOD_HIGH) +	if ((lod == LLModel::LOD_HIGH) && !mSubmodelID)  	{ //try to load skin info and decomp info  		std::ios::pos_type cur_pos = is.tellg();  		loadSkinInfo(header, is);  		is.seekg(cur_pos);  	} -	if (lod == LLModel::LOD_HIGH || lod == LLModel::LOD_PHYSICS) +	if ((lod == LLModel::LOD_HIGH || lod == LLModel::LOD_PHYSICS) && !mSubmodelID)  	{  		std::ios::pos_type cur_pos = is.tellg();  		loadDecomposition(header, is);  		is.seekg(cur_pos);  	} -	is.seekg(header[nm[lod]]["offset"].asInteger(), std::ios_base::cur); +	is.seekg(header[lod_name[lod]]["offset"].asInteger(), std::ios_base::cur); -	if (unpackVolumeFaces(is, header[nm[lod]]["size"].asInteger())) +	if (unpackVolumeFaces(is, header[lod_name[lod]]["size"].asInteger()))  	{  		if (has_skin)  		{  @@ -2117,8 +1245,10 @@ bool LLModel::isMaterialListSubset( LLModel* ref )  				break;  			}										  		} +  		if (!foundRef)  		{ +            LL_INFOS() << "Could not find material " << mMaterialList[src] << " in reference model " << ref->mLabel << LL_ENDL;  			return false;  		}  	} @@ -2169,41 +1299,42 @@ bool LLModel::matchMaterialOrder(LLModel* ref, int& refFaceCnt, int& modelFaceCn  	for (U32 i = 0; i < mMaterialList.size(); i++)  	{  		index_map[ref->mMaterialList[i]] = i; -		if (!reorder) -		{ //if any material name does not match reference, we need to reorder -			reorder = ref->mMaterialList[i] != mMaterialList[i]; -		} +		//if any material name does not match reference, we need to reorder +		reorder |= ref->mMaterialList[i] != mMaterialList[i];  		base_mat.insert(ref->mMaterialList[i]);  		cur_mat.insert(mMaterialList[i]);  	} -	if (reorder &&  -		base_mat == cur_mat) //don't reorder if material name sets don't match +	if (reorder &&  (base_mat == cur_mat)) //don't reorder if material name sets don't match  	{  		std::vector<LLVolumeFace> new_face_list; -		new_face_list.resize(mVolumeFaces.size()); +		new_face_list.resize(mMaterialList.size());  		std::vector<std::string> new_material_list; -		new_material_list.resize(mVolumeFaces.size()); +		new_material_list.resize(mMaterialList.size());  		//rebuild face list so materials have the same order   		//as the reference model  		for (U32 i = 0; i < mMaterialList.size(); ++i)  		{   			U32 ref_idx = index_map[mMaterialList[i]]; -			new_face_list[ref_idx] = mVolumeFaces[i]; +			if (i < mVolumeFaces.size()) +			{ +				new_face_list[ref_idx] = mVolumeFaces[i]; +			}  			new_material_list[ref_idx] = mMaterialList[i];  		}  		llassert(new_material_list == ref->mMaterialList);  		mVolumeFaces = new_face_list; -	} -	//override material list with reference model ordering -	mMaterialList = ref->mMaterialList; +		//override material list with reference model ordering +		mMaterialList = ref->mMaterialList; +	} +	  	return true;  } @@ -2234,7 +1365,7 @@ bool LLModel::loadDecomposition(LLSD& header, std::istream& is)  	S32 offset = header["physics_convex"]["offset"].asInteger();  	S32 size = header["physics_convex"]["size"].asInteger(); -	if (offset >= 0 && size > 0) +	if (offset >= 0 && size > 0 && !mSubmodelID)  	{  		is.seekg(offset, std::ios_base::cur); @@ -2642,3 +1773,227 @@ void LLModel::Decomposition::merge(const LLModel::Decomposition* rhs)  	}  } +bool ll_is_degenerate(const LLVector4a& a, const LLVector4a& b, const LLVector4a& c, F32 tolerance) +{ +	// small area check +	{ +		LLVector4a edge1; edge1.setSub( a, b ); +		LLVector4a edge2; edge2.setSub( a, c ); +		////////////////////////////////////////////////////////////////////////// +		/// Linden Modified +		////////////////////////////////////////////////////////////////////////// + +		// If no one edge is more than 10x longer than any other edge, we weaken +		// the tolerance by a factor of 1e-4f. + +		LLVector4a edge3; edge3.setSub( c, b ); +		const F32 len1sq = edge1.dot3(edge1).getF32(); +		const F32 len2sq = edge2.dot3(edge2).getF32(); +		const F32 len3sq = edge3.dot3(edge3).getF32(); +		bool abOK = (len1sq <= 100.f * len2sq) && (len1sq <= 100.f * len3sq); +		bool acOK = (len2sq <= 100.f * len1sq) && (len1sq <= 100.f * len3sq); +		bool cbOK = (len3sq <= 100.f * len1sq) && (len1sq <= 100.f * len2sq); +		if ( abOK && acOK && cbOK ) +		{ +			tolerance *= 1e-4f; +		} + +		////////////////////////////////////////////////////////////////////////// +		/// End Modified +		////////////////////////////////////////////////////////////////////////// + +		LLVector4a cross; cross.setCross3( edge1, edge2 ); + +		LLVector4a edge1b; edge1b.setSub( b, a ); +		LLVector4a edge2b; edge2b.setSub( b, c ); +		LLVector4a crossb; crossb.setCross3( edge1b, edge2b ); + +		if ( ( cross.dot3(cross).getF32() < tolerance ) || ( crossb.dot3(crossb).getF32() < tolerance )) +		{ +			return true; +		} +	} + +	// point triangle distance check +	{ +		LLVector4a Q; Q.setSub(a, b); +		LLVector4a R; R.setSub(c, b); + +		const F32 QQ = dot3fpu(Q, Q); +		const F32 RR = dot3fpu(R, R); +		const F32 QR = dot3fpu(R, Q); + +		volatile F32 QQRR = QQ * RR; +		volatile F32 QRQR = QR * QR; +		F32 Det = (QQRR - QRQR); + +		if( Det == 0.0f ) +		{ +			return true; +		} +	} + +	return false; +} + +bool validate_face(const LLVolumeFace& face) +{ +	for (U32 i = 0; i < face.mNumIndices; ++i) +	{ +		if (face.mIndices[i] >= face.mNumVertices) +		{ +			LL_WARNS() << "Face has invalid index." << LL_ENDL; +			return false; +		} +	} + +	if (face.mNumIndices % 3 != 0 || face.mNumIndices == 0) +	{ +		LL_WARNS() << "Face has invalid number of indices." << LL_ENDL; +		return false; +	} + +	/*const LLVector4a scale(0.5f); + +	for (U32 i = 0; i < face.mNumIndices; i+=3) +	{ +		U16 idx1 = face.mIndices[i]; +		U16 idx2 = face.mIndices[i+1]; +		U16 idx3 = face.mIndices[i+2]; + +		LLVector4a v1; v1.setMul(face.mPositions[idx1], scale); +		LLVector4a v2; v2.setMul(face.mPositions[idx2], scale); +		LLVector4a v3; v3.setMul(face.mPositions[idx3], scale); + +		if (ll_is_degenerate(v1,v2,v3)) +		{ +			llwarns << "Degenerate face found!" << LL_ENDL; +			return false; +		} +	}*/ + +	return true; +} + +bool validate_model(const LLModel* mdl) +{ +	if (mdl->getNumVolumeFaces() == 0) +	{ +		LL_WARNS() << "Model has no faces!" << LL_ENDL; +		return false; +	} + +	for (S32 i = 0; i < mdl->getNumVolumeFaces(); ++i) +	{ +		if (mdl->getVolumeFace(i).mNumVertices == 0) +		{ +			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; +		} +	} + +	return true; +} + +LLModelInstance::LLModelInstance(LLSD& data) +	: LLModelInstanceBase() +{ +	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() +{ +} + +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; +} + +bool LLImportMaterial::operator<(const LLImportMaterial &rhs) const +{ + +	if (mDiffuseMapID != rhs.mDiffuseMapID) +	{ +		return mDiffuseMapID < rhs.mDiffuseMapID; +	} + +	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; +} + diff --git a/indra/llprimitive/llmodel.h b/indra/llprimitive/llmodel.h index aaafc55258..ae602c09df 100755 --- a/indra/llprimitive/llmodel.h +++ b/indra/llprimitive/llmodel.h @@ -31,6 +31,7 @@  #include "llvolume.h"  #include "v4math.h"  #include "m4math.h" +#include <queue>  class daeElement;  class domMesh; @@ -138,15 +139,16 @@ public:  		BOOL upload_skin,  		BOOL upload_joints,  		BOOL nowrite = FALSE, -		BOOL as_slm = FALSE); +		BOOL as_slm = FALSE, +		int submodel_id = 0);  	static LLSD writeModelToStream(  		std::ostream& ostr,  		LLSD& mdl,  		BOOL nowrite = FALSE, BOOL as_slm = FALSE); +	 +	void ClearFacesAndMaterials() { mVolumeFaces.clear(); mMaterialList.clear(); } -	static LLModel* loadModelFromDomMesh(domMesh* mesh); -	static std::string getElementLabel(daeElement* element);  	std::string getName() const;  	std::string getMetric() const {return mMetric;}  	EModelStatus getStatus() const {return mStatus;} @@ -169,20 +171,25 @@ public:  	void addFace(const LLVolumeFace& face); +	void sortVolumeFacesByMaterialName();  	void normalizeVolumeFaces(); +	void trimVolumeFacesToSize(U32 new_count = LL_SCULPT_MESH_MAX_FACES, LLVolume::face_list_t* remainder = NULL);  	void optimizeVolumeFaces();  	void offsetMesh( const LLVector3& pivotPoint );  	void getNormalizedScaleTranslation(LLVector3& scale_out, LLVector3& translation_out);  	LLVector3 getTransformedCenter(const LLMatrix4& mat); - +	  	//reorder face list based on mMaterialList in this and reference so   	//order matches that of reference (material ordering touchup)  	bool matchMaterialOrder(LLModel* ref, int& refFaceCnt, int& modelFaceCnt );  	bool isMaterialListSubset( LLModel* ref );  	bool needToAddFaces( LLModel* ref, int& refFaceCnt, int& modelFaceCnt ); -	 -	std::vector<std::string> mMaterialList; +	typedef std::vector<std::string> material_list; + +	material_list mMaterialList; + +	material_list& getMaterialList() { return mMaterialList; }  	//data used for skin weights  	class JointWeight @@ -275,9 +282,115 @@ public:  	Decomposition mPhysics;  	EModelStatus mStatus ; + +	int mSubmodelID; +}; + +typedef std::vector<LLPointer<LLModel> >	model_list; +typedef std::queue<LLPointer<LLModel> >	model_queue; + +class LLModelMaterialBase +{ +public:	 +	std::string mDiffuseMapFilename; +	std::string mDiffuseMapLabel; +	std::string mBinding; +	LLColor4		mDiffuseColor; +	bool			mFullbright; + +	LLModelMaterialBase()  +		: mFullbright(false)  +	{  +		mDiffuseColor.set(1,1,1,1); +	} +}; + +class LLImportMaterial : public LLModelMaterialBase +{ +public: +    friend class LLMeshUploadThread; +    friend class LLModelPreview; +     +    bool operator<(const LLImportMaterial ¶ms) const; +     +    LLImportMaterial() : LLModelMaterialBase() +    { +        mDiffuseColor.set(1,1,1,1); +    } +     +    LLImportMaterial(LLSD& data); +    virtual ~LLImportMaterial(); +     +    LLSD asLLSD(); +     +    const LLUUID&	getDiffuseMap() const					{ return mDiffuseMapID;		} +    void				setDiffuseMap(const LLUUID& texId)	{ mDiffuseMapID = texId;	} +      protected: -	void addVolumeFacesFromDomMesh(domMesh* mesh); -	virtual BOOL createVolumeFacesFromDomMesh(domMesh *mesh); +     +    LLUUID		mDiffuseMapID; +    void*			mOpaqueData;	// allow refs to viewer/platform-specific structs for each material +    // currently only stores an LLPointer< LLViewerFetchedTexture > > to +    // maintain refs to textures associated with each material for free +    // ref counting.  }; +typedef std::map<std::string, LLImportMaterial> material_map; + +class LLModelInstanceBase +{ +public: +	LLPointer<LLModel> mModel; +	LLPointer<LLModel> mLOD[5]; +	LLUUID mMeshID; + +	LLMatrix4 mTransform; +	material_map mMaterial; + +	LLModelInstanceBase(LLModel* model, LLMatrix4& transform, material_map& materials) +		: mModel(model), mTransform(transform), mMaterial(materials) +	{ +	} + +	LLModelInstanceBase() +		: mModel(NULL) +	{ +	} +}; + +typedef std::vector<LLModelInstanceBase> model_instance_list; + +class LLModelInstance : public LLModelInstanceBase +{ +public: +	std::string mLabel; +	LLUUID mMeshID; +	S32 mLocalMeshID; + +	LLModelInstance(LLModel* model, const std::string& label, LLMatrix4& transform, material_map& materials) +		: LLModelInstanceBase(model, transform, materials), mLabel(label) +	{ +		mLocalMeshID = -1; +	} + +	LLModelInstance(LLSD& data); + +	LLSD asLLSD(); +}; + +#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); + +bool validate_face(const LLVolumeFace& face); +bool validate_model(const LLModel* mdl); +  #endif //LL_LLMODEL_H diff --git a/indra/llprimitive/llmodelloader.cpp b/indra/llprimitive/llmodelloader.cpp new file mode 100644 index 0000000000..677e4fcb37 --- /dev/null +++ b/indra/llprimitive/llmodelloader.cpp @@ -0,0 +1,622 @@ +/** + * @file llmodelloader.cpp + * @brief LLModelLoader class implementation + * + * $LicenseInfo:firstyear=2004&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$ + */ + +#include "llmodelloader.h" +#include "llsdserialize.h" +#include "lljoint.h" +#include "llcallbacklist.h" + +#include "glh/glh_linear.h" +#include "llmatrix4a.h" +#include <boost/bind.hpp> + +std::list<LLModelLoader*> LLModelLoader::sActiveLoaderList; + +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()); +} + +//----------------------------------------------------------------------------- +// LLModelLoader +//----------------------------------------------------------------------------- +LLModelLoader::LLModelLoader( +	std::string				filename, +	S32						lod, +	load_callback_t		load_cb, +	joint_lookup_func_t	joint_lookup_func, +	texture_load_func_t	texture_load_func, +	state_callback_t		state_cb, +	void*						opaque_userdata, +	JointTransformMap&	jointMap, +	JointSet&				jointsFromNodes ) +: mJointList( jointMap ) +, mJointsFromNode( jointsFromNodes ) +, LLThread("Model Loader") +, mFilename(filename) +, mLod(lod) +, mFirstTransform(TRUE) +, mNumOfFetchingTextures(0) +, mLoadCallback(load_cb) +, mJointLookupFunc(joint_lookup_func) +, mTextureLoadFunc(texture_load_func) +, mStateCallback(state_cb) +, mOpaqueData(opaque_userdata) +, mNoNormalize(false) +, mNoOptimize(false) +, mCacheOnlyHitIfRigged(false) +{ +	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"; + +	//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"); + +	assert_main_thread(); +	sActiveLoaderList.push_back(this) ; +} + +LLModelLoader::~LLModelLoader() +{ +	assert_main_thread(); +	sActiveLoaderList.remove(this); +} + +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; +					} +				} +			}	 +		} +	} + +	return OpenFile(mFilename); +} + +void LLModelLoader::setLoadState(U32 state) +{ +	mStateCallback(state, mOpaqueData); +} + +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, 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) +				{ +					if (!loaded_model->mSkinInfo.mJointNames.empty()) +					{  +						//check to see if rig is valid					 +						critiqueRigForUploadApplicability( loaded_model->mSkinInfo.mJointNames );					 +					} +					else if (mCacheOnlyHitIfRigged) +					{ +						return false; +					} +				} +			} +		} +	}	 + +	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()) +			{ +				if (idx >= model[lod].size()) +				{ +					if (model[lod].size()) +					{ +						instance_list[i].mLOD[lod] = model[lod][0]; +					} +					else +					{ +						instance_list[i].mLOD[lod] = NULL; +					}					 +					continue; +				} +				instance_list[i].mLOD[lod] = model[lod][idx]; +			} +		} + +		if (!instance_list[i].mModel) +			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() +{ +	mLoadCallback(mScene,mModelList,mLod, mOpaqueData); + +	while (!isStopped()) +	{ //wait until this thread is stopped before deleting self +		apr_sleep(100); +	} + +	//double check if "this" is valid before deleting it, in case it is aborted during running. +	if(!isAlive(this)) +	{ +		return ; +	} + +	delete this; +} + +//----------------------------------------------------------------------------- +// critiqueRigForUploadApplicability() +//----------------------------------------------------------------------------- +void LLModelLoader::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 LLModelLoader::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 +	 +	JointSet::iterator jointsFromNodeIt = mJointsFromNode.begin(); +	JointSet::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 LLModelLoader::isRigLegacy( const std::vector<std::string> &jointListFromAsset ) +{ +	//No joints in asset +	if ( jointListFromAsset.size() == 0 ) +	{ +		return false; +	} + +	bool result = false; + +	JointSet :: const_iterator masterJointIt = mMasterLegacyJointList.begin();	 +	JointSet :: 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 LLModelLoader::isRigSuitableForJointPositionUpload( const std::vector<std::string> &jointListFromAsset ) +{ +	bool result = false; + +	JointSet :: const_iterator masterJointIt = mMasterJointList.begin();	 +	JointSet :: 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()) +				{ +					mNumOfFetchingTextures += mTextureLoadFunc(material, mOpaqueData);					 +				} +			} +		} +	} + +	if(!is_paused) +	{ +		unpause() ; +	} +} diff --git a/indra/llprimitive/llmodelloader.h b/indra/llprimitive/llmodelloader.h new file mode 100644 index 0000000000..90ffc0a83a --- /dev/null +++ b/indra/llprimitive/llmodelloader.h @@ -0,0 +1,211 @@ +/** + * @file llmodelloader.h + * @brief LLModelLoader class definition + * + * $LicenseInfo:firstyear=2004&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_LLMODELLOADER_H +#define LL_LLMODELLOADER_H + +#include "llmodel.h" +#include "llthread.h" +#include <boost/function.hpp> +#include <list> + +class LLJoint; + +typedef std::map<std::string, LLMatrix4>					JointTransformMap; +typedef std::map<std::string, LLMatrix4>:: iterator	JointTransformMapIt; +typedef std::map<std::string, std::string>				JointMap; +typedef std::deque<std::string>								JointSet; + +const S32 SLM_SUPPORTED_VERSION	= 3; +const S32 NUM_LOD						= 4; + +class LLModelLoader : public LLThread +{ +public: + +	typedef std::map<std::string, LLImportMaterial>			material_map; +	typedef std::vector<LLPointer<LLModel > >					model_list;	 +	typedef std::vector<LLModelInstance>						model_instance_list;	 +	typedef std::map<LLMatrix4, model_instance_list >		scene; + +	// Callback with loaded model data and loaded LoD +	//  +	typedef boost::function<void (scene&,model_list&,S32,void*) >		load_callback_t; + +	// Function to provide joint lookup by name +	// (within preview avi skeleton, for example) +	// +	typedef boost::function<LLJoint* (const std::string&,void*) >		joint_lookup_func_t; + +	// Func to load and associate material with all it's textures, +	// returned value is the number of textures loaded +	// intentionally non-const so func can modify material to +	// store platform-specific data +	// +	typedef boost::function<U32 (LLImportMaterial&,void*) >				texture_load_func_t; + +	// Callback to inform client of state changes +	// during loading process (errors will be reported +	// as state changes here as well) +	// +	typedef boost::function<void (U32,void*) >								state_callback_t; + +	typedef enum +	{ +		STARTING = 0, +		READING_FILE, +		CREATING_FACES, +		GENERATING_VERTEX_BUFFERS, +		GENERATING_LOD, +		DONE, +		ERROR_PARSING, //basically loading failed +		ERROR_MATERIALS, +		ERROR_PASSWORD_REQUIRED, +		ERROR_NEED_MORE_MEMORY, +		ERROR_INVALID_FILE, +		ERROR_LOADER_SETUP, +		ERROR_INVALID_PARAMETERS, +		ERROR_OUT_OF_RANGE, +		ERROR_FILE_VERSION_INVALID +	} eLoadState; + +	U32 mState; +	std::string mFilename; +	 +	S32 mLod; +	 +	LLMatrix4 mTransform; +	BOOL mFirstTransform; +	LLVector3 mExtents[2]; +	 +	bool mTrySLM; +	bool mCacheOnlyHitIfRigged; // ignore cached SLM if it does not contain rig info (and we want rig info) + +	model_list		mModelList; +	scene				mScene; + +	typedef std::queue<LLPointer<LLModel> > model_queue; + +	//queue of models that need a physics rep +	model_queue mPhysicsQ; + +	//map of avatar joints as named in COLLADA assets to internal joint names +	JointMap			mJointMap; +	JointTransformMap&	mJointList;	 +	JointSet&			mJointsFromNode; + +	LLModelLoader( +		std::string									filename, +		S32											lod,  +		LLModelLoader::load_callback_t		load_cb, +		LLModelLoader::joint_lookup_func_t	joint_lookup_func, +		LLModelLoader::texture_load_func_t	texture_load_func, +		LLModelLoader::state_callback_t		state_cb, +		void*											opaque_userdata, +		JointTransformMap&						jointMap, +		JointSet&									jointsFromNodes); +	virtual ~LLModelLoader() ; + +	virtual void setNoNormalize() { mNoNormalize = true; } +	virtual void setNoOptimize() { mNoOptimize = true; } + +	virtual void run(); +	 +	// Will try SLM or derived class OpenFile as appropriate +	// +	virtual bool doLoadModel(); + +	// Derived classes need to provide their parsing of files here +	// +	virtual bool OpenFile(const std::string& filename) = 0; + +	bool loadFromSLM(const std::string& filename); +	 +	void loadModelCallback(); +	void loadTextures() ; //called in the main thread. +	void setLoadState(U32 state); + +	 + +	S32 mNumOfFetchingTextures ; //updated in the main thread +	bool areTexturesReady() { return !mNumOfFetchingTextures; } //called in the main thread. + +	bool verifyCount( int expected, int result ); + +	//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  ); + +	//Determines if a rig is a legacy from the joint list +	bool isRigLegacy( const std::vector<std::string> &jointListFromAsset ); + +	//Determines if a rig is suitable for upload +	bool isRigSuitableForJointPositionUpload( const std::vector<std::string> &jointListFromAsset ); + +	void setRigWithSceneParity( bool state ) { mRigParityWithScene = state; } +	const bool getRigWithSceneParity( void ) const { return mRigParityWithScene; } + +	const bool isRigValidForJointPositionUpload( void ) const { return mRigValidJointUpload; } +	void setRigValidForJointPositionUpload( bool rigValid ) { mRigValidJointUpload = rigValid; } + +	const bool isLegacyRigValid( void ) const { return mLegacyRigValid; } +	void setLegacyRigValid( bool rigValid ) { mLegacyRigValid = rigValid; }		 + +	//----------------------------------------------------------------------------- +	// isNodeAJoint() +	//----------------------------------------------------------------------------- +	bool isNodeAJoint(const char* name) +	{ +		return mJointMap.find(name) != mJointMap.end(); +	} + +protected: + +	LLModelLoader::load_callback_t		mLoadCallback; +	LLModelLoader::joint_lookup_func_t	mJointLookupFunc; +	LLModelLoader::texture_load_func_t	mTextureLoadFunc; +	LLModelLoader::state_callback_t		mStateCallback; +	void*											mOpaqueData; + +	bool		mRigParityWithScene; +	bool		mRigValidJointUpload; +	bool		mLegacyRigValid; + +	bool		mNoNormalize; +	bool		mNoOptimize; + +	JointSet				mMasterJointList; +	JointSet				mMasterLegacyJointList; +	JointTransformMap	mJointTransformMap; + +	static std::list<LLModelLoader*> sActiveLoaderList; +	static bool isAlive(LLModelLoader* loader) ; +}; +class LLMatrix4a; +void stretch_extents(LLModel* model, LLMatrix4a& mat, LLVector4a& min, LLVector4a& max, BOOL& first_transform); +void stretch_extents(LLModel* model, LLMatrix4& mat, LLVector3& min, LLVector3& max, BOOL& first_transform); + +#endif  // LL_LLMODELLOADER_H diff --git a/indra/llprimitive/lltextureentry.h b/indra/llprimitive/lltextureentry.h index 19edcaa27d..a40c3988f2 100755 --- a/indra/llprimitive/lltextureentry.h +++ b/indra/llprimitive/lltextureentry.h @@ -89,6 +89,10 @@ public:  	bool operator==(const LLTextureEntry &rhs) const;  	bool operator!=(const LLTextureEntry &rhs) const; +	 +	// Added to allow use with std::map +	// +	bool operator <(const LLTextureEntry &rhs) const;  	LLSD asLLSD() const;  	void asLLSD(LLSD& sd) const; diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index e8f4144e70..b7b7b88d35 100755 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -134,7 +134,6 @@ set(viewer_SOURCE_FILES      llbreadcrumbview.cpp      llbrowsernotification.cpp      llbuycurrencyhtml.cpp -    llcallbacklist.cpp      llcallingcard.cpp      llcapabilitylistener.cpp      llcaphttpsender.cpp @@ -738,7 +737,6 @@ set(viewer_HEADER_FILES      llbox.h      llbreadcrumbview.h      llbuycurrencyhtml.h -    llcallbacklist.h      llcallingcard.h      llcapabilitylistener.h      llcapabilityprovider.h @@ -995,6 +993,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 94d3c8a59f..caf1a04e86 100755 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -2,6 +2,28 @@  <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>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/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 0c81ab7e79..efe8b6c266 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,13 @@  #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;  const S32 PREVIEW_BORDER_WIDTH = 2;  const S32 PREVIEW_RESIZE_HANDLE_SIZE = S32(RESIZE_HANDLE_WIDTH * OO_SQRT2) + PREVIEW_BORDER_WIDTH; @@ -205,190 +177,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) -		{ -			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))) +		if (texture->getDiscardLevel() > -1)  		{ -			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; @@ -399,6 +218,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() @@ -1309,1815 +1151,9 @@ 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, 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  //----------------------------------------------------------------------------- @@ -3171,51 +1207,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();  } @@ -3285,7 +1290,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) @@ -3352,29 +1359,9 @@ 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" ); -				} -			} -		} -	} -  	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; @@ -3391,38 +1378,198 @@ 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) -				{ -					break; -				} +            for (int i = LLModel::NUM_LODS - 1; i >= LLModel::LOD_IMPOSTOR; i--) +			{ // 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. + +                LLModel* lod_model = NULL; +                LLMatrix4 transform; + +                std::string name_to_match = instance.mLabel; +                llassert(!name_to_match.empty()); + +                std::string toAdd; +                switch (i) +                { +                    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); + +                BOOL importerDebug = gSavedSettings.getBOOL("ImporterDebug");                     + +                // Fall back to old method of index-based association if +                // we could not find a match based on the mesh names +                // +                if (lod_model) +                { +                     +                    if (i == LLModel::LOD_PHYSICS) +                    { +                        if (importerDebug) +                        { +                            LL_INFOS() << "Assigning collision for " << instance.mLabel << " to match " << lod_model->mLabel << LL_ENDL; +                        } +                        instance.mLOD[i] = lod_model; +                    } +                    else +                    { +                        if (importerDebug) +                        { +                            LL_INFOS() << "Assigning LOD" << i << " for " << instance.mLabel << " to found match " << lod_model->mLabel << LL_ENDL; +                        } +                        instance.mLOD[i] = lod_model; +                    } +                } +                else +                { + +                    if  (i != LLModel::LOD_PHYSICS) +                    { +                        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++; +                        } +                    } + +                    // Fall back to old method of index-based association if +                    // we could not find a match based on the mesh names at all. +                    // +                    if (lod_model) +                    { +                        if (importerDebug) +                        { +                            LL_INFOS() << "Falling back LOD" << i << " for " << instance.mLabel << " to found " << lod_model->mLabel << LL_ENDL; +                        } +                        instance.mLOD[i] = lod_model; +                    } +                    else +                    { +                        S32 idx = 0; +			            for (idx = 0; idx < mBaseModel.size(); ++idx) +			            {  //find reference instance for this model +				            if (mBaseModel[idx] == base_model) +				            { +                                if (importerDebug) +                                { +                                    LL_INFOS() << "Falling back to model index " << idx << " for LOD " << i << " of " << instance.mLabel << LL_ENDL; +                                } +					            break; +				            } +			            } + +                        // If the model list for the current LOD includes that index... +                        // +					    if (mModel[i].size() > idx) +					    {                               +                            // Assign that index from the model list for our LOD as the LOD model for this instance +                            // +                            lod_model = mModel[i][idx]; +						    instance.mLOD[i] = lod_model; +                            if (i == LLModel::LOD_PHYSICS) +                            { +                                if (importerDebug) +                                { +                                    LL_INFOS() << "Indexed fallback to model index " << idx << ": LOD " << i << " named " << lod_model->mLabel << " for collision for " << instance.mLabel <<  LL_ENDL; +                                } +                            } +                            else +                            { +                                if (importerDebug) +                                { +                                    LL_INFOS() << "Indexed fallback to model index " << idx << " LOD " << i << " named " << lod_model->mLabel << " for LOD " << i << " for " << instance.mLabel << LL_ENDL; +                                } +                            } +					    } +                        else +                        { +                            if (importerDebug) +                            { +                                LL_INFOS() << "List of models for LOD " << i << " did not include index " << idx <<  LL_ENDL; +                            } +                        } +                    } +                }  			} -			if(idx < mBaseModel.size()) +            LLModel* high_lod_model = instance.mLOD[LLModel::LOD_HIGH]; +            if (!high_lod_model)  			{ -				for (U32 i = 0; i < LLModel::NUM_LODS; i++) -				{ //fill LOD slots based on reference model index -					if (mModel[i].size() > idx) +				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 ) )  					{ -						instance.mLOD[i] = mModel[i][idx]; +						setLoadState( LLModelLoader::ERROR_MATERIALS ); +						mFMP->childDisable( "calculate_btn" );  					}  					else  					{ -						instance.mLOD[i] = NULL; +						if (mBaseModel.size() == mModel[i].size()) +						{ +							for (U32 idx = 0; idx < mBaseModel.size(); ++idx) +							{ +								if (mModel[i][idx] && !mModel[i][idx]->matchMaterialOrder(mBaseModel[idx], refFaceCnt, modelFaceCnt ) ) +								{ +									setLoadState( LLModelLoader::ERROR_MATERIALS ); +									mFMP->childDisable( "calculate_btn" ); +								} +							} +						}  					}  				}  			} @@ -3497,7 +1644,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 :  @@ -3510,8 +1656,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();  		} @@ -3579,13 +1725,27 @@ 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 );	  	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")); @@ -3674,7 +1834,7 @@ void LLModelPreview::clearGLODGroup()  	}  } -void LLModelPreview::loadModelCallback(S32 lod) +void LLModelPreview::loadModelCallback(S32 loaded_lod)  {  	assert_main_thread(); @@ -3687,12 +1847,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(); @@ -3724,6 +1890,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; @@ -3732,7 +1903,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; @@ -3775,31 +1946,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();  		} @@ -3821,6 +1992,8 @@ void LLModelPreview::loadModelCallback(S32 lod)  	refresh();  	mModelLoadedSignal(); + +	mModelLoader = NULL;  }  void LLModelPreview::resetPreviewTarget() @@ -4108,6 +2281,19 @@ 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; +              			GLint* sizes = new GLint[patch_count*2];  			glodGetObjectParameteriv(mObject[base], GLOD_PATCH_SIZES, sizes);  			stop_gloderror(); @@ -4220,17 +2406,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() @@ -4247,43 +2422,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" ); +            } + +            int refFaceCnt = 0; +            int modelFaceCnt = 0; + +            if (!lod_model->matchMaterialOrder(model_high_lod, refFaceCnt, modelFaceCnt ) ) +			{ +                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; +            if (lod_model) +			{ +					//for each model in the lod +				S32 cur_tris = 0; +				S32 cur_verts = 0; +				S32 cur_submeshes = lod_model->getNumVolumeFaces(); -					//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); +				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)  	{ @@ -4297,28 +2518,36 @@ 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"); @@ -4421,13 +2650,16 @@ void LLModelPreview::updateStatusMessages()  	{  		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; upload_ok && j < mdl->mPhysics.mHull.size(); ++j)  			{ -				upload_ok = false; +				if (mdl->mPhysics.mHull[j].size() > 256) +				{ +					upload_ok = false; +				}  			} -		} +		}		  	}  	bool errorStateFromLoader = getLoadState() >= LLModelLoader::ERROR_PARSING ? true : false; @@ -4889,23 +3121,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()  //----------------------------------------------------------------------------- @@ -4939,10 +3171,62 @@ 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;  	}  } +void LLModelPreview::loadedCallback( +	LLModelLoader::scene& scene, +	LLModelLoader::model_list& model_list, +	S32 lod, +	void* opaque) +{ +	LLModelPreview* pPreview = static_cast< LLModelPreview* >(opaque); +	if (pPreview) +	{ +		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 )  {  	U32 type_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0; @@ -5185,24 +3469,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); @@ -5216,62 +3482,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)  			{ @@ -5299,97 +3564,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); @@ -5576,13 +3841,13 @@ BOOL LLModelPreview::render()  							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); @@ -5697,14 +3962,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 diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h index 6c0c60b87f..0991980575 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: @@ -358,21 +275,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 ); @@ -387,6 +297,14 @@ public:  	LLVector3 getTranslationForJointOffset( std::string joint ); +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 ); @@ -452,7 +370,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]; @@ -470,11 +388,10 @@ private:  	bool		mLegacyRigValid;  	bool		mLastJointUpdate; +	 +	JointSet				mJointsFromNode; +	JointTransformMap	mJointTransformMap; -	std::deque<std::string> mMasterJointList; -	std::deque<std::string> mMasterLegacyJointList; -	std::deque<std::string> mJointsFromNode; -	JointTransformMap		mJointTransformMap;  	LLPointer<LLVOAvatar>	mPreviewAvatar;  }; diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 648056484e..35b5844914 100755 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -492,6 +492,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 +592,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); @@ -766,7 +772,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 +841,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 +914,7 @@ void LLMeshRepoThread::run()  					mSkinRequests.erase(iter);  					mMutex->unlock(); -					if (!fetchMeshSkinInfo(mesh_id)) +					if (! fetchMeshSkinInfo(mesh_id))  					{  						incomplete.insert(mesh_id);  					} @@ -937,7 +943,7 @@ void LLMeshRepoThread::run()  					mDecompositionRequests.erase(iter);  					mMutex->unlock(); -					if (!fetchMeshDecomposition(mesh_id)) +					if (! fetchMeshDecomposition(mesh_id))  					{  						incomplete.insert(mesh_id);  					} @@ -963,7 +969,7 @@ void LLMeshRepoThread::run()  					mPhysicsShapeRequests.erase(iter);  					mMutex->unlock(); -					if (!fetchMeshPhysicsShape(mesh_id)) +					if (! fetchMeshPhysicsShape(mesh_id))  					{  						incomplete.insert(mesh_id);  					} @@ -1189,7 +1195,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 +1243,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 +1289,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 +1335,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 +1383,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 +1428,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 +1519,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 +1611,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 +1885,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 +1953,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 +2025,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 +2070,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 +2107,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 +2141,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 +2393,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 +2498,7 @@ void LLMeshUploadThread::requestWholeModelFee()  	else  	{  		U32 sleep_time(10); - +		  		mHttpRequest->update(0);  		while (! LLApp::isQuitting() && ! finished() && ! isDiscarded())  		{ @@ -2405,7 +2593,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 +2623,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 +2694,7 @@ void LLMeshRepoThread::notifyLoadedMeshes()  		LODRequest req = mUnavailableQ.front();  		mUnavailableQ.pop();  		mMutex->unlock(); -		 +  		update_metrics = true;  		gMeshRepo.notifyMeshUnavailable(req.mMeshParams, req.mLOD);  	} @@ -2642,7 +2830,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 +2886,7 @@ void LLMeshHandlerBase::onCompleted(LLCore::HttpHandle handle, LLCore::HttpRespo  				// 200 case, typically  				offset = 0;  			} - +		  			// *DEBUG:  To test validation below  			// offset += 1; @@ -2814,7 +3002,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 +3010,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 +3022,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 +3052,8 @@ LLMeshLODHandler::~LLMeshLODHandler()  			gMeshRepo.mThread->lockAndLoadMeshLOD(mMeshParams, mLOD);  		}  		LLMeshRepoThread::decActiveLODRequests(); -		}  	} +}  void LLMeshLODHandler::processFailure(LLCore::HttpStatus status)  { @@ -2883,7 +3071,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 +3116,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 +3440,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 +3517,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 +3536,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 +3557,7 @@ void LLMeshRepository::notifyLoadedMeshes()  									<< LL_ENDL;  			}  		} - +		  		//popup queued error messages from background threads  		while (!mUploadErrorQ.empty())  		{ @@ -3724,7 +3912,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 +3983,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 +4380,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 +4568,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; | 
