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

  1.  
  2. #include "precompile.h"
  3. #include "model.h"
  4. #include "newgenlod.h"
  5. #include "model_cleanup.h"
  6. #include <vector>
  7.  
  8.  
  9. #define LOD_SPEED_UP
  10.  
  11. #define VMAP_NONE    0xFFFF
  12.  
  13.  
  14. class GLTri : public ModelTri
  15. {
  16. public:
  17.     BOOL        m_bActive;
  18. };
  19.  
  20.  
  21. class GLPieceLOD
  22. {
  23. public:
  24.  
  25.     // This tells what the original index for this vertex in the GLPiece is.
  26.     CMoArray<DWORD>        m_OriginalVertIndices;
  27. };
  28.  
  29. class GLPiece
  30. {
  31. public:
  32.     GLPiece()
  33.         :m_Tris(5000),m_Verts(400) 
  34.     {
  35.         
  36.     }
  37.  
  38.     ~GLPiece() {
  39.         for (DWORD i = 0; i < m_LODs.GetSize(); i++)
  40.             delete m_LODs[i];
  41.         m_LODs.Term();
  42.     };
  43.     ModelPiece            *m_pModelPiece; // T.F ModelPiece
  44.     PieceLOD                *m_pPiece; // first lod
  45.     CMoArray<GLTri>        m_Tris;
  46.     CMoArray<ModelVert>    m_Verts;
  47.     CMoArray<GLPieceLOD*>    m_LODs;    // lods based on first lod.
  48. };
  49.  
  50.  
  51. class GLModel
  52. {
  53. public:
  54.     ~GLModel() {
  55.         for (DWORD i = 0; i < m_Pieces.GetSize(); i++)
  56.             delete m_Pieces[i];
  57.         m_Pieces.Term();
  58.     };
  59.     BuildLODRequest        *m_pRequest;
  60.     Model                *m_pModel;
  61.     CMoArray<GLPiece*>    m_Pieces;
  62. };
  63.  
  64.  
  65. class EColInfo
  66. {
  67. public:
  68.     DWORD        m_iPiece;
  69.     DWORD        m_Tris[2];
  70.     DWORD        m_iVerts[2];
  71.     DWORD        m_iNewVert; // Is this needed?
  72. };
  73.  
  74.  
  75. typedef CMoArray<EColInfo> EColInfoArray;
  76.  
  77.  
  78. //typedef CMoArray<ModelTri*> ModelTriPtrArray;
  79.  
  80.  
  81. class ModelTriPtrArray {
  82. public :
  83.     enum { SIZE = 20 };
  84.  
  85.     ModelTriPtrArray() :m_MaskedData(SIZE) {}
  86.  
  87.     int GetSize() { return m_MaskedData.GetSize() ; } 
  88.  
  89.     void Append( ModelTri * type ) { m_MaskedData.Append( type ); }
  90.  
  91.     ModelTri *operator []( int val ) { return m_MaskedData[val] ; }
  92.  
  93.     CMoArray<ModelTri*> m_MaskedData ;
  94.  
  95. };
  96.  
  97.  
  98. // Sets up the GLModel structure from the Model structure.
  99. void SetupGLModel(GLModel *pModel, BuildLODRequest *pRequest)
  100. {
  101.     PieceLOD *pInPiece;
  102.     GLPiece *pPiece;
  103.     DWORD iPiece, iTri, iVert;
  104.     Model *pInModel;
  105.  
  106.     pInModel = pRequest->m_pModel;
  107.     pModel->m_pModel = pInModel;
  108.     pModel->m_pRequest = pRequest;
  109.  
  110.     // Copy the pieces.
  111.     for(iPiece=0; iPiece < pInModel->NumPieces(); iPiece++)
  112.     {
  113.         // when generating lods from peices automatically we assume there is only
  114.         // one starting geometry.
  115.         pInPiece = pInModel->GetPiece(iPiece)->GetLOD((uint32)0);
  116.  
  117.         pPiece = new GLPiece;
  118.  
  119.         pPiece->m_pModelPiece = pInModel->GetPiece(iPiece);
  120.         pPiece->m_pPiece = pInPiece;
  121.         pPiece->m_Tris.SetSize(pInPiece->m_Tris.GetSize());
  122.         for(iTri=0; iTri < pPiece->m_Tris; iTri++)
  123.         {
  124.             pPiece->m_Tris[iTri].m_bActive = TRUE;
  125.             pPiece->m_Tris[iTri].ModelTri::operator=(pInPiece->m_Tris[iTri]);
  126.         }
  127.  
  128.         pPiece->m_Verts.SetSize(pInPiece->m_Verts.GetSize());
  129.         for(iVert=0; iVert < pPiece->m_Verts; iVert++)
  130.         {
  131.             pPiece->m_Verts[iVert] = pInPiece->m_Verts[iVert];
  132.             pPiece->m_Verts[iVert].m_iReplacement = (short)iVert;
  133.         }
  134.  
  135.         pModel->m_Pieces.Append(pPiece);
  136.     }
  137. }
  138.  
  139. /*
  140. void AddGenLODToPiece( Piece *pPiece , PieceLOD *pPieceLOD, float tri_percent )
  141. {
  142.  
  143. }
  144. */
  145.  
  146.  
  147. // If pVert has a weight weighted to the specified node, this returns it.
  148. NewVertexWeight* FindWeight(ModelVert *pVert, DWORD iNode)
  149. {
  150.     DWORD i;
  151.  
  152.     for(i=0; i < pVert->m_nWeights; i++)
  153.     {
  154.         if(pVert->m_Weights[i].m_iNode == iNode)
  155.             return &pVert->m_Weights[i];
  156.     }
  157.  
  158.     return NULL;
  159. }
  160.  
  161.  
  162. // Marks any m_iReplacements referencing iVert to iChangeTo.
  163. void MarkReplacements(GLPiece *pPiece, DWORD iVert, DWORD iChangeTo)
  164. {
  165.     DWORD i;
  166.     ModelVert *pVert;
  167.  
  168.  
  169.     for(i=0; i < pPiece->m_Verts; i++)
  170.     {
  171.         pVert = &pPiece->m_Verts[i];
  172.     
  173.         if(pVert->m_iReplacement == iVert)
  174.             pVert->m_iReplacement = (short)iChangeTo;
  175.     }
  176. }
  177.  
  178.  
  179. // Creates a new vertex by merging the two vertices together.
  180. void MergeVerts(GLPiece *pPiece, DWORD iVert1, DWORD iVert2)
  181. {
  182.     ModelVert *pVert1, *pVert2, *pNewVert;
  183.     ModelVert tempVert;
  184.     DWORD i;
  185.     NewVertexWeight *pWeight, *pNewWeight;
  186.  
  187.  
  188.     pPiece->m_Verts.Append(tempVert);
  189.  
  190.     pVert1 = &pPiece->m_Verts[iVert1];
  191.     pVert2 = &pPiece->m_Verts[iVert2];
  192.     
  193.     MarkReplacements(pPiece, iVert1, pPiece->m_Verts.LastI());
  194.     MarkReplacements(pPiece, iVert2, pPiece->m_Verts.LastI());
  195.     
  196.     pVert1->m_iReplacement = (short)pPiece->m_Verts.LastI();
  197.     pVert2->m_iReplacement = (short)pPiece->m_Verts.LastI();
  198.     pNewVert = &pPiece->m_Verts.Last();
  199.     //pNewVert = pPiece->m_Verts.m_MaskedData.end();
  200.     pNewVert->m_iReplacement = (short)pPiece->m_Verts.LastI();
  201.  
  202.  
  203. ASSERT(pVert1->m_iReplacement != (pVert1 - pPiece->m_Verts.GetArray()));
  204. ASSERT(pVert2->m_iReplacement != (pVert2 - pPiece->m_Verts.GetArray()));
  205.  
  206.     pNewVert->m_Vec = pVert1->m_Vec + (pVert2->m_Vec - pVert1->m_Vec) * 0.5f;
  207.     pNewVert->m_Normal = pVert1->m_Normal + (pVert2->m_Normal - pVert1->m_Normal) * 0.5f;
  208.     pNewVert->m_Normal.Norm();
  209.  
  210.     // Add pVert1's weights.
  211.     for(i=0; i < pVert1->m_nWeights; i++)
  212.     {
  213.         pWeight = &pVert1->m_Weights[i];
  214.         pNewWeight = pNewVert->AddWeight();
  215.         
  216.         pNewWeight->m_Vec[0] = pWeight->m_Vec[0] * 0.5f;
  217.         pNewWeight->m_Vec[1] = pWeight->m_Vec[1] * 0.5f;
  218.         pNewWeight->m_Vec[2] = pWeight->m_Vec[2] * 0.5f;
  219.         pNewWeight->m_Vec[3] = pWeight->m_Vec[3] * 0.5f;
  220.         pNewWeight->m_iNode = pWeight->m_iNode;
  221.     }
  222.     
  223.     // Add pVert2's weights.
  224.     for(i=0; i < pVert2->m_nWeights; i++)
  225.     {
  226.         pWeight = &pVert2->m_Weights[i];
  227.  
  228.         pNewWeight = FindWeight(pNewVert, pWeight->m_iNode);
  229.         if(!pNewWeight)
  230.         {
  231.             pNewWeight = pNewVert->AddWeight();
  232.         }
  233.  
  234.         pNewWeight->m_Vec[0] += pWeight->m_Vec[0] * 0.5f;
  235.         pNewWeight->m_Vec[1] += pWeight->m_Vec[1] * 0.5f;
  236.         pNewWeight->m_Vec[2] += pWeight->m_Vec[2] * 0.5f;
  237.         pNewWeight->m_Vec[3] += pWeight->m_Vec[3] * 0.5f;
  238.         pNewWeight->m_iNode = pWeight->m_iNode;
  239.     }
  240. }
  241.  
  242.  
  243. BOOL GetTriVert(GLPiece *pPiece, DWORD iTri, DWORD iVert, DWORD *pIndex)
  244. {
  245.     DWORD i;
  246.     ModelTri *pTri;
  247.  
  248.     pTri = &pPiece->m_Tris[iTri];
  249.     for(i=0; i < 3; i++)
  250.     {
  251.         if(pTri->m_Indices[i] == iVert)
  252.         {
  253.             *pIndex = i;
  254.             return TRUE;
  255.         }
  256.     }
  257.  
  258.     return FALSE;
  259. }
  260.  
  261.  
  262. // If there are any vertices whose only reference comes from these triangles,
  263. // change any replacements referencing them to reference the new vertex.
  264. void UpdateDeadVertexReferences(
  265.     GLModel *pModel, 
  266.     EColInfo *pInfo,
  267.     DWORD iReplacement)
  268. {
  269.     GLPiece *pGLPiece;
  270.     // here tf-cache-test
  271.     CMoArray<ModelTriPtrArray> vertTriRefs;
  272.     DWORD iTri, iTriVert, iVert;
  273.     GLTri *pTri, *pTris[2];
  274.     
  275.  
  276.  
  277.     pGLPiece = pModel->m_Pieces[pInfo->m_iPiece];
  278.  
  279.     pTris[0] = &pGLPiece->m_Tris[pInfo->m_Tris[0]];
  280.     pTris[1] = &pGLPiece->m_Tris[pInfo->m_Tris[1]];
  281.  
  282.     // Make a list for each vertex of what tris reference it.
  283.     vertTriRefs.SetSize(pGLPiece->m_Verts.GetSize());
  284.     for(iTri=0; iTri < pGLPiece->m_Tris; iTri++)
  285.     {
  286.         pTri = &pGLPiece->m_Tris[iTri];
  287.  
  288.         if(!pTri->m_bActive && 
  289.             (pTri != pTris[0] && pTri != pTris[1]))
  290.             continue;
  291.  
  292.         for(iTriVert=0; iTriVert < 3; iTriVert++)
  293.         {
  294.             vertTriRefs[pTri->m_Indices[iTriVert]].Append(pTri);
  295.         }
  296.     }
  297.  
  298.     // Now look for vertices that only are referenced by these tris.
  299.     for(iVert=0; iVert < vertTriRefs; iVert++)
  300.     {
  301.         ModelTriPtrArray &theArray = vertTriRefs[iVert];
  302.         
  303.         if(theArray.GetSize() == 1 && 
  304.             (theArray[0] == pTris[0] || theArray[0] == pTris[1]))
  305.         {
  306.             MarkReplacements(pGLPiece, iVert, iReplacement);
  307.         }    
  308.         else if(theArray.GetSize() == 2 &&
  309.             (theArray[0] == pTris[0] || theArray[0] == pTris[1]) &&
  310.             (theArray[1] == pTris[0] || theArray[1] == pTris[1]))
  311.         {
  312.             MarkReplacements(pGLPiece, iVert, iReplacement);
  313.         }
  314.     }
  315. }
  316.  
  317.  
  318. // Adds the specified edge collapse to the model and updates its structures.
  319. BOOL ProcessECol(GLModel *pModel, EColInfo *pInfo)
  320. {
  321.     DWORD i, iTri, iTriVert;
  322.     GLTri *pTri;
  323.     GLPiece *pGLPiece;
  324.     UVPair uvs[2][2], newUVs[2];
  325.     DWORD iTriVerts[2][2];
  326.     float fMin;
  327.     ModelTri *pUVRefTris[2];
  328.  
  329.     pGLPiece = pModel->m_Pieces[pInfo->m_iPiece];
  330.  
  331.     // Deactivate the tris.
  332.     ASSERT(pGLPiece->m_Tris[pInfo->m_Tris[0]].m_bActive);
  333.     ASSERT(pGLPiece->m_Tris[pInfo->m_Tris[1]].m_bActive);
  334.     pGLPiece->m_Tris[pInfo->m_Tris[0]].m_bActive = FALSE;
  335.     pGLPiece->m_Tris[pInfo->m_Tris[1]].m_bActive = FALSE;
  336.  
  337.     for(i=0; i < 2; i++)
  338.     {
  339.         if(!GetTriVert(pGLPiece, pInfo->m_Tris[i], pInfo->m_iVerts[0], &iTriVerts[i][0]) ||
  340.             !GetTriVert(pGLPiece, pInfo->m_Tris[i], pInfo->m_iVerts[1], &iTriVerts[i][1]))
  341.         {
  342.             ASSERT(FALSE);
  343.             return FALSE;
  344.         }
  345.  
  346.         pUVRefTris[i] = &pGLPiece->m_Tris[pInfo->m_Tris[i]];
  347.  
  348.         uvs[i][0] = pUVRefTris[i]->m_UVs[iTriVerts[i][0]];
  349.         uvs[i][1] = pUVRefTris[i]->m_UVs[iTriVerts[i][1]];
  350.         newUVs[i].tu = uvs[i][0].tu + (uvs[i][1].tu - uvs[i][0].tu) * 0.5f;
  351.         newUVs[i].tv = uvs[i][0].tv + (uvs[i][1].tv - uvs[i][0].tv) * 0.5f;
  352.     }
  353.  
  354.     fMin = 0.001f;
  355.  
  356.     // Update the UVs of any adjacent vertices.
  357.     for(iTri=0; iTri < pGLPiece->m_Tris; iTri++)
  358.     {
  359.         pTri = &pGLPiece->m_Tris[iTri];
  360.  
  361.         if(iTri == pInfo->m_Tris[0] || iTri == pInfo->m_Tris[1])
  362.             continue;
  363.  
  364.         for(iTriVert=0; iTriVert < 3; iTriVert++)
  365.         {
  366.             for(i=0; i < 2; i++)
  367.             {
  368.                 if(pTri->m_Indices[iTriVert] == pUVRefTris[i]->m_Indices[iTriVerts[i][0]])
  369.                 {
  370.                     if(fabs(pTri->m_UVs[iTriVert].tu - uvs[i][0].tu) < fMin && fabs(pTri->m_UVs[iTriVert].tv - uvs[i][0].tv) < fMin)
  371.                         pTri->m_UVs[iTriVert] = newUVs[i];
  372.                 }
  373.                 else if(pTri->m_Indices[iTriVert] == pUVRefTris[i]->m_Indices[iTriVerts[i][1]])
  374.                 {
  375.                     if(fabs(pTri->m_UVs[iTriVert].tu - uvs[i][1].tu) < fMin && fabs(pTri->m_UVs[iTriVert].tv - uvs[i][1].tv) < fMin)
  376.                         pTri->m_UVs[iTriVert] = newUVs[i];
  377.                 }
  378.             }
  379.         }
  380.     }
  381.  
  382.     // Add on the new vertex.
  383.     MergeVerts(pGLPiece, pInfo->m_iVerts[0], pInfo->m_iVerts[1]);
  384.  
  385.     // Reindex the triangles.
  386.     pGLPiece = pModel->m_Pieces[pInfo->m_iPiece];
  387.     for(iTri=0; iTri < pGLPiece->m_Tris; iTri++)
  388.     {
  389.         pTri = &pGLPiece->m_Tris[iTri];
  390.         
  391.         for(iTriVert=0; iTriVert < 3; iTriVert++)
  392.         {
  393.             if(pTri->m_Indices[iTriVert] == pInfo->m_iVerts[0] || pTri->m_Indices[iTriVert] == pInfo->m_iVerts[1])
  394.                 pTri->m_Indices[iTriVert] = (short)pGLPiece->m_Verts.LastI();
  395.         }
  396.     }
  397.  
  398.     // If there are any vertices whose only reference comes from these triangles,
  399.     // change any replacements referencing them to reference the new vertex.
  400.     // This seems to only happen rarely, but it can cause invalid LOD transitions to
  401.     // be generated.
  402.     UpdateDeadVertexReferences(pModel, pInfo, pGLPiece->m_Verts.LastI());
  403.  
  404.     return TRUE;
  405. }
  406.  
  407.  
  408. // Gets rid of the current LOD info in the model.
  409. void DeleteLOD(Model *pModel)
  410. {
  411.     DWORD iPiece;
  412.  
  413.     //pModel->m_LODs.Term();
  414.  
  415.     for(iPiece=0; iPiece < pModel->NumPieces(); iPiece++)
  416.     {
  417.         // // only delete the lods after the first. explictly toss out all other lods.
  418.         pModel->GetPiece(iPiece)->m_LODs.NiceSetSize(1);
  419.     }
  420. }
  421.  
  422.  
  423. // Returns TRUE if 2 and only 2 triangles share the edge.  Returns the triangle indices.
  424. // Fills in pTris with the tris that share the edge.
  425. BOOL TestECol(GLPiece *pPiece, DWORD iVert1, DWORD iVert2, DWORD *pTris)
  426. {
  427.     DWORD i, iCurTri, iVert, iTest1, iTest2;
  428.     GLTri *pTri;
  429.  
  430.     iCurTri = 0;
  431.     for(i=0; i < pPiece->m_Tris; i++)
  432.     {
  433.         pTri = &pPiece->m_Tris[i];
  434.  
  435.         if(!pTri->m_bActive)
  436.             continue;
  437.  
  438.         for(iVert=0; iVert < 3; iVert++)
  439.         {
  440.             iTest1 = pTri->m_Indices[iVert];
  441.             iTest2 = pTri->m_Indices[(iVert+1)%3];
  442.         
  443.             if((iTest1==iVert1 && iTest2==iVert2) || 
  444.                 (iTest2==iVert1 && iTest1==iVert2))
  445.             {
  446.                 // More than 2 tris share this edge.
  447.                 if(iCurTri >= 2)
  448.                     return FALSE;
  449.  
  450.                 pTris[iCurTri] = i;
  451.                 ++iCurTri;
  452.             }
  453.         }
  454.     }
  455.  
  456.     return iCurTri == 2 && (pTris[0] != pTris[1]);
  457. }
  458.  
  459.  
  460. // Returns the number of active triangles in the piece.
  461. DWORD CalcNumActiveTris(GLPiece *pGLPiece)
  462. {
  463.     DWORD i, count;
  464.  
  465.     count = 0;
  466.     for(i=0; i < pGLPiece->m_Tris; i++)
  467.     {
  468.         if(pGLPiece->m_Tris[i].m_bActive)
  469.             ++count;
  470.     }
  471.  
  472.     return count;
  473. }
  474.  
  475.  
  476. // Finds the best edge collapse available in the current model LOD.
  477. BOOL FindShortestEdge(GLModel *pModel, 
  478.     EColInfo *pInfo, 
  479.     BOOL bCheckEdgeLength
  480.     )
  481. {
  482.     DWORD iPiece, iTri, iVert, iTriVert, iTriNextVert;
  483.     DWORD testTris[2];
  484.     PieceLOD *pPiece;
  485.     GLPiece *pGLPiece;
  486.     float fShortestEdge, fTestLen;
  487.     GLTri *pGLTri;
  488.     BOOL bFoundEdge;
  489.     DWORD nActive;
  490.  
  491.     // short edge max
  492.     fShortestEdge = 100000.0f;
  493.     bFoundEdge = FALSE;
  494.     
  495.     // for every piece in model
  496.     for(iPiece=0; iPiece < pModel->m_Pieces; iPiece++)
  497.     {
  498.         // get original model's piece
  499.         pPiece = pModel->m_pModel->m_Pieces[iPiece]->GetLOD(uint32(0));
  500.         pGLPiece = pModel->m_Pieces[iPiece];
  501.  
  502.  
  503.         nActive = CalcNumActiveTris(pGLPiece);
  504.         
  505.         if(nActive <= pModel->m_pRequest->m_nMinPieceTris ||
  506.             nActive <= 2)
  507.         {
  508.             continue;
  509.         }
  510.  
  511.         for(iTri=0; iTri < pGLPiece->m_Tris; iTri++)
  512.         {
  513.             pGLTri = &pGLPiece->m_Tris[iTri];
  514.  
  515.             if(!pGLTri->m_bActive)
  516.                 continue;
  517.  
  518.             for(iVert=0; iVert < 3; iVert++)
  519.             {
  520.                 iTriVert = pGLTri->m_Indices[iVert];
  521.                 iTriNextVert = pGLTri->m_Indices[(iVert+1)%3];
  522.                                                                               
  523.                 fTestLen = (pGLPiece->m_Verts[iTriVert].m_Vec - pGLPiece->m_Verts[iTriNextVert].m_Vec).Mag();
  524.                 fTestLen *= pModel->m_pRequest->GetPieceWeight(iPiece);
  525.  
  526.                 if((fTestLen < fShortestEdge) && (fTestLen > 0.0f) &&
  527.                     TestECol(pGLPiece, iTriVert, iTriNextVert, testTris))
  528.                 {
  529.                     if(bCheckEdgeLength)
  530.                     {
  531.                         if(fTestLen >= pModel->m_pRequest->m_MaxEdgeLength)
  532.                             continue;
  533.                     }
  534.  
  535.                     fShortestEdge = fTestLen;
  536.                     pInfo->m_iVerts[0] = iTriVert;
  537.                     pInfo->m_iVerts[1] = iTriNextVert;
  538.                     pInfo->m_Tris[0] = testTris[0];
  539.                     pInfo->m_Tris[1] = testTris[1];
  540.                     pInfo->m_iPiece = iPiece;
  541.                     bFoundEdge = TRUE;
  542.                 }
  543.             }
  544.         }
  545.     }
  546.  
  547.     return bFoundEdge;
  548. }
  549.  
  550.  
  551. // Adds an LOD to the model using the current state of the GLModel.
  552. BOOL AddLODToModel(GLModel *pModel, 
  553.                     EColInfoArray &ecols,
  554.                     LODRequestInfo *pInfo)
  555. {
  556.     DWORD iPiece, iTri, iECol, nUsedTris, iOutTri;
  557.     DWORD nUsedVerts, iVert, iOutVert, iTriVert;
  558.     GLPiece *pGLPiece;
  559.     GLPieceLOD *pGLLOD, *pPrevGLLOD;
  560.     ModelPiece *pPiece;
  561.     PieceLOD *pLOD;
  562.     PieceLOD tempLOD;
  563.     PieceLOD *pPrevLOD;
  564.     EColInfo *pECol;
  565.     ModelTri *pTri;
  566.     CMoArray<BOOL> usedTris, usedVerts;
  567.     CMoArray<DWORD> vertIndexRemap;
  568.     LODInfo lodInfo;
  569.     BOOL *pUsedVert;
  570.     
  571.     ModelVert *pVert;
  572.  
  573.  
  574.     tempLOD.Init(pModel->m_pModel);
  575.  
  576.     for(iPiece=0; iPiece < pModel->m_Pieces; iPiece++)
  577.     {
  578.         pGLPiece = pModel->m_Pieces[iPiece];
  579.         pPiece = pModel->m_pModel->GetPiece(iPiece);
  580.  
  581.         if(pGLPiece->m_LODs.GetSize() > 0)
  582.             pPrevGLLOD = pGLPiece->m_LODs.Last();
  583.         else
  584.             pPrevGLLOD = NULL;
  585.  
  586.         pPiece->AddLOD(tempLOD,pInfo->m_Dist);
  587.         pLOD = &pPiece->m_LODs.Last();
  588.         
  589.         
  590.         pPrevLOD = pPiece->GetLOD(pPiece->NumLODs() - 2);
  591.         ASSERT(pPrevLOD);
  592.  
  593.         pGLLOD = new GLPieceLOD;
  594.         pGLPiece->m_LODs.Append(pGLLOD);
  595.  
  596.         // Mark which tris we are using.
  597.         nUsedTris = pGLPiece->m_Tris.GetSize();
  598.         usedTris.SetSizeInit2(pGLPiece->m_Tris.GetSize(), TRUE);
  599.         for(iECol=0; iECol < ecols.GetSize(); iECol++)
  600.         {
  601.             pECol = &ecols[iECol];
  602.  
  603.             if(pECol->m_iPiece != iPiece)
  604.                 continue;
  605.  
  606.             usedTris[pECol->m_Tris[0]] = usedTris[pECol->m_Tris[1]] = FALSE;
  607.             nUsedTris -= 2;
  608.         }
  609.  
  610.         // Setup its triangle list.
  611.         iOutTri = 0;
  612.         pLOD->m_Tris.SetSize(nUsedTris);
  613.         for(iTri=0; iTri < usedTris; iTri++)
  614.         {
  615.             if(!usedTris[iTri])
  616.                 continue;
  617.  
  618.             pLOD->m_Tris[iOutTri] = pGLPiece->m_Tris[iTri];
  619.             ++iOutTri;
  620.         }
  621.  
  622.  
  623.         // See which verts are used by the tris.
  624.         nUsedVerts = 0;
  625.         usedVerts.SetSizeInit2(pGLPiece->m_Verts.GetSize(), FALSE);
  626.         for(iTri=0; iTri < pLOD->m_Tris; iTri++)
  627.         {
  628.             for(iTriVert=0; iTriVert < 3; iTriVert++)
  629.             {
  630.                 pUsedVert = &usedVerts[pLOD->m_Tris[iTri].m_Indices[iTriVert]];
  631.                 if(!*pUsedVert)
  632.                 {
  633.                     *pUsedVert = TRUE;
  634.                     nUsedVerts++;
  635.                 }
  636.             }
  637.         }
  638.  
  639.         // Build the vertex list.
  640.         pLOD->m_Verts.SetSize(nUsedVerts);
  641.         pGLLOD->m_OriginalVertIndices.SetSize(nUsedVerts);
  642.  
  643.         vertIndexRemap.SetSizeInit2(pGLPiece->m_Verts.GetSize(), 0xFFFFFFFF);
  644.         iOutVert = 0;
  645.         for(iVert=0; iVert < pGLPiece->m_Verts; iVert++)
  646.         {
  647.             if(!usedVerts[iVert])
  648.                 continue;
  649.         
  650.             pLOD->m_Verts[iOutVert] = pGLPiece->m_Verts[iVert];
  651.             pGLLOD->m_OriginalVertIndices[iOutVert] = iVert;
  652.  
  653.             vertIndexRemap[iVert] = iOutVert;
  654.             iOutVert++;
  655.         }
  656.  
  657.         ASSERT(iOutVert == pLOD->m_Verts.GetSize());
  658.  
  659.         // Now remap the triangle indices.
  660.         for(iTri=0; iTri < pLOD->m_Tris; iTri++)
  661.         {
  662.             pTri = &pLOD->m_Tris[iTri];
  663.  
  664.             for(iTriVert=0; iTriVert < 3; iTriVert++)
  665.             {
  666.                 ASSERT(pTri->m_Indices[iTriVert] != 0xFFFFFFFF);
  667.                 pTri->m_Indices[iTriVert] = (short)vertIndexRemap[pTri->m_Indices[iTriVert]];
  668.             }
  669.         }
  670.  
  671.         // Set the previous LOD's vertex remap parameters..
  672.         for(iVert=0; iVert < pPrevLOD->m_Verts; iVert++)
  673.         {
  674.             pVert = &pPrevLOD->m_Verts[iVert];
  675.  
  676.             if(pPrevGLLOD)
  677.             {
  678.                 pVert->m_iReplacement = (short)vertIndexRemap[
  679.                     pGLPiece->m_Verts[pPrevGLLOD->m_OriginalVertIndices[iVert]].m_iReplacement
  680.                 ];
  681.             }
  682.             else
  683.             {
  684.                 pVert->m_iReplacement = (short)vertIndexRemap[
  685.                     pGLPiece->m_Verts[iVert].m_iReplacement
  686.                 ];
  687.             }
  688.  
  689.             // Was an invalid transition generated (or were replacement indices
  690.             // updated incorrectly?)
  691.             ASSERT(pVert->m_iReplacement < pLOD->m_Verts.GetSize());
  692.             if(pVert->m_iReplacement >= pLOD->m_Verts.GetSize())
  693.                 return FALSE;
  694.         }
  695.     }
  696.     
  697.     return TRUE;
  698. }
  699.  
  700. // iteratively build lods. 
  701. BOOL BuildLODs(BuildLODRequest *pRequest)
  702. {
  703.     GLModel model;
  704.     EColInfo ecol;
  705.     EColInfoArray ecols;
  706.     DWORD i, nBaseTris, iCurLOD, nCurTris;
  707.     LODRequestInfo *pInfo;
  708.  
  709.  
  710.     // Old exporters didn't remove unused vertices and unused vertices
  711.     // screw up the LOD algorithm.
  712.     gn_RemoveUnusedVertices(pRequest->m_pModel);
  713.  
  714.     // Get rid of previous LODs.
  715.     DeleteLOD(pRequest->m_pModel);
  716.     
  717.     SetupGLModel(&model, pRequest);
  718.  
  719.     ecols.SetCacheSize(512);
  720. //    
  721.     nBaseTris = pRequest->m_pModel->CalcNumTris();
  722.  
  723.     // Mark them as unprocessed.
  724.     for(i=0; i < pRequest->m_LODInfos; i++)
  725.         pRequest->m_LODInfos[i].m_bProcessed = FALSE;
  726.  
  727.     // Generate a sequence of edge collapses.
  728.     iCurLOD = 0;
  729.     while(1)
  730.     {
  731.         iCurLOD++;
  732.  
  733.         // Get the best next edge collapse..
  734.         if(!FindShortestEdge(&model, &ecol, TRUE))
  735.         {
  736.             if(!FindShortestEdge(&model, &ecol, FALSE))
  737.             {
  738.                 break;
  739.             }
  740.         }
  741.  
  742.         // Update the structures with this edge collapse.
  743.         ProcessECol(&model, &ecol);
  744.  
  745.         // Remember this edge collapse.
  746.         ecols.Append(ecol);
  747.  
  748.         // If there are any LODs eligible for this # of tris, add an LOD.
  749.         for(i=0; i < pRequest->m_LODInfos; i++)
  750.         {
  751.             pInfo = &pRequest->m_LODInfos[i];
  752.  
  753.             if(pInfo->m_bProcessed)
  754.                 continue;
  755.  
  756.             nCurTris = nBaseTris - (iCurLOD << 1);
  757.             if(LTDIFF(nCurTris, pInfo->m_nTris) <= 1)
  758.             {
  759.                 // Add an LOD for this..
  760.                 if(!AddLODToModel(&model, ecols, pInfo))
  761.                     return FALSE;
  762.  
  763.                 pInfo->m_bProcessed = TRUE;
  764.                 break;
  765.             }
  766.         }
  767.     }
  768.  
  769.     return TRUE;
  770. }
  771.  
  772.  
  773.