home *** CD-ROM | disk | FTP | other *** search
/ Xentax forum attachments archive / xentax.7z / 8090 / ModelEdit.7z / PieceMerge.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2006-03-08  |  9.1 KB  |  322 lines

  1. #include "precompile.h"
  2. #include "model.h"
  3. #include "PieceMerge.h"
  4. #include <algorithm>
  5.  
  6. using namespace std;
  7.  
  8.  
  9. CPieceMerge::CPieceMerge( Model* model, vector<ModelPiece*>& pieces )
  10. {
  11.     ASSERT( model );
  12.     m_Model = model;
  13.  
  14.     for( vector<ModelPiece*>::iterator it = pieces.begin(); it != pieces.end(); it++ )
  15.     {
  16.         m_Pieces.push_front( *it );
  17.     }
  18.  
  19.     // store the original pointers in order (for vertex animation remapping)
  20.     m_OriginalPieces.reserve( m_Model->m_Pieces.GetSize() );
  21.     for( uint32 curPiece = 0; curPiece < m_Model->m_Pieces; curPiece++ )
  22.     {
  23.         m_OriginalPieces.push_back( m_Model->m_Pieces[curPiece] );
  24.     }
  25. }
  26.  
  27.  
  28. CPieceMerge::~CPieceMerge()
  29. {
  30. }
  31.  
  32.  
  33. // merge the pieces and return the number of resulting pieces
  34. uint32 CPieceMerge::Merge( void )
  35. {
  36.     list<ModelPiece*> mergePieces;
  37.     uint32 numNewPieces = 0;
  38.  
  39.     // grab any remaining mergeable pieces and merge them together
  40.     while( m_Pieces.size() )
  41.     {
  42.         if( GetMergeablePieces( mergePieces ) )
  43.             MergePieces( mergePieces );
  44.  
  45.         numNewPieces++;
  46.     }
  47.  
  48.     // we've probably just trampled vertex animation indices, so remap them
  49.     RemapVertexAnimations();
  50.  
  51.     // return resulting number of pieces
  52.     return numNewPieces;
  53. }
  54.  
  55.  
  56. // get a list of pieces that can be merged with the first piece in the list and remove them from the list of pieces waiting to be merged
  57. // returns false if no pieces were mergeable with the first piece in the list
  58. bool CPieceMerge::GetMergeablePieces( list<ModelPiece*>& pieces )
  59. {
  60.     pieces.clear();
  61.  
  62.     int numMergeablePieces = 0;
  63.     int numPiecesLeft = m_Pieces.size();
  64.     if( !numPiecesLeft )
  65.         return false;
  66.  
  67.     // grab the item we will be comparing others against
  68.     list<ModelPiece*>::iterator it = m_Pieces.begin();
  69.     ModelPiece* first = *it;
  70.     it = m_Pieces.erase( it );
  71.  
  72.     // loop through all the items in the list looking for ones that are mergeable with the first one
  73.     while( it != m_Pieces.end() )
  74.     {
  75.         if( ArePiecesMergeable( first, *it ) )
  76.         {
  77.             // the pieces are mergeable, move the current one to the merge list
  78.             pieces.push_back( *it );
  79.             it = m_Pieces.erase( it );
  80.             numMergeablePieces++;
  81.         }
  82.         else
  83.             it++;
  84.     }
  85.  
  86.     // if matches were found, add the first element to the mergeable pieces array
  87.     if( numMergeablePieces )
  88.     {
  89.         pieces.push_front( first );
  90.         numMergeablePieces++;
  91.     }
  92.  
  93.     return( numMergeablePieces >= 2 );
  94. }
  95.  
  96.  
  97. // returns true if two model pieces are mergeable
  98. bool CPieceMerge::ArePiecesMergeable( ModelPiece* a, ModelPiece* b )
  99. {
  100.     // must be skeletally animated
  101.     if( a->m_isVA || b->m_isVA )
  102.         return false;
  103.  
  104.     // must have the same LOD offsets
  105.     uint32 aMinLOD, aMaxLOD, bMinLOD, bMaxLOD;
  106.     a->GetMinMaxLODOffset( aMinLOD, aMaxLOD );
  107.     b->GetMinMaxLODOffset( bMinLOD, bMaxLOD );
  108.     if( (aMinLOD != bMinLOD) || (aMaxLOD != bMaxLOD) )
  109.         return false;
  110.  
  111.     // must have same number of LODs
  112.     uint32 aNumLODs = a->NumLODs();
  113.     uint32 bNumLODs = b->NumLODs();
  114.     if( aNumLODs != bNumLODs )
  115.         return false;
  116.  
  117.     // check each LOD for matching info
  118.     for( uint32 curLOD = 0; curLOD < aNumLODs; curLOD++ )
  119.     {
  120.         PieceLOD* aLOD = a->GetLOD( curLOD );
  121.         PieceLOD* bLOD = b->GetLOD( curLOD );
  122.  
  123.         // must have the same LOD distance
  124.         if( a->GetLODDist( curLOD ) != b->GetLODDist( curLOD ) )
  125.             return false;
  126.  
  127.         // must have same number of textures
  128.         if( aLOD->m_nNumTextures != bLOD->m_nNumTextures )
  129.             return false;
  130.  
  131.         // texture indices that matter must be the same
  132.         for( uint32 curTex = 0; curTex < aLOD->m_nNumTextures; curTex++ )
  133.         {
  134.             if( aLOD->m_iTextures[curTex] != bLOD->m_iTextures[curTex] )
  135.                 return false;
  136.         }
  137.  
  138.         // must have the same renderstyle
  139.         if( aLOD->m_iRenderStyle != bLOD->m_iRenderStyle )
  140.             return false;
  141.     }
  142.  
  143.     return true;
  144. }
  145.  
  146.  
  147. // merge these pieces into one and delete the original pieces (must be mergeable pieces)
  148. bool CPieceMerge::MergePieces( list<ModelPiece*>& pieces )
  149. {
  150.     // create the new modelpiece
  151.     ModelPiece* newPiece = new ModelPiece( m_Model );
  152. //    ModelPiece* newPiece = LNew_1P( m_Model->GetAlloc(), ModelPiece, m_Model );
  153.  
  154.     // the piece we will be copying information from
  155.     ModelPiece* originalPiece = pieces.front();
  156.  
  157.     // copy the name
  158.     newPiece->SetName( originalPiece->GetName() );
  159.  
  160.     // copy the LOD offset information
  161.     uint32 minLODOffset, maxLODOffset;
  162.     originalPiece->GetMinMaxLODOffset( minLODOffset, maxLODOffset );
  163.     newPiece->SetMinMaxLODOffset( minLODOffset, maxLODOffset );
  164.  
  165.     // copy LOD weight (not really used, but copy anyway)
  166.     float originalLODWeight = originalPiece->GetLODWeight();
  167.     newPiece->SetLODWeight( originalLODWeight );
  168.  
  169.     // create space for LODs
  170.     uint32 numLODs = originalPiece->NumLODs();
  171.     newPiece->m_LODs.SetCacheSize( numLODs );
  172.     newPiece->m_LODDists.SetCacheSize( numLODs );
  173.  
  174.     // create the LODs
  175.     for( uint32 curLOD = 0; curLOD < numLODs; curLOD++ )
  176.     {
  177.         // create the new LOD (copy assignment, so don't allocate on heap)
  178.         PieceLOD newLOD;
  179.         newLOD.Init( m_Model );
  180.  
  181.         // grab the original LOD to copy information from
  182.         PieceLOD* originalLOD = originalPiece->GetLOD( curLOD );
  183.         ASSERT( originalLOD );
  184.         float originalLODDist = originalPiece->GetLODDist( curLOD );
  185.  
  186.         // copy material information
  187.         newLOD.SetMaterialInfo( *originalLOD );
  188.  
  189.         // count the number of tris and verts
  190.         uint32 numTris = 0;
  191.         uint32 numVerts = 0;
  192.  
  193.         list<ModelPiece*>::iterator pieceIt;
  194.  
  195.         for( pieceIt = pieces.begin(); pieceIt != pieces.end(); pieceIt++ )
  196.         {
  197.             PieceLOD* origLOD = (*pieceIt)->GetLOD( curLOD );
  198.             numTris += origLOD->m_Tris.GetSize();
  199.             numVerts += origLOD->m_Verts.GetSize();
  200.         }
  201.  
  202.         // allocate space for the new tris and verts
  203.         ASSERT( numVerts && numTris );
  204.         newLOD.m_Tris.SetSize( numTris );
  205.         newLOD.m_Verts.SetSize( numVerts );
  206.  
  207.         // copy the geometry data
  208.         uint32 curTri = 0;
  209.         uint32 curVert = 0;
  210.  
  211.         for( pieceIt = pieces.begin(); pieceIt != pieces.end(); pieceIt++ )
  212.         {
  213.             PieceLOD* origLOD = (*pieceIt)->GetLOD( curLOD );
  214.  
  215.             // copy the triangles
  216.             for( uint32 curOrigTri = 0; curOrigTri < origLOD->m_Tris; curOrigTri++ )
  217.             {
  218.                 newLOD.m_Tris[curTri] = origLOD->m_Tris[curOrigTri];
  219.  
  220.                 // need to update indices
  221.                 for( uint32 curIndex = 0; curIndex < 3; curIndex++ )
  222.                 {
  223.                     newLOD.m_Tris[curTri].m_Indices[curIndex] += curVert;
  224.                 }
  225.  
  226.                 curTri++;
  227.             }
  228.  
  229.             // copy the verts
  230.             for( uint32 curOrigVert = 0; curOrigVert < origLOD->m_Verts; curOrigVert++ )
  231.             {
  232.                 newLOD.m_Verts[curVert] = origLOD->m_Verts[curOrigVert];
  233.  
  234.                 // need to create new weight array
  235.                 uint32 numWeights = newLOD.m_Verts[curVert].m_nWeights;
  236.                 newLOD.m_Verts[curVert].m_Weights = new NewVertexWeight[numWeights];    // this memory will be leaked :(
  237.                 for( uint32 curWeight = 0; curWeight < numWeights; curWeight++ )
  238.                 {
  239.                     newLOD.m_Verts[curVert].m_Weights[curWeight].m_iNode = origLOD->m_Verts[curOrigVert].m_Weights[curWeight].m_iNode;
  240.                     for( uint32 weightVec = 0; weightVec < 4; weightVec++ )
  241.                     {
  242.                         newLOD.m_Verts[curVert].m_Weights[curWeight].m_Vec[weightVec] = origLOD->m_Verts[curOrigVert].m_Weights[curWeight].m_Vec[weightVec];
  243.                     }
  244.                 }
  245.  
  246.                 curVert++;
  247.             }
  248.         }
  249.  
  250.         ASSERT( (curVert == numVerts) && (curTri == numTris) );
  251.  
  252.         // update the used node list so nodes don't get removed
  253.         newLOD.CalcUsedNodeList();
  254.  
  255.         // add the new LOD to the piece
  256.         newPiece->AddLOD( newLOD, originalLODDist, true );
  257.     }
  258.  
  259.     // kill the old pieces and replace with the new one
  260.     uint32 insertAt = m_Model->m_Pieces.FindElement( pieces.front() );
  261.  
  262.     for( list<ModelPiece*>::iterator it = pieces.begin(); it != pieces.end(); it++ )
  263.     {
  264.         uint32 removeAt = m_Model->m_Pieces.FindElement( *it );
  265.         m_Model->m_Pieces.Remove( removeAt );
  266.         delete *it;
  267.     }
  268.  
  269.     m_Model->m_Pieces.Insert( insertAt, newPiece );
  270.  
  271.     return true;
  272. }
  273.  
  274.  
  275. // fix vertex animation piece mappings that were trampled in the merge
  276. bool CPieceMerge::RemapVertexAnimations( void )
  277. {
  278.     for( uint32 curPieceNum = 0; curPieceNum < m_Model->NumPieces(); curPieceNum++ )
  279.     {
  280.         ModelPiece* curPiece = m_Model->GetPiece( curPieceNum );
  281.  
  282.         // skip it if it's not vertex animated
  283.         if( !curPiece->m_isVA )
  284.             continue;
  285.  
  286.         // find the original index for this piece
  287.         vector<ModelPiece*>::iterator it = find( m_OriginalPieces.begin(), m_OriginalPieces.end(), curPiece );
  288.         uint32 originalIndex = it - m_OriginalPieces.begin();
  289.         ASSERT( it != m_OriginalPieces.end() );
  290.  
  291.         // now find the vertex animation that references this piece
  292.         for( uint32 curAnimNum = 0; curAnimNum < m_Model->NumAnims(); curAnimNum++ )
  293.         {
  294.             ModelAnim* curAnim = m_Model->GetAnim( curAnimNum );
  295.             AnimNode* rootAnim = curAnim->GetRootNode();
  296.  
  297.             RemapVertexAnimationsRecurse( rootAnim, originalIndex, curPieceNum );
  298.         }
  299.     }
  300.  
  301.     return true;
  302. }
  303.  
  304.  
  305. void CPieceMerge::RemapVertexAnimationsRecurse( AnimNode* curNode, uint32 originalIndex, uint32 newIndex )
  306. {
  307.     if( !curNode )
  308.         return;
  309.  
  310.     if( curNode->GetVertexAnimTarget() == (int)originalIndex )
  311.         curNode->SetVertexAnimTarget( (int)newIndex );
  312.  
  313.     // recurse through children
  314.     uint32 numChildren = curNode->NumChildren();
  315.  
  316.     for( uint32 curChild = 0; curChild < numChildren; curChild++ )
  317.     {
  318.         AnimNode* child = curNode->GetChild( curChild );
  319.         RemapVertexAnimationsRecurse( child, originalIndex, newIndex );
  320.     }
  321. }
  322.