From b092147a0be579e102c9210c6c99110862e9ad02 Mon Sep 17 00:00:00 2001
From: "Brad Payne (Vir Linden)" <vir@lindenlab.com>
Date: Tue, 19 Apr 2016 11:48:06 -0400
Subject: [PATCH] SL-372 - handle dae models with multiple skeleton roots

---
 indra/llprimitive/lldaeloader.cpp | 186 +++++++++++++++---------------
 1 file changed, 95 insertions(+), 91 deletions(-)

diff --git a/indra/llprimitive/lldaeloader.cpp b/indra/llprimitive/lldaeloader.cpp
index 50875669fa1..df696074043 100644
--- a/indra/llprimitive/lldaeloader.cpp
+++ b/indra/llprimitive/lldaeloader.cpp
@@ -1152,28 +1152,29 @@ void LLDAELoader::processDomModel(LLModel* model, DAE* dae, daeElement* root, do
 
 
 		//Some collada setup for accessing the skeleton
-		daeElement* pElement = 0;
-		dae->getDatabase()->getElement( &pElement, 0, 0, "skeleton" );
+        U32 skeleton_count = dae->getDatabase()->getElementCount( NULL, "skeleton" );
+        std::vector<domInstance_controller::domSkeleton*> skeletons;
+        for (S32 i=0; i<skeleton_count; i++)
+        {
+            daeElement* pElement = 0;
+            dae->getDatabase()->getElement( &pElement, i, 0, "skeleton" );
 
-		//Try to get at the skeletal instance controller
-		domInstance_controller::domSkeleton* pSkeleton = daeSafeCast<domInstance_controller::domSkeleton>( pElement );
+            //Try to get at the skeletal instance controller
+            domInstance_controller::domSkeleton* pSkeleton = daeSafeCast<domInstance_controller::domSkeleton>( pElement );
+			daeElement* pSkeletonRootNode = NULL;
+            if (pSkeleton)
+            {
+                pSkeletonRootNode = pSkeleton->getValue().getElement();
+            }
+            if (pSkeleton && pSkeletonRootNode)
+            {
+                skeletons.push_back(pSkeleton);
+            }
+        }
 		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 )
+		if ( skeletons.size() == 0 )
 		{
 			daeElement* pScene = root->getDescendant("visual_scene");
 			if ( !pScene )
@@ -1200,85 +1201,88 @@ void LLDAELoader::processDomModel(LLModel* model, DAE* dae, daeElement* root, do
 			}
 		}
 		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 );
+			//Has one or more skeletons
+            for (std::vector<domInstance_controller::domSkeleton*>::iterator skel_it = skeletons.begin();
+                 skel_it != skeletons.end(); ++skel_it)
+            {
+                domInstance_controller::domSkeleton* pSkeleton = *skel_it;
+                //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();
 
-					//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() );
+                    //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;
 
-						LLMatrix4 workingTransform;
+                        //Setup the resolver
+                        daeSIDResolver resolver( pSkeletonRootNode, str );
 
-						//Translation via SID
-						if ( pTranslateA )
-						{
-							extractTranslation( pTranslateA, workingTransform );
-						}
-						else
+                        //Look for the joint
+                        domNode* pJoint = daeSafeCast<domNode>( resolver.getElement() );
+                        if ( pJoint )
                         {
-							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 );
-									}
-
-							}
+                            //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 its name.
+                            mJointList[(*jointIt).second.c_str()] = workingTransform;
                         }
+                    }
 
-                        //Store the joint transform w/respect to its 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?
-		}
+                    //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();
-- 
GitLab