home *** CD-ROM | disk | FTP | other *** search
/ Programming a Multiplayer FPS in DirectX / Programming a Multiplayer FPS in DirectX (Companion CD).iso / DirectX / dxsdk_oct2004.exe / dxsdk.exe / Utilities / MView / mload.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2004-09-30  |  91.9 KB  |  2,880 lines

  1. /*//////////////////////////////////////////////////////////////////////////////
  2. //
  3. // File: mload.cpp
  4. //
  5. // Copyright (C) 1999 Microsoft Corporation. All Rights Reserved.
  6. //
  7. //
  8. //////////////////////////////////////////////////////////////////////////////*/
  9.  
  10. #include "mviewpch.h"
  11.  
  12. HRESULT GenerateMesh(SMeshContainer *pmcMesh);
  13. HRESULT
  14. CalculateBoundingSphereMC(SMeshContainer *pmcMesh, LPD3DXVECTOR3 pCenter, FLOAT *pfRadius);
  15.  
  16. HRESULT AllocateName(LPCSTR Name, LPTSTR *pNewName)
  17. {
  18.     UINT cbLength;
  19.  
  20.     if (Name != NULL)
  21.     {
  22.         cbLength = strlen(Name)+1;
  23.         *pNewName = new TCHAR[cbLength];
  24.         if (*pNewName == NULL)
  25.         {
  26.             return E_OUTOFMEMORY;
  27.         }
  28.  
  29.         memcpy(*pNewName, Name, cbLength*sizeof(TCHAR));
  30.     }
  31.     else
  32.     {
  33.         *pNewName = NULL;
  34.     }
  35.  
  36.     return S_OK;
  37. }
  38.  
  39. // Make a copy of one effect default into another
  40. HRESULT CopyEffectDefault
  41.     (
  42.     LPD3DXEFFECTDEFAULT pDefaultSrc,
  43.     LPD3DXEFFECTDEFAULT pDefaultDest
  44.     )
  45. {
  46.     HRESULT hr;
  47.  
  48.     hr = AllocateName(pDefaultSrc->pParamName, &pDefaultDest->pParamName);
  49.     if (FAILED(hr))
  50.         return hr;
  51.  
  52.     pDefaultDest->Type = pDefaultSrc->Type;
  53.     pDefaultDest->NumBytes = pDefaultSrc->NumBytes;
  54.     pDefaultDest->pValue = new BYTE[pDefaultSrc->NumBytes];
  55.     if (pDefaultDest->pValue == NULL)
  56.         return E_OUTOFMEMORY;
  57.  
  58.     memcpy(pDefaultDest->pValue, pDefaultSrc->pValue, pDefaultDest->NumBytes);
  59.  
  60.     return hr;
  61. }
  62.  
  63. // Make a copy of one effect instance into another
  64. HRESULT CopyEffectInstance
  65.     (
  66.     CONST D3DXEFFECTINSTANCE *pEffectSrc,
  67.     LPD3DXEFFECTINSTANCE pEffectDest
  68.     )
  69. {
  70.     HRESULT hr = S_OK;
  71.     UINT iDefault;
  72.  
  73.     hr = AllocateName(pEffectSrc->pEffectFilename, &pEffectDest->pEffectFilename);
  74.     if (FAILED(hr))
  75.         goto e_Exit;
  76.  
  77.     pEffectDest->NumDefaults = pEffectSrc->NumDefaults;
  78.     if (pEffectDest->NumDefaults > 0)
  79.     {
  80.         pEffectDest->pDefaults = new D3DXEFFECTDEFAULT[pEffectSrc->NumDefaults];
  81.         if (pEffectDest->pDefaults == NULL)
  82.         {
  83.             hr = E_OUTOFMEMORY;
  84.             goto e_Exit;
  85.         }
  86.  
  87.         for (iDefault = 0; iDefault < pEffectSrc->NumDefaults; iDefault++)
  88.         {
  89.             hr = CopyEffectDefault(&pEffectSrc->pDefaults[iDefault], &pEffectDest->pDefaults[iDefault]);
  90.             if (FAILED(hr))
  91.                 goto e_Exit;
  92.         }
  93.     }
  94.  
  95. e_Exit:
  96.     return hr;
  97. }
  98.  
  99. HRESULT AddNormal
  100.     (
  101.     CD3DXCrackDecl1 &cd,
  102.     D3DVERTEXELEMENT9 pDecl[MAX_FVF_DECL_SIZE]
  103.     )
  104. {
  105.     UINT iInsert;
  106.     D3DVERTEXELEMENT9 NormalElement;
  107.  
  108.     iInsert = 0;
  109.  
  110.     // try to insert the normal in a place that would satisfy FVF conventions
  111.     if (cd.BPosition())
  112.         iInsert += 1;
  113.     if (cd.BWeights())
  114.         iInsert += 1;
  115.     if (cd.BIndexedWeights())
  116.         iInsert += 1;
  117.  
  118.     if (D3DXGetDeclLength(pDecl) + 1 == MAX_FVF_DECL_SIZE)
  119.     {
  120.         /// UNDONE UNDONE
  121.         // need to add a message box here that we can't load the mesh due to number of vertex elements
  122.         return E_FAIL;
  123.     }
  124.  
  125.     // Insert a normal element into the decl 
  126.     NormalElement.Stream = 0;
  127.     NormalElement.Type = D3DDECLTYPE_FLOAT3;
  128.     NormalElement.Usage = D3DDECLUSAGE_NORMAL;
  129.     NormalElement.UsageIndex = 0;
  130.     NormalElement.Method = D3DDECLMETHOD_DEFAULT;
  131.     InsertDeclElement(iInsert, &NormalElement, pDecl);
  132.  
  133.     // update the crack decl with the new normal added
  134.     cd.SetDeclaration(pDecl);              
  135.  
  136.     return S_OK;
  137. }
  138.  
  139. HRESULT AddTangent
  140.     (
  141.     CD3DXCrackDecl1 &cd,
  142.     D3DVERTEXELEMENT9 pDecl[MAX_FVF_DECL_SIZE]
  143.     )
  144. {
  145.     UINT iInsert;
  146.     D3DVERTEXELEMENT9 NormalElement;
  147.  
  148.     iInsert = 0;
  149.  
  150.     // try to insert the normal in a place that would satisfy FVF conventions
  151.     if (cd.BPosition())
  152.         iInsert += 1;
  153.     if (cd.BWeights())
  154.         iInsert += 1;
  155.     if (cd.BIndexedWeights())
  156.         iInsert += 1;
  157.  
  158.     if (D3DXGetDeclLength(pDecl) + 1 == MAX_FVF_DECL_SIZE)
  159.     {
  160.         /// UNDONE UNDONE
  161.         // need to add a message box here that we can't load the mesh due to number of vertex elements
  162.         return E_FAIL;
  163.     }
  164.  
  165.     // Insert a normal element into the decl 
  166.     NormalElement.Stream = 0;
  167.     NormalElement.Type = D3DDECLTYPE_FLOAT3;
  168.     NormalElement.Usage = D3DDECLUSAGE_TANGENT;
  169.     NormalElement.UsageIndex = 0;
  170.     NormalElement.Method = D3DDECLMETHOD_DEFAULT;
  171.     InsertDeclElement(iInsert, &NormalElement, pDecl);
  172.  
  173.     // update the crack decl with the new normal added
  174.     cd.SetDeclaration(pDecl);              
  175.  
  176.     return S_OK;
  177. }
  178.  
  179. //=============================================================================
  180. //
  181. //  CAllocateHierarchy - Allocate nodes for the frame hierarchy tree
  182. //
  183. //=============================================================================
  184. class CAllocateHierarchy: public ID3DXAllocateHierarchy
  185. {
  186. public:
  187.  
  188.     // ID3DXInterpolator
  189.     STDMETHOD(CreateFrame)(THIS_ LPCSTR Name, 
  190.                             LPD3DXFRAME *ppNewFrame)
  191.     {
  192.         HRESULT hr = S_OK;
  193.         SFrame *pFrame;
  194.  
  195.         *ppNewFrame = NULL;
  196.  
  197.         pFrame = new SFrame;
  198.         if (pFrame == NULL)
  199.         {
  200.             hr = E_OUTOFMEMORY;
  201.             goto e_Exit;
  202.         }
  203.  
  204.         hr = AllocateName(Name, &pFrame->szName);
  205.         if (FAILED(hr))
  206.             goto e_Exit;
  207.  
  208.         *ppNewFrame = (LPD3DXFRAME)pFrame;
  209.         pFrame = NULL;
  210. e_Exit:
  211.         delete pFrame;
  212.         return hr;
  213.     }
  214.  
  215.     STDMETHOD(CreateMeshContainer)(THIS_ 
  216.         LPCSTR Name, 
  217.         CONST D3DXMESHDATA *pMeshData, 
  218.         CONST D3DXMATERIAL *pMaterials, 
  219.         CONST D3DXEFFECTINSTANCE *pEffects, 
  220.         DWORD NumMaterials, 
  221.         CONST DWORD *pAdjacency, 
  222.         LPD3DXSKININFO pSkinInfo, 
  223.         LPD3DXMESHCONTAINER *ppNewMeshContainer) 
  224.     {
  225.         HRESULT hr;
  226.         SMeshContainer *pMeshContainer = NULL;
  227.         UINT iBone, cBones;
  228.         UINT NumFaces;
  229.         UINT iMaterial;
  230.         LPDIRECT3DDEVICE9 pd3dDevice = NULL;
  231.         LPDIRECT3DTEXTURE9 ptex;
  232.         LPD3DXEFFECT pEffect;
  233.         D3DVERTEXELEMENT9 pDecl[MAX_FVF_DECL_SIZE];
  234.         CD3DXCrackDecl1 cd;
  235.         DWORD dwSkinningSupport;
  236.         LPD3DXBUFFER pbufErrors;
  237.         D3DXVECTOR3 vMeshCenter;
  238.         FLOAT fMeshRadius;
  239.         BOOL bUsesTangents = FALSE;
  240.  
  241.         LPD3DXMESH pMesh = NULL;
  242.         LPD3DXPMESH pPMesh = NULL;
  243.         LPD3DXPATCHMESH pPatchMesh = NULL;
  244.  
  245.         if (pMeshData->Type == D3DXMESHTYPE_PATCHMESH)
  246.             pPatchMesh = pMeshData->pPatchMesh;
  247.         else if (pMeshData->Type == D3DXMESHTYPE_PMESH)
  248.             pPMesh = pMeshData->pPMesh;
  249.         else
  250.             pMesh = pMeshData->pMesh;
  251.  
  252.         *ppNewMeshContainer = NULL;
  253.  
  254.         pMeshContainer = new SMeshContainer;
  255.         if (pMeshContainer == NULL)
  256.         {
  257.             hr = E_OUTOFMEMORY;
  258.             goto e_Exit;
  259.         }
  260.  
  261.         pMeshContainer->m_Method = g_pData->m_method;
  262.         pMeshContainer->m_iPaletteSize = g_pData->m_iPaletteSize;
  263.  
  264.         hr = AllocateName(Name, &pMeshContainer->Name);
  265.         if (FAILED(hr))
  266.             goto e_Exit;
  267.         
  268.         // if a patch mesh is found, enable tesselate mode for this node and then generate a mesh via tesselation
  269.         if (pPatchMesh != NULL)
  270.         {
  271.             pPatchMesh->GetDevice(&pd3dDevice);
  272.  
  273.             pMeshContainer->pPatchMesh = pPatchMesh;
  274.             pPatchMesh->AddRef();
  275.  
  276.             hr = g_pData->Tesselate(pMeshContainer, FALSE);
  277.             if(FAILED(hr))
  278.                 goto e_Exit;
  279.  
  280.             pPatchMesh->GetDeclaration(pDecl);
  281.  
  282.             pMeshContainer->bTesselateMode = TRUE;
  283.         }
  284.         // if a pmesh is found, setup this node to enable pmeshes and allocate an adjacency array large enough for the max LOD
  285.         else if (pPMesh != NULL)
  286.         {
  287.             pPMesh->GetDevice(&pd3dDevice);
  288.  
  289.             pMeshContainer->bPMMeshMode = true;
  290.  
  291.             pMeshContainer->m_cNumVertices = pPMesh->GetNumVertices();
  292.             pMeshContainer->m_cMaxVerticesSoft = pPMesh->GetMaxVertices();
  293.             pMeshContainer->m_cMinVerticesSoft = pPMesh->GetMinVertices();
  294.  
  295.             pMeshContainer->pPMMesh = pPMesh;
  296.             pMeshContainer->pPMMesh->AddRef();
  297.  
  298.             NumFaces = pMeshContainer->pPMMesh->GetMaxFaces();
  299.  
  300.             pMeshContainer->rgdwAdjacency = new DWORD[NumFaces*3];
  301.             if (pMeshContainer->rgdwAdjacency == NULL) 
  302.             {
  303.                 hr = E_OUTOFMEMORY;
  304.                 goto e_Exit;
  305.             }
  306.  
  307.             // get the adjacency from the pmesh rather than the input
  308.             pMeshContainer->pPMMesh->GetAdjacency(pMeshContainer->rgdwAdjacency);
  309.  
  310.             pMeshContainer->pPMMesh->GetDeclaration(pDecl);
  311.         }
  312.         // standard mesh found, allocate an adjacency buffer of the same size
  313.         else
  314.         {
  315.  
  316.             pMesh->GetDevice(&pd3dDevice);
  317.  
  318.             pMeshContainer->pMesh = pMesh;
  319.             pMeshContainer->pMesh->AddRef();
  320.  
  321.             NumFaces = pMeshContainer->pMesh->GetNumFaces();
  322.             
  323.             pMeshContainer->rgdwAdjacency = new DWORD[NumFaces*3];
  324.             if (pMeshContainer->rgdwAdjacency == NULL) 
  325.             {
  326.                 hr = E_OUTOFMEMORY;
  327.                 goto e_Exit;
  328.             }
  329.  
  330.             memcpy(pMeshContainer->rgdwAdjacency, pAdjacency, sizeof(DWORD) * NumFaces*3);
  331.  
  332.             pMeshContainer->pMesh->GetDeclaration(pDecl);
  333.         }
  334.  
  335.         //.now that we have data for the vertex layout, create a crack decl
  336.         cd.SetDeclaration(pDecl);
  337.  
  338.         // if no materials are found, then generate a "default" material of gray
  339.         if ((pMaterials == NULL) || (NumMaterials == 0))
  340.         {
  341.             pMeshContainer->NumMaterials = 1;
  342.             pMeshContainer->m_cAttributeGroups = 1;
  343.             pMeshContainer->m_rgpfxAttributes = new LPD3DXEFFECT[pMeshContainer->NumMaterials];
  344.             pMeshContainer->m_rgEffectInfo = new SEffectInfo[pMeshContainer->NumMaterials];
  345.             pMeshContainer->rgMaterials = new D3DXMATERIAL[pMeshContainer->NumMaterials];
  346.             if ((pMeshContainer->rgMaterials == NULL) || (pMeshContainer->m_rgEffectInfo == NULL) || (pMeshContainer->m_rgpfxAttributes == NULL))
  347.             {
  348.                 pMeshContainer->NumMaterials = 0;
  349.                 hr = E_OUTOFMEMORY;
  350.                 goto e_Exit;
  351.             }
  352.  
  353.             memset(pMeshContainer->rgMaterials, 0, sizeof(D3DXMATERIAL) * pMeshContainer->NumMaterials);
  354.             memset(pMeshContainer->m_rgpfxAttributes, 0, sizeof(LPD3DXEFFECT) * pMeshContainer->NumMaterials);
  355.  
  356.             D3DMATERIAL9 mat;
  357.             memset(&mat, 0, sizeof(D3DMATERIAL9));
  358.             mat.Diffuse.r = 0.5f;
  359.             mat.Diffuse.g = 0.5f;
  360.             mat.Diffuse.b = 0.5f;
  361.             mat.Specular = mat.Diffuse;
  362.  
  363.             pMeshContainer->rgMaterials[0].MatD3D = mat;
  364.             pMeshContainer->rgMaterials[0].pTextureFilename = NULL;
  365.  
  366.             D3DXEFFECTINSTANCE EffectInstance;
  367.  
  368.             memset(&EffectInstance, 0, sizeof(D3DXEFFECTINSTANCE));
  369.  
  370.             // create effect instance will create a "default" effect when pEffectFilename is NULL
  371.             hr = D3DXCreateEffectInstance(&EffectInstance, pd3dDevice, &pMeshContainer->m_rgpfxAttributes[0], NULL);
  372.             if (FAILED(hr))
  373.                 goto e_Exit;
  374.  
  375.             //hr = GenerateEffectInfo(pMeshContainer->m_rgpfxAttributes[0], &pMeshContainer->m_rgEffectInfo[0]);
  376.             //if (FAILED(hr))
  377.                 //goto e_Exit;
  378.  
  379.             // set our "default" material colors
  380.             pMeshContainer->m_rgpfxAttributes[0]->SetVector("Ambient", (LPD3DXVECTOR4)&mat.Ambient);
  381.             pMeshContainer->m_rgpfxAttributes[0]->SetVector("Diffuse", (LPD3DXVECTOR4)&mat.Diffuse);
  382.             pMeshContainer->m_rgpfxAttributes[0]->SetVector("Specular", (LPD3DXVECTOR4)&mat.Specular);            
  383.         }
  384.         // materials found, so save them off
  385.         else
  386.         {
  387.             pMeshContainer->m_rgpfxAttributes = new LPD3DXEFFECT[NumMaterials];
  388.             pMeshContainer->m_rgEffectInfo = new SEffectInfo[NumMaterials];
  389.             pMeshContainer->rgMaterials = new D3DXMATERIAL[NumMaterials];
  390.             pMeshContainer->pEffects = new D3DXEFFECTINSTANCE[NumMaterials];
  391.             pMeshContainer->NumMaterials = NumMaterials;
  392.             pMeshContainer->m_cAttributeGroups = NumMaterials;
  393.             if ((pMeshContainer->rgMaterials == NULL) || (pMeshContainer->m_rgEffectInfo == NULL) || (pMeshContainer->m_rgpfxAttributes == NULL))
  394.             {
  395.                 pMeshContainer->NumMaterials = 0;
  396.                 hr = E_OUTOFMEMORY;
  397.                 goto e_Exit;
  398.             }
  399.  
  400.             memset(pMeshContainer->rgMaterials, 0, sizeof(D3DXMATERIAL) * NumMaterials);
  401.             memset(pMeshContainer->m_rgpfxAttributes, 0, sizeof(LPD3DXEFFECT) * NumMaterials);
  402.             memset(pMeshContainer->pEffects, 0, sizeof(D3DXEFFECTINSTANCE) * NumMaterials);
  403.  
  404.             for (iMaterial = 0; iMaterial < NumMaterials; iMaterial++)
  405.             {
  406.                 hr = CopyEffectInstance(&pEffects[iMaterial], &pMeshContainer->pEffects[iMaterial]);
  407.                 if (FAILED(hr))
  408.                     goto e_Exit;
  409.  
  410.                 pMeshContainer->rgMaterials[iMaterial].MatD3D = pMaterials[iMaterial].MatD3D;
  411.  
  412.                 ptex = NULL;
  413.                 if (pMaterials[iMaterial].pTextureFilename != NULL)
  414.                 {
  415.                     DWORD cchFilename = strlen(pMaterials[iMaterial].pTextureFilename) + 1;
  416.                     pMeshContainer->rgMaterials[iMaterial].pTextureFilename = new char[cchFilename];
  417.                     if (pMeshContainer->rgMaterials[iMaterial].pTextureFilename == NULL)
  418.                     {
  419.                         hr = E_OUTOFMEMORY;
  420.                         goto e_Exit;
  421.                     }
  422.                     memcpy(pMeshContainer->rgMaterials[iMaterial].pTextureFilename,
  423.                                     pMaterials[iMaterial].pTextureFilename, sizeof(char) * cchFilename);
  424.                 }
  425.  
  426.                 hr = D3DXCreateEffectInstance(&pEffects[iMaterial], pd3dDevice, &pMeshContainer->m_rgpfxAttributes[iMaterial], &pbufErrors);
  427.  
  428.                 if (pbufErrors)
  429.                 {
  430.                     MessageBox(NULL, (LPSTR)pbufErrors->GetBufferPointer(), "Effect file errors", MB_OK);
  431.                     GXRELEASE(pbufErrors);
  432.                 }
  433.  
  434.                 if (FAILED(hr))
  435.                     goto e_Exit;
  436.  
  437.                 //pMeshContainer->m_rgpfxAttributes[iMaterial]->SetTechnique((LPCSTR)1);
  438.  
  439.                 //hr = GenerateEffectInfo(pMeshContainer->m_rgpfxAttributes[iMaterial], &pMeshContainer->m_rgEffectInfo[iMaterial]);
  440.                 //if (FAILED(hr))
  441.                   //  goto e_Exit;
  442.             }
  443.         }
  444.  
  445.  
  446.         // if skinning info is found, then we need to setup all info for skinning this mesh container
  447.         if (pSkinInfo != NULL)
  448.         {
  449.             pMeshContainer->pSkinInfo = pSkinInfo;
  450.             pSkinInfo->AddRef();
  451.             pMeshContainer->m_pOrigMesh = pMesh;
  452.             pMesh->AddRef();
  453.  
  454.             cBones = pSkinInfo->GetNumBones();
  455.  
  456.             pMeshContainer->pBoneOffsetMatrices = new D3DXMATRIX[cBones];
  457.             pMeshContainer->m_pBoneMatrix = new D3DXMATRIX*[cBones];
  458.             if ((pMeshContainer->m_pBoneMatrix == NULL) || (pMeshContainer->pBoneOffsetMatrices == NULL))
  459.             {
  460.                 hr = E_OUTOFMEMORY;
  461.                 goto e_Exit;
  462.             }
  463.  
  464.  
  465.             for (iBone = 0; iBone < cBones; iBone++)
  466.             {
  467.                 pMeshContainer->pBoneOffsetMatrices[iBone] = *(pSkinInfo->GetBoneOffsetMatrix(iBone));
  468.             }
  469.  
  470.             hr = GenerateMesh(pMeshContainer);
  471.             if (FAILED(hr))
  472.                 goto e_Exit;
  473.  
  474.             dwSkinningSupport = D3DXST_3WEIGHT;
  475.         }
  476.         else  // non-skinned case, unskinned required
  477.         {
  478.             dwSkinningSupport = D3DXST_UNSKINNED;
  479.         }
  480.  
  481.         pd3dDevice->SetSoftwareVertexProcessing(TRUE);
  482.         pMeshContainer->m_dwSkinningType = dwSkinningSupport;
  483.  
  484.         pd3dDevice->SetFVF(D3DFVF_XYZ);
  485.  
  486.         // now that the skinning mode has been selected, select the first technique to match it and validate
  487.         for (iMaterial = 0; iMaterial < pMeshContainer->NumMaterials; iMaterial++)
  488.         {
  489.             hr = SelectTechnique(pMeshContainer->m_rgpfxAttributes[iMaterial], dwSkinningSupport);
  490.             if (FAILED(hr))
  491.             {
  492.                 DPF(0, "CreateMeshContainer: No technique found that will validate");
  493.                 goto e_Exit;
  494.             }
  495.  
  496.             hr = GenerateEffectInfo(pMeshContainer->m_rgpfxAttributes[iMaterial], &pMeshContainer->m_rgEffectInfo[iMaterial]);
  497.             if (FAILED(hr))
  498.                 goto e_Exit;
  499.  
  500.             D3DXTECHNIQUE_DESC TechniqueDesc;
  501.             D3DXPASS_DESC PassDesc;
  502.             D3DXHANDLE hPass;
  503.             D3DXHANDLE hTechnique;
  504.             hTechnique = pMeshContainer->m_rgpfxAttributes[iMaterial]->GetCurrentTechnique();
  505.             pMeshContainer->m_rgpfxAttributes[iMaterial]->GetTechniqueDesc(hTechnique, &TechniqueDesc);
  506.             for( UINT iPass = 0; iPass < TechniqueDesc.Passes; iPass++ )
  507.             {
  508.                 hPass = pMeshContainer->m_rgpfxAttributes[iMaterial]->GetPass( hTechnique, iPass );
  509.                 pMeshContainer->m_rgpfxAttributes[iMaterial]->GetPassDesc( hPass, &PassDesc );
  510.  
  511.                 UINT NumVSSemanticsUsed;
  512.                 D3DXSEMANTIC pVSSemantics[MAXD3DDECLLENGTH];
  513.  
  514.                 if( !PassDesc.pVertexShaderFunction ||
  515.                     FAILED( D3DXGetShaderInputSemantics( PassDesc.pVertexShaderFunction, pVSSemantics, &NumVSSemanticsUsed ) ) )
  516.                 {
  517.                     continue;
  518.                 }
  519.  
  520.                 for( UINT iSem = 0; iSem < NumVSSemanticsUsed; iSem++ )
  521.                 {
  522.                     if( pVSSemantics[iSem].Usage == D3DDECLUSAGE_TANGENT )
  523.                     {
  524.                         bUsesTangents = TRUE;
  525.                         break;
  526.                     }
  527.                 }
  528.             }
  529.         }
  530.  
  531.         pd3dDevice->SetSoftwareVertexProcessing(FALSE);
  532.  
  533.         // handle the case where there is a mesh without normals
  534.         if (pMeshContainer->pMesh != NULL)
  535.         {
  536.             /* if no normals in the mesh, then clone the mesh to add the normals and then compute them */
  537.             if (cd.GetSemanticElement(D3DDECLUSAGE_NORMAL, 0) == NULL)
  538.             {
  539.                 LPD3DXMESH pMeshTemp = pMeshContainer->pMesh;
  540.  
  541.                 AddNormal(cd, pDecl);
  542.  
  543.                 pMeshContainer->pMesh = NULL;
  544.  
  545.                 // clone in the space for the new normal
  546.                 hr = pMeshTemp->CloneMesh(pMeshTemp->GetOptions(), pDecl, pd3dDevice, &pMeshContainer->pMesh);
  547.     
  548.                 GXRELEASE(pMeshTemp);
  549.  
  550.                 if (FAILED(hr))
  551.                     goto e_Exit;
  552.     
  553.                 hr = D3DXComputeNormals(pMeshContainer->pMesh, NULL);
  554.                 if (FAILED(hr))
  555.                     goto e_Exit;
  556.  
  557.             }            
  558.  
  559.             if (bUsesTangents && (NULL == cd.GetSemanticElement(D3DDECLUSAGE_TANGENT, 0)))
  560.             {
  561.                 LPD3DXMESH pMeshTemp = pMeshContainer->pMesh;
  562.  
  563.                 AddTangent(cd, pDecl);
  564.  
  565.                 pMeshContainer->pMesh = NULL;
  566.  
  567.                 // clone in the space for the new normal
  568.                 hr = pMeshTemp->CloneMesh(pMeshTemp->GetOptions(), pDecl, pd3dDevice, &pMeshContainer->pMesh);
  569.     
  570.                 GXRELEASE(pMeshTemp);
  571.  
  572.                 if (FAILED(hr))
  573.                     goto e_Exit;
  574.     
  575.                 hr = D3DXComputeTangent( pMeshContainer->pMesh, 0, 0, D3DX_DEFAULT, TRUE, NULL );
  576.                 if (FAILED(hr))
  577.                     goto e_Exit;
  578.             }
  579.  
  580.             // down cast to the base mesh type (could also QI for it)
  581.             GXRELEASE(pMeshContainer->ptmDrawMesh);
  582.             pMeshContainer->ptmDrawMesh = pMeshContainer->pMesh;
  583.             pMeshContainer->ptmDrawMesh->AddRef();
  584.  
  585.         }
  586.         // handle the case where there is a pmesh without normals
  587.         else if (pMeshContainer->pPMMesh != NULL)
  588.         {
  589.             /* if no normals in the mesh, then clone the mesh to add the normals and then compute them */
  590.             if (cd.GetSemanticElement(D3DDECLUSAGE_NORMAL, 0) == NULL)
  591.             {
  592.                 LPD3DXPMESH pPMeshTemp = pMeshContainer->pPMMesh;
  593.                 pMeshContainer->pPMMesh = NULL;
  594.  
  595.                 AddNormal(cd, pDecl);
  596.  
  597.                 hr = pPMeshTemp->ClonePMesh(pPMeshTemp->GetOptions(), pDecl, pd3dDevice, &pMeshContainer->pPMMesh);
  598.     
  599.                 GXRELEASE(pPMeshTemp);
  600.  
  601.                 if (FAILED(hr))
  602.                     goto e_Exit;
  603.     
  604.                 hr = D3DXComputeNormals(pMeshContainer->pPMMesh, NULL);
  605.                 if (FAILED(hr))
  606.                     goto e_Exit;
  607.  
  608.             }
  609.  
  610.             // need compute tangent to take a base mesh
  611.             if (bUsesTangents && (NULL == cd.GetSemanticElement(D3DDECLUSAGE_TANGENT, 0)))
  612.             {
  613.                 LPD3DXMESH pMeshTemp;
  614.                 LPD3DXPMESH pPMeshTemp = pMeshContainer->pPMMesh;
  615.                 pMeshContainer->pPMMesh = NULL;
  616.  
  617.                 AddTangent(cd, pDecl);
  618.  
  619.                 hr = pPMeshTemp->ClonePMesh(pPMeshTemp->GetOptions(), pDecl, pd3dDevice, &pMeshContainer->pPMMesh);
  620.     
  621.                 GXRELEASE(pPMeshTemp);
  622.  
  623.                 if (FAILED(hr))
  624.                     goto e_Exit;
  625.  
  626.              // normal mesh required for compute tangent, so clone one that uses the same VB and do the work there
  627.  
  628.                 // set to Max LOD so that all vertices will be touched
  629.                 pMeshContainer->pPMMesh->SetNumVertices(0xffffffff);
  630.  
  631.                 // clone the mesh NOTE: SHARING the VB
  632.                 hr = pMeshContainer->pPMMesh->CloneMesh(pMeshContainer->pPMMesh->GetOptions() | D3DXMESH_VB_SHARE, NULL, pd3dDevice, &pMeshTemp);
  633.                 if (FAILED(hr))
  634.                     goto e_Exit;
  635.     
  636.                 // compute the tangents on the mesh with the shared VB
  637.                 hr = D3DXComputeTangent( pMeshTemp, 0, 0, D3DX_DEFAULT, TRUE, NULL );
  638.                 GXRELEASE (pMeshTemp);
  639.  
  640.                 if (FAILED(hr))
  641.                     goto e_Exit;
  642.             }
  643.  
  644.             // down cast to the base mesh type (could also QI for it)
  645.             GXRELEASE(pMeshContainer->ptmDrawMesh);
  646.             pMeshContainer->ptmDrawMesh = pMeshContainer->pPMMesh;
  647.             pMeshContainer->ptmDrawMesh->AddRef();
  648.         }
  649.  
  650.         // setup attribute table
  651.         pMeshContainer->ptmDrawMesh->GetAttributeTable(NULL, &pMeshContainer->m_caeAttributeTable);
  652.  
  653.         // The load function will attribute sort the mesh, just make sure that there is one
  654.         GXASSERT(pMeshContainer->m_caeAttributeTable > 0);
  655.  
  656.         // allocate an attribute table for convenience purposes
  657.         delete []pMeshContainer->m_rgaeAttributeTable;
  658.         pMeshContainer->m_rgaeAttributeTable = new D3DXATTRIBUTERANGE[pMeshContainer->m_caeAttributeTable];
  659.         if (pMeshContainer->m_rgaeAttributeTable == NULL)
  660.         {
  661.             hr = E_OUTOFMEMORY;
  662.             goto e_Exit;
  663.         }
  664.  
  665.         pMeshContainer->ptmDrawMesh->GetAttributeTable(pMeshContainer->m_rgaeAttributeTable, &pMeshContainer->m_caeAttributeTable);
  666.  
  667.  
  668.         hr = CalculateBoundingSphereMC(pMeshContainer, &vMeshCenter, &fMeshRadius);
  669.         if (FAILED(hr))
  670.             goto e_Exit;
  671.  
  672.         // set the mesh radius/center into the effect
  673.         for (iMaterial = 0; iMaterial < pMeshContainer->NumMaterials; iMaterial++)
  674.         {
  675.             SetEffectMeshInfo(pMeshContainer->m_rgpfxAttributes[iMaterial], &vMeshCenter, fMeshRadius);
  676.         }
  677.  
  678.         *ppNewMeshContainer = (LPD3DXMESHCONTAINER)pMeshContainer;
  679.         pMeshContainer = NULL;
  680. e_Exit:
  681.         GXRELEASE(pd3dDevice);
  682.  
  683.         // call Destroy function to properly clean up the memory allocated 
  684.         if (pMeshContainer != NULL)
  685.         {
  686.             DestroyMeshContainer((LPD3DXMESHCONTAINER)pMeshContainer);
  687.         }
  688.  
  689.         return hr;
  690.     }
  691.  
  692.  
  693.     STDMETHOD(DestroyFrame)(THIS_ LPD3DXFRAME pFrameToFree) 
  694.     {
  695.         SFrame *pFrame = (SFrame*)pFrameToFree;
  696.  
  697.         pFrame->pframeSibling = NULL;
  698.         pFrame->pframeFirstChild = NULL;
  699.         pFrame->pmcMesh = NULL; 
  700.         delete pFrame;
  701.         return S_OK; 
  702.     }
  703.  
  704.     STDMETHOD(DestroyMeshContainer)(THIS_ LPD3DXMESHCONTAINER pMeshContainerBase)
  705.     {
  706.         SMeshContainer *pMeshContainer = (SMeshContainer*)pMeshContainerBase;
  707.  
  708.         // DON"T traverse the list of mesh containers to free them in the destructor
  709.         pMeshContainer->pNextMeshContainer = NULL;
  710.         delete pMeshContainer;
  711.  
  712.         return S_OK;
  713.     }
  714. };
  715.  
  716. HRESULT
  717. InitViews
  718.     (
  719.     SFrame *pframe, 
  720.     SDrawElement *pde
  721.     )
  722. {
  723.     HRESULT hr = S_OK;
  724.     SMeshContainer *pmcCur = pframe->pmcMesh;
  725.     SFrame *pframeCur;
  726.  
  727.     while (pmcCur != NULL)
  728.     {
  729.         hr = pmcCur->UpdateViews(pde);
  730.         if (FAILED(hr))
  731.             goto e_Exit;
  732.  
  733.         pmcCur = (SMeshContainer*)pmcCur->pNextMeshContainer;
  734.     }
  735.  
  736.     pframeCur = pframe->pframeFirstChild;
  737.     while (pframeCur != NULL)
  738.     {
  739.         hr = InitViews(pframeCur, pde);
  740.         if (FAILED(hr))
  741.             goto e_Exit;
  742.  
  743.         pframeCur = pframeCur->pframeSibling;
  744.     }
  745.  
  746. e_Exit:
  747.     return hr;
  748. }
  749.  
  750. HRESULT
  751. SetupOrigMatrices
  752.     (
  753.     SFrame *pframe
  754.     )
  755. {
  756.     HRESULT hr = S_OK;
  757.     SMeshContainer *pmcCur = pframe->pmcMesh;
  758.     SFrame *pframeCur;
  759.  
  760.     // remember the starting matrix for saving later
  761.     pframe->matRotOrig = pframe->matRot;
  762.  
  763.     pframeCur = pframe->pframeFirstChild;
  764.     while (pframeCur != NULL)
  765.     {
  766.         hr = SetupOrigMatrices(pframeCur);
  767.         if (FAILED(hr))
  768.             goto e_Exit;
  769.  
  770.         pframeCur = pframeCur->pframeSibling;
  771.     }
  772.  
  773. e_Exit:
  774.     return hr;
  775. }
  776.  
  777. HRESULT
  778. TrivialData::LoadMeshHierarchyFromFile(char *szFilename)
  779. {
  780.     HRESULT hr = S_OK;
  781.     SDrawElement *pdeMesh = NULL;
  782.     DWORD dwOptions;
  783.     int cchFileName;
  784.     char szPath[256];
  785.     char *szTemp;
  786.     DWORD cchPath;
  787.     CAllocateHierarchy Alloc;
  788.  
  789.     cchPath = GetFullPathName(szFilename, sizeof(szPath), szPath, &szTemp);
  790.     if ((cchPath == 0) || (sizeof(szPath) <= cchPath))
  791.         return 1;
  792.  
  793.     // remove the filename from the path part
  794.     szPath[szTemp - szPath] = '\0';
  795.  
  796.     // set the current directory, so that textures will be searched from there
  797.     SetCurrentDirectory(szPath);
  798.  
  799.     pdeMesh = new SDrawElement();
  800.     if (pdeMesh == NULL)
  801.     {
  802.         hr = E_OUTOFMEMORY;
  803.         goto e_Exit;
  804.     }
  805.  
  806.     pdeMesh->dwTexCoordsCalculated = m_dwTexCoordsShown;
  807.  
  808.     cchFileName = strlen(szFilename);
  809.     if (cchFileName < 2)
  810.     {
  811.         hr = E_FAIL;
  812.         goto e_Exit;
  813.     }
  814.  
  815.     // reset skinning palette size to 255 when loading
  816.     m_iPaletteSize = x_iDefaultSkinningPaletteSize;
  817.  
  818.     pdeMesh->pframeRoot = new SFrame();
  819.     if (pdeMesh->pframeRoot == NULL)
  820.     {
  821.         hr = E_OUTOFMEMORY;
  822.         goto e_Exit;
  823.     }
  824.  
  825.     hr = D3DXLoadMeshHierarchyFromX(szFilename, D3DXMESH_MANAGED, m_pDevice, &Alloc, NULL, (LPD3DXFRAME*)&(pdeMesh->pframeRoot->pframeFirstChild), &pdeMesh->m_pAnimMixer);
  826.     if (FAILED(hr))
  827.         goto e_Exit;
  828.  
  829.     // the root cannot have any meshes, it is there just for
  830.     //   mouse stuff (rot/tran)
  831.     if (pdeMesh->pframeRoot->pmcMesh != NULL)
  832.     {
  833.         SFrame *pframeNew;
  834.  
  835.         pframeNew = new SFrame();
  836.         if (pframeNew == NULL)
  837.         {
  838.             hr = E_OUTOFMEMORY;
  839.             goto e_Exit;
  840.         }
  841.  
  842.         pframeNew->pframeFirstChild = pdeMesh->pframeRoot;
  843.         pdeMesh->pframeRoot = pframeNew;
  844.     }
  845.  
  846.     hr = FindBones(pdeMesh->pframeRoot, pdeMesh);
  847.     if (FAILED(hr))
  848.         goto e_Exit;
  849.  
  850.     // replace the head, only one scene loaded at a time
  851.     delete m_pdeHead;
  852.     m_pdeHead = pdeMesh;
  853.  
  854.  
  855.     delete []pdeMesh->szName;
  856.     pdeMesh->szName = new char[cchFileName+1];
  857.     if (pdeMesh->szName == NULL)
  858.     {
  859.         hr = E_OUTOFMEMORY;
  860.         goto e_Exit;
  861.     }
  862.     memcpy(pdeMesh->szName, szFilename, cchFileName+1);
  863.  
  864.     SelectDrawElement(pdeMesh);
  865.     SelectFrame(pdeMesh->pframeRoot, pdeMesh->pframeRoot->pmcMesh);
  866.  
  867.     hr = CalculateBoundingSphere(pdeMesh);
  868.     if (FAILED(hr))
  869.         goto e_Exit;
  870.  
  871.     hr = InitViews(pdeMesh->pframeRoot, pdeMesh);
  872.     if (FAILED(hr))
  873.         goto e_Exit;
  874.  
  875.     hr = SetupOrigMatrices(pdeMesh->pframeRoot);
  876.     if (FAILED(hr))
  877.         goto e_Exit;
  878.  
  879.     SetProjectionMatrix();
  880.  
  881.     m_pdeSelected->fCurTime = 0.0f;
  882.     m_pdeSelected->fMaxTime = 200.0f;
  883.  
  884.     D3DXMatrixTranslation(&m_pdeSelected->pframeRoot->matRot,
  885.                                 -pdeMesh->vCenter.x, -pdeMesh->vCenter.y, -pdeMesh->vCenter.z);
  886.     m_pdeSelected->pframeRoot->matRotOrig = m_pdeSelected->pframeRoot->matRot;
  887.  
  888. e_Exit:
  889.  
  890.     if (FAILED(hr))
  891.     {
  892.                 delete pdeMesh;
  893.     }
  894.  
  895.     return hr;
  896. }
  897.  
  898.  
  899. HRESULT
  900. MergeMeshes
  901.     (
  902.     SFrame *pframe, 
  903.     LPDIRECT3DDEVICE9 pDevice,    
  904.     LPD3DXMESH *ppMeshMerged, 
  905.     LPD3DXBUFFER *ppbufAdjacencyMerged,
  906.     LPD3DXBUFFER *ppbufMaterialsMerged,
  907.     DWORD *pcMaterialsMerged
  908.     );
  909.  
  910. namespace GXU
  911. {
  912. HRESULT WINAPI
  913.     LoadMeshFromM(
  914.         IStream *pstream,
  915.         DWORD options,
  916.         DWORD fvf,
  917.         LPDIRECT3DDEVICE9 pD3D,
  918.         LPD3DXMESH *ppMesh,
  919.         LPD3DXBUFFER *ppbufAdjacency);
  920. }
  921.  
  922. HRESULT
  923. CalculateSum(SFrame *pframe, D3DXMATRIX *pmatCur, D3DXVECTOR3 *pvCenter, UINT *pcVertices)
  924. {
  925.     HRESULT hr = S_OK;
  926.     PBYTE pbPoints = NULL;
  927.     LPDIRECT3DVERTEXBUFFER9 pVertexBuffer = NULL;
  928.     UINT cVerticesLocal = 0;
  929.     PBYTE pbCur;
  930.     D3DXVECTOR3 *pvCur;
  931.     D3DXVECTOR3 vTransformedCur;
  932.     UINT iPoint;
  933.     SMeshContainer *pmcCur;
  934.     SFrame *pframeCur;
  935.     UINT cVertices;
  936.     D3DXMATRIX matLocal;
  937.     CD3DXCrackDecl1 cd;
  938.     D3DVERTEXELEMENT9 pDecl[MAX_FVF_DECL_SIZE];
  939.  
  940.     D3DXMatrixMultiply(&matLocal, &pframe->matRot, pmatCur);
  941.  
  942.     pmcCur = pframe->pmcMesh;
  943.     while (pmcCur != NULL)
  944.     {
  945.         pmcCur->ptmDrawMesh->GetDeclaration(pDecl);
  946.         cd.SetDeclaration(pDecl);
  947.  
  948.         cVertices = pmcCur->ptmDrawMesh->GetNumVertices();
  949.  
  950.             hr = pmcCur->ptmDrawMesh->GetVertexBuffer(&pVertexBuffer);
  951.         if (FAILED(hr))
  952.             goto e_Exit;
  953.  
  954.         hr = pVertexBuffer->Lock(0,0, (PVOID*)&pbPoints, D3DLOCK_NOSYSLOCK );
  955.         if (FAILED(hr))
  956.             goto e_Exit;
  957.  
  958.         for( iPoint=0, pbCur = pbPoints; iPoint < cVertices; iPoint++, pbCur += cd.m_cBytesPerVertex )
  959.         {
  960.             pvCur = cd.PvGetPosition(pbCur);
  961.  
  962.             if ((pvCur->x != 0.0) || (pvCur->y != 0.0) || (pvCur->z != 0.0))
  963.             {
  964.                 cVerticesLocal++;
  965.  
  966.                 D3DXVec3TransformCoord(&vTransformedCur, pvCur, &matLocal);
  967.  
  968.                 pvCenter->x += vTransformedCur.x;
  969.                 pvCenter->y += vTransformedCur.y;
  970.                 pvCenter->z += vTransformedCur.z;
  971.             }
  972.         }
  973.  
  974.  
  975.  
  976.         // calculate the bounding box after calculating part of the global sphere calculation
  977.         hr = D3DXComputeBoundingBox((D3DXVECTOR3*)pbPoints, 
  978.                         cVertices, 
  979.                         cd.m_cBytesPerVertex, 
  980.                         &pmcCur->m_vBoundingBoxMin,
  981.                         &pmcCur->m_vBoundingBoxMax);
  982.         if (FAILED(hr))
  983.             goto e_Exit;
  984.  
  985.         pVertexBuffer->Unlock();
  986.         GXRELEASE(pVertexBuffer);
  987.         pbPoints = NULL;
  988.  
  989.         pmcCur = (SMeshContainer*)pmcCur->pNextMeshContainer;
  990.     }
  991.  
  992.     *pcVertices += cVerticesLocal;
  993.  
  994.     pframeCur = pframe->pframeFirstChild;
  995.     while (pframeCur != NULL)
  996.     {
  997.         hr = CalculateSum(pframeCur, &matLocal, pvCenter, pcVertices);
  998.         if (FAILED(hr))
  999.             goto e_Exit;
  1000.  
  1001.         pframeCur = pframeCur->pframeSibling;
  1002.     }
  1003.  
  1004. e_Exit:
  1005.     if (pbPoints != NULL)
  1006.     {
  1007.         GXASSERT(pVertexBuffer != NULL);
  1008.         pVertexBuffer->Unlock();
  1009.     }
  1010.     GXRELEASE(pVertexBuffer);
  1011.  
  1012.     return hr;
  1013. }
  1014.  
  1015. HRESULT
  1016. CalculateRadius(SFrame *pframe, D3DXMATRIX *pmatCur, D3DXVECTOR3 *pvCenter, float *pfRadiusSq)
  1017. {
  1018.     HRESULT hr = S_OK;
  1019.     PBYTE pbPoints = NULL;
  1020.     LPDIRECT3DVERTEXBUFFER9 pVertexBuffer = NULL;
  1021.     PBYTE pbCur;
  1022.     D3DXVECTOR3 *pvCur;
  1023.     D3DXVECTOR3 vDist;;
  1024.     UINT iPoint;
  1025.     UINT cVertices;
  1026.     SMeshContainer *pmcCur;
  1027.     SFrame *pframeCur;
  1028.     float fRadiusLocalSq;
  1029.     float fDistSq;
  1030.     D3DXMATRIX matLocal;
  1031.     CD3DXCrackDecl1 cd;
  1032.     D3DVERTEXELEMENT9 pDecl[MAX_FVF_DECL_SIZE];
  1033.  
  1034.     D3DXMatrixMultiply(&matLocal, &pframe->matRot, pmatCur);
  1035.  
  1036.     pmcCur = pframe->pmcMesh;
  1037.     fRadiusLocalSq = *pfRadiusSq;
  1038.     while (pmcCur != NULL)
  1039.     {
  1040.         pmcCur->ptmDrawMesh->GetDeclaration(pDecl);
  1041.         cd.SetDeclaration(pDecl);
  1042.  
  1043.         cVertices = pmcCur->ptmDrawMesh->GetNumVertices();
  1044.  
  1045.             hr = pmcCur->ptmDrawMesh->GetVertexBuffer(&pVertexBuffer);
  1046.         if (FAILED(hr))
  1047.             goto e_Exit;
  1048.  
  1049.         hr = pVertexBuffer->Lock(0,0, (PVOID*)&pbPoints, D3DLOCK_NOSYSLOCK );
  1050.         if (FAILED(hr))
  1051.             goto e_Exit;
  1052.  
  1053.         for( iPoint=0, pbCur = pbPoints; iPoint < cVertices; iPoint++, pbCur += cd.m_cBytesPerVertex )
  1054.         {
  1055.             pvCur = cd.PvGetPosition(pbCur);
  1056.  
  1057.             if ((pvCur->x == 0.0) && (pvCur->y == 0.0) && (pvCur->z == 0.0))
  1058.                 continue;
  1059.  
  1060.             D3DXVec3TransformCoord(&vDist, pvCur, &matLocal);
  1061.  
  1062.             vDist -= *pvCenter;
  1063.  
  1064.             fDistSq = D3DXVec3LengthSq(&vDist);
  1065.  
  1066.             if( fDistSq > fRadiusLocalSq )
  1067.                 fRadiusLocalSq = fDistSq;
  1068.         }
  1069.  
  1070.  
  1071.         pVertexBuffer->Unlock();
  1072.         pbPoints = NULL;
  1073.         GXRELEASE(pVertexBuffer);
  1074.  
  1075.         pmcCur = (SMeshContainer*)pmcCur->pNextMeshContainer;
  1076.     }
  1077.  
  1078.     *pfRadiusSq = fRadiusLocalSq;
  1079.  
  1080.     pframeCur = pframe->pframeFirstChild;
  1081.     while (pframeCur != NULL)
  1082.     {
  1083.         hr = CalculateRadius(pframeCur, &matLocal, pvCenter, pfRadiusSq);
  1084.         if (FAILED(hr))
  1085.             goto e_Exit;
  1086.  
  1087.         pframeCur = pframeCur->pframeSibling;
  1088.     }
  1089.  
  1090. e_Exit:
  1091.     if (pbPoints != NULL)
  1092.     {
  1093.         GXASSERT(pVertexBuffer != NULL);
  1094.         pVertexBuffer->Unlock();
  1095.     }
  1096.  
  1097.     GXRELEASE(pVertexBuffer);
  1098.  
  1099.     return hr;
  1100. }
  1101.  
  1102. HRESULT
  1103. CalculateBoundingSphere(SDrawElement *pdeCur)
  1104. {
  1105.     HRESULT hr = S_OK;
  1106.     D3DXVECTOR3 vCenter(0,0,0);
  1107.     UINT cVertices = 0;
  1108.     float fRadiusSq = 0;
  1109.     D3DXMATRIX matCur;
  1110.  
  1111.     D3DXMatrixIdentity(&matCur);
  1112.     hr = CalculateSum(pdeCur->pframeRoot, &matCur, &vCenter, &cVertices);
  1113.     if (FAILED(hr))
  1114.         goto e_Exit;
  1115.  
  1116.     if (cVertices > 0)
  1117.     {
  1118.         vCenter /= (float)cVertices;
  1119.  
  1120.         D3DXMatrixIdentity(&matCur);
  1121.         hr = CalculateRadius(pdeCur->pframeRoot, &matCur, &vCenter, &fRadiusSq);
  1122.         if (FAILED(hr))
  1123.             goto e_Exit;
  1124.     }
  1125.  
  1126.     pdeCur->fRadius = (float)sqrt((double)fRadiusSq);;
  1127.     pdeCur->vCenter = vCenter;
  1128. e_Exit:
  1129.     return hr;
  1130. }
  1131.  
  1132. HRESULT
  1133. CalculateBoundingSphereMC(SMeshContainer *pmcMesh, LPD3DXVECTOR3 pCenter, FLOAT *pfRadius)
  1134. {
  1135.     LPVOID pbVertices;
  1136.  
  1137.     pmcMesh->ptmDrawMesh->LockVertexBuffer(D3DLOCK_READONLY, &pbVertices);
  1138.  
  1139.     // UNDONE UNDONE - to handle general FVFs, this needs to add the offset of the position into pbVertices
  1140.     //   this only works with FLOAT3 positions anyhow, so this function isn't useful in some cases
  1141.     D3DXComputeBoundingSphere((D3DXVECTOR3*)pbVertices, pmcMesh->ptmDrawMesh->GetNumVertices(), pmcMesh->ptmDrawMesh->GetNumBytesPerVertex(), pCenter, pfRadius);
  1142.  
  1143.     pmcMesh->ptmDrawMesh->UnlockVertexBuffer();
  1144.  
  1145.     return S_OK;;
  1146. }
  1147.  
  1148. HRESULT
  1149. TrivialData::DeleteSelectedMesh()
  1150. {
  1151.     if (m_pdeSelected != NULL)
  1152.     {
  1153.         SDrawElement *pdeCur = m_pdeHead;
  1154.         SDrawElement *pdePrev = NULL;
  1155.         while ((pdeCur != NULL) && (pdeCur != m_pdeSelected))
  1156.         {
  1157.             pdePrev = pdeCur;
  1158.             pdeCur = pdeCur->pdeNext;
  1159.         }
  1160.  
  1161.         GXASSERT(pdeCur != NULL);
  1162.         GXASSERT(pdeCur == m_pdeSelected);
  1163.  
  1164.         if (pdePrev == NULL)
  1165.         {
  1166.             m_pdeHead = m_pdeHead->pdeNext;
  1167.         }
  1168.         else
  1169.         {
  1170.             pdePrev->pdeNext = pdeCur->pdeNext;
  1171.         }
  1172.  
  1173.         m_pdeSelected->pdeNext = NULL;
  1174.         delete m_pdeSelected;
  1175.  
  1176.         m_dwVertexSelected = UNUSED32;
  1177.         m_dwFaceSelected = UNUSED32;
  1178.  
  1179.         SelectDrawElement(m_pdeHead);
  1180.  
  1181.         UpdateMeshMenu();
  1182.  
  1183.         if (m_pdeHead == NULL)
  1184.         {
  1185.             SendMessage(m_hwndStatus, SB_SETTEXT , (WPARAM) 1, (LPARAM) "Nothing Selected"); 
  1186.             SendMessage(m_hwndStatus, SB_SETTEXT , (WPARAM) 2, (LPARAM) ""); 
  1187.             SendMessage(m_hwndStatus, SB_SETTEXT , (WPARAM) 3, (LPARAM) ""); 
  1188.             SendMessage(m_hwndStatus, SB_SETTEXT , (WPARAM) 4, (LPARAM) ""); 
  1189.             SendMessage(m_hwndStatus, SB_SETTEXT , (WPARAM) 5, (LPARAM) ""); 
  1190.         }
  1191.     }
  1192.  
  1193.     return S_OK;
  1194. }
  1195.  
  1196. char *SkipWhiteSpace(char *sz)
  1197. {
  1198.     while ((*sz != '\0') && ((*sz == ' ') || (*sz == '\t') || (*sz == '\n')))
  1199.         sz++;
  1200.  
  1201.     return sz;
  1202. }
  1203.  
  1204. HRESULT
  1205. TrivialData::AddMeshToDrawList
  1206. (
  1207.     char *szName,
  1208.     LPD3DXMESH ptmMesh,
  1209.     LPD3DXPMESH ptmPMesh,
  1210.     LPD3DXBUFFER pbufAdjacency,
  1211.     LPD3DXBUFFER pbufMaterials,
  1212.     LPD3DXBUFFER pbufEffectInstances,
  1213.     UINT cMaterials
  1214. )
  1215. {
  1216.     HRESULT hr = S_OK;
  1217.     SDrawElement *pdeMesh = NULL;
  1218.     SMeshContainer *pmcMesh;
  1219.     UINT cFaces;
  1220.     LPD3DXMATERIAL rgMaterials;
  1221.     LPD3DXEFFECTINSTANCE rgEffects = NULL;
  1222.     UINT iMaterial;
  1223.     LPDIRECT3DTEXTURE9 ptex;
  1224.     UINT cchName;
  1225.     UINT cchFilename;
  1226.     D3DXMATRIX matRHtoLH;
  1227.     SFrame *pframeMesh;
  1228.     LPD3DXEFFECT pEffect;
  1229.     D3DXEFFECTINSTANCE EffectInstance;
  1230.     BOOL bUsesTangents = FALSE;
  1231.  
  1232.     GXASSERT((ptmMesh != NULL) || (ptmPMesh != NULL));
  1233.     GXASSERT((ptmMesh == NULL) || (ptmPMesh == NULL));
  1234.  
  1235.     pdeMesh = new SDrawElement();
  1236.     if (pdeMesh == NULL)
  1237.     {
  1238.         hr = E_OUTOFMEMORY;
  1239.         goto e_Exit;
  1240.     }
  1241.     pdeMesh->dwTexCoordsCalculated = m_dwTexCoordsShown;
  1242.  
  1243.     pdeMesh->pframeRoot = new SFrame();
  1244.     if (pdeMesh->pframeRoot == NULL)
  1245.     {
  1246.         hr = E_OUTOFMEMORY;
  1247.         goto e_Exit;
  1248.     }
  1249.  
  1250.     // add a second level to be similar to mesh hierarchys
  1251.     //   always a frame even if the root one (mouse stuff) is pulled
  1252.     pdeMesh->pframeRoot->pframeFirstChild = new SFrame();
  1253.     if (pdeMesh->pframeRoot->pframeFirstChild == NULL)
  1254.     {
  1255.         hr = E_OUTOFMEMORY;
  1256.         goto e_Exit;
  1257.     }
  1258.     pframeMesh = pdeMesh->pframeRoot->pframeFirstChild;
  1259.  
  1260.     pframeMesh->pmcMesh = new SMeshContainer();
  1261.     if (pframeMesh->pmcMesh == NULL)
  1262.     {
  1263.         hr = E_OUTOFMEMORY;
  1264.         goto e_Exit;
  1265.     }
  1266.  
  1267.     pmcMesh = pframeMesh->pmcMesh;
  1268.  
  1269.     if ((pbufMaterials == NULL) || (cMaterials == 0))
  1270.     {
  1271.         pmcMesh->m_cAttributeGroups = 1;
  1272.         pmcMesh->NumMaterials = 1;
  1273.  
  1274.         pmcMesh->m_rgpfxAttributes = new LPD3DXEFFECT[pmcMesh->NumMaterials];
  1275.         pmcMesh->m_rgEffectInfo = new SEffectInfo[pmcMesh->NumMaterials];
  1276.         pmcMesh->rgMaterials = new D3DXMATERIAL[pmcMesh->NumMaterials];
  1277.         if ((pmcMesh->m_rgpfxAttributes == NULL) || (pmcMesh->m_rgEffectInfo == NULL) || (pmcMesh->rgMaterials == NULL))
  1278.         {
  1279.             hr = E_OUTOFMEMORY;
  1280.             goto e_Exit;
  1281.         }
  1282.  
  1283.         D3DMATERIAL9 mat;
  1284.         memset(&mat, 0, sizeof(D3DMATERIAL9));
  1285.         mat.Diffuse.r = 0.5f;
  1286.         mat.Diffuse.g = 0.5f;
  1287.         mat.Diffuse.b = 0.5f;
  1288.         mat.Specular = mat.Diffuse;
  1289.  
  1290.         pmcMesh->rgMaterials[0].MatD3D = mat;
  1291.         pmcMesh->rgMaterials[0].pTextureFilename = NULL;
  1292.  
  1293.         memset(&EffectInstance, 0, sizeof(D3DXEFFECTINSTANCE));
  1294.  
  1295.         // create effect instance will create a "default" effect when pEffectFilename is NULL
  1296.         hr = D3DXCreateEffectInstance(&EffectInstance, m_pDevice, &pmcMesh->m_rgpfxAttributes[0], NULL);
  1297.         if (FAILED(hr))
  1298.             goto e_Exit;
  1299.  
  1300.         hr = GenerateEffectInfo(pmcMesh->m_rgpfxAttributes[0], &pmcMesh->m_rgEffectInfo[0]);
  1301.         if (FAILED(hr))
  1302.             goto e_Exit;
  1303.  
  1304.         // set our "default" material colors
  1305.         pmcMesh->m_rgpfxAttributes[0]->SetVector("Ambient", (LPD3DXVECTOR4)&mat.Ambient);
  1306.         pmcMesh->m_rgpfxAttributes[0]->SetVector("Diffuse", (LPD3DXVECTOR4)&mat.Diffuse);
  1307.         pmcMesh->m_rgpfxAttributes[0]->SetVector("Specular", (LPD3DXVECTOR4)&mat.Specular);            
  1308.     }
  1309.     else
  1310.     {
  1311.         pmcMesh->m_cAttributeGroups = cMaterials;
  1312.         pmcMesh->NumMaterials = cMaterials;
  1313.  
  1314.         pmcMesh->m_rgpfxAttributes = new LPD3DXEFFECT[pmcMesh->NumMaterials];
  1315.         pmcMesh->m_rgEffectInfo = new SEffectInfo[pmcMesh->NumMaterials];
  1316.         pmcMesh->rgMaterials = new D3DXMATERIAL[pmcMesh->NumMaterials];
  1317.         if ((pmcMesh->m_rgpfxAttributes == NULL) || (pmcMesh->m_rgEffectInfo == NULL) || (pmcMesh->rgMaterials == NULL))
  1318.         {
  1319.             hr = E_OUTOFMEMORY;
  1320.             goto e_Exit;
  1321.         }
  1322.         memset(pmcMesh->rgMaterials, 0, sizeof(D3DXMATERIAL) * cMaterials);
  1323.         memset(pmcMesh->m_rgpfxAttributes, 0, sizeof(LPD3DXEFFECT) * cMaterials);
  1324.  
  1325.         rgMaterials = (LPD3DXMATERIAL)pbufMaterials->GetBufferPointer();
  1326.  
  1327.         if (pbufEffectInstances != NULL)
  1328.         {
  1329.             rgEffects = (LPD3DXEFFECTINSTANCE)pbufEffectInstances->GetBufferPointer();
  1330.         }
  1331.  
  1332.         for (iMaterial = 0; iMaterial < cMaterials; iMaterial++)
  1333.         {
  1334.             pmcMesh->rgMaterials[iMaterial].MatD3D = rgMaterials[iMaterial].MatD3D;
  1335.  
  1336.             if (rgMaterials[iMaterial].pTextureFilename != NULL)
  1337.             {
  1338.                 cchFilename = strlen(rgMaterials[iMaterial].pTextureFilename) + 1;
  1339.                 pmcMesh->rgMaterials[iMaterial].pTextureFilename = new char[cchFilename];
  1340.                 if (pmcMesh->rgMaterials[iMaterial].pTextureFilename == NULL)
  1341.                 {
  1342.                     hr = E_OUTOFMEMORY;
  1343.                     goto e_Exit;
  1344.                 }
  1345.                 memcpy(pmcMesh->rgMaterials[iMaterial].pTextureFilename,
  1346.                                 rgMaterials[iMaterial].pTextureFilename, sizeof(char) * cchFilename);
  1347.             }
  1348.  
  1349.             if (rgEffects != NULL)
  1350.             {
  1351.                 hr = D3DXCreateEffectInstance(&rgEffects[iMaterial], m_pDevice, &pmcMesh->m_rgpfxAttributes[iMaterial], NULL);
  1352.                 if (FAILED(hr))
  1353.                     goto e_Exit;
  1354.             }
  1355.             else  // only used for text and other shape type things
  1356.             {
  1357.                 // should not be used for anything using a texture filename
  1358.                 GXASSERT(pmcMesh->rgMaterials[iMaterial].pTextureFilename == NULL);
  1359.  
  1360.                 memset(&EffectInstance, 0, sizeof(D3DXEFFECTINSTANCE));
  1361.  
  1362.                 // create effect instance will create a "default" effect when pEffectFilename is NULL
  1363.                 hr = D3DXCreateEffectInstance(&EffectInstance, m_pDevice, &pmcMesh->m_rgpfxAttributes[iMaterial], NULL);
  1364.                 if (FAILED(hr))
  1365.                     goto e_Exit;
  1366.  
  1367.                 // set our "default" material colors
  1368.                 pmcMesh->m_rgpfxAttributes[iMaterial]->SetVector("Ambient", (LPD3DXVECTOR4)&pmcMesh->rgMaterials[iMaterial].MatD3D.Ambient);
  1369.                 pmcMesh->m_rgpfxAttributes[iMaterial]->SetVector("Diffuse", (LPD3DXVECTOR4)&pmcMesh->rgMaterials[iMaterial].MatD3D.Diffuse);
  1370.                 pmcMesh->m_rgpfxAttributes[iMaterial]->SetVector("Specular", (LPD3DXVECTOR4)&pmcMesh->rgMaterials[iMaterial].MatD3D.Specular);            
  1371.             }
  1372.  
  1373.             hr = GenerateEffectInfo(pmcMesh->m_rgpfxAttributes[iMaterial], &pmcMesh->m_rgEffectInfo[iMaterial]);
  1374.             if (FAILED(hr))
  1375.                 goto e_Exit;
  1376.  
  1377.             D3DXTECHNIQUE_DESC TechniqueDesc;
  1378.             D3DXPASS_DESC PassDesc;
  1379.             D3DXHANDLE hPass;
  1380.             D3DXHANDLE hTechnique;
  1381.             hTechnique = pmcMesh->m_rgpfxAttributes[iMaterial]->GetCurrentTechnique();
  1382.             pmcMesh->m_rgpfxAttributes[iMaterial]->GetTechniqueDesc(hTechnique, &TechniqueDesc);
  1383.             for( UINT iPass = 0; iPass < TechniqueDesc.Passes; iPass++ )
  1384.             {
  1385.                 hPass = pmcMesh->m_rgpfxAttributes[iMaterial]->GetPass( hTechnique, iPass );
  1386.                 pmcMesh->m_rgpfxAttributes[iMaterial]->GetPassDesc( hPass, &PassDesc );
  1387.  
  1388.                 UINT NumVSSemanticsUsed;
  1389.                 D3DXSEMANTIC pVSSemantics[MAXD3DDECLLENGTH];
  1390.  
  1391.                 if( !PassDesc.pVertexShaderFunction ||
  1392.                     FAILED( D3DXGetShaderInputSemantics( PassDesc.pVertexShaderFunction, pVSSemantics, &NumVSSemanticsUsed ) ) )
  1393.                 {
  1394.                     continue;
  1395.                 }
  1396.  
  1397.                 for( UINT iSem = 0; iSem < NumVSSemanticsUsed; iSem++ )
  1398.                 {
  1399.                     if( pVSSemantics[iSem].Usage == D3DDECLUSAGE_TANGENT )
  1400.                     {
  1401.                         bUsesTangents = TRUE;
  1402.                         break;
  1403.                     }
  1404.                 }
  1405.             }
  1406.         }
  1407.     }
  1408.  
  1409.  
  1410.     if (ptmMesh != NULL)
  1411.     {
  1412.         D3DVERTEXELEMENT9 pDecl[MAX_FVF_DECL_SIZE];
  1413.         CD3DXCrackDecl1 cd;
  1414.  
  1415.         // down cast to the base mesh type (could also QI for it)
  1416.         pmcMesh->pMesh = ptmMesh;
  1417.         pmcMesh->pMesh->AddRef();
  1418.  
  1419.         hr = ptmMesh->GetDeclaration(pDecl);
  1420.         if (FAILED(hr))
  1421.             goto e_Exit;
  1422.         
  1423.         cd.SetDeclaration(pDecl);
  1424.  
  1425.         if (bUsesTangents && (NULL == cd.GetSemanticElement(D3DDECLUSAGE_TANGENT, 0)))
  1426.         {
  1427.             LPD3DXMESH pMeshTemp = pmcMesh->pMesh;
  1428.  
  1429.             AddTangent(cd, pDecl);
  1430.  
  1431.             pmcMesh->pMesh = NULL;
  1432.  
  1433.             // clone in the space for the new normal
  1434.             hr = pMeshTemp->CloneMesh(pMeshTemp->GetOptions(), pDecl, m_pDevice, &pmcMesh->pMesh);
  1435.  
  1436.             GXRELEASE(pMeshTemp);
  1437.  
  1438.             if (FAILED(hr))
  1439.                 goto e_Exit;
  1440.  
  1441.             hr = D3DXComputeTangent( pmcMesh->pMesh, 0, 0, D3DX_DEFAULT, TRUE, NULL );
  1442.             if (FAILED(hr))
  1443.                 goto e_Exit;
  1444.         }
  1445.  
  1446.         pmcMesh->ptmDrawMesh = pmcMesh->pMesh;
  1447.         pmcMesh->ptmDrawMesh->AddRef();
  1448.  
  1449.         pmcMesh->bPMMeshMode = false;
  1450.         pmcMesh->bSimplifyMode = false;
  1451.     }
  1452.     else
  1453.     {
  1454.         GXASSERT(ptmPMesh != NULL);
  1455.  
  1456.         pmcMesh->pPMMesh = ptmPMesh;
  1457.         pmcMesh->pPMMesh->AddRef();
  1458.         pmcMesh->ptmDrawMesh = ptmPMesh;
  1459.         pmcMesh->ptmDrawMesh->AddRef();
  1460.  
  1461.         pmcMesh->m_cMinVerticesSoft = ptmPMesh->GetMinVertices();
  1462.         pmcMesh->m_cMaxVerticesSoft = ptmPMesh->GetMaxVertices();
  1463.  
  1464.         pmcMesh->bPMMeshMode = true;
  1465.         pmcMesh->bSimplifyMode = false;
  1466.     }
  1467.  
  1468. #if 0
  1469.     hr = ApplyEffectsToMesh(pmcMesh);
  1470.     if (FAILED(hr))
  1471.         goto e_Exit;
  1472. #endif
  1473.  
  1474.     cFaces = pmcMesh->ptmDrawMesh->GetNumFaces();
  1475.  
  1476.     // allocate a local buffer to put the adjacency data in
  1477.     pmcMesh->rgdwAdjacency = new DWORD[cFaces * 3];
  1478.     if (pmcMesh->rgdwAdjacency == NULL) 
  1479.     {
  1480.         hr = E_OUTOFMEMORY;
  1481.         goto e_Exit;
  1482.     }
  1483.  
  1484.     if (pbufAdjacency != NULL)
  1485.     {
  1486.         GXASSERT(cFaces * 3 * sizeof(DWORD) == pbufAdjacency->GetBufferSize());
  1487.  
  1488.         // copy the adjacency data into the local buffer, could keep the buffer around, but not needed
  1489.         memcpy(pmcMesh->rgdwAdjacency, pbufAdjacency->GetBufferPointer(),
  1490.                                 pbufAdjacency->GetBufferSize());
  1491.     }
  1492.     else
  1493.     {
  1494.         memset(pmcMesh->rgdwAdjacency, 0xff, sizeof(DWORD) * 3 * cFaces);
  1495.     }
  1496.  
  1497. #if 0
  1498.     // then link into the draw list
  1499.     pdeMesh->pdeNext = m_pdeHead;
  1500.     m_pdeHead = pdeMesh;
  1501. #else
  1502.     // replace the head, only one scene loaded at a time
  1503.     delete m_pdeHead;
  1504.     m_pdeHead = pdeMesh;
  1505. #endif
  1506.  
  1507.     cchName = strlen(szName) + 1;
  1508.     pdeMesh->szName = new char[cchName];
  1509.     if (pdeMesh->szName == NULL)
  1510.     {
  1511.             hr = E_OUTOFMEMORY;
  1512.             goto e_Exit;
  1513.     }
  1514.     memcpy(pdeMesh->szName, szName, cchName);
  1515.  
  1516.     // select the new pde, pmc and pframe as current
  1517.     SelectDrawElement(pdeMesh);
  1518.     SelectFrame(pframeMesh, NULL);
  1519.     GXASSERT(m_pmcSelectedMesh == pmcMesh);
  1520.  
  1521.     Optimize(D3DXMESHOPT_ATTRSORT);
  1522.  
  1523.     hr = CalculateBoundingSphere(pdeMesh);
  1524.     if (FAILED(hr))
  1525.         goto e_Exit;
  1526.  
  1527.     // set the mesh radius/center into the effect
  1528.     for (iMaterial = 0; iMaterial < pmcMesh->NumMaterials; iMaterial++)
  1529.     {
  1530.         SetEffectMeshInfo(pmcMesh->m_rgpfxAttributes[iMaterial], &pdeMesh->vCenter, pdeMesh->fRadius);
  1531.     }
  1532.  
  1533.     D3DXMatrixTranslation(&pdeMesh->pframeRoot->matRot,
  1534.                                 -pdeMesh->vCenter.x, -pdeMesh->vCenter.y, -pdeMesh->vCenter.z);
  1535.     pdeMesh->pframeRoot->matRotOrig = pdeMesh->pframeRoot->matRot;
  1536.  
  1537.     if (pmcMesh->pMesh != NULL)
  1538.     {
  1539.         // make sure there is an attribute table
  1540.         Optimize(D3DXMESHOPT_ATTRSORT);
  1541.  
  1542.         hr = pmcMesh->UpdateViews(pdeMesh);
  1543.         if (FAILED(hr))
  1544.             goto e_Exit;
  1545.     }
  1546.  
  1547.     SetProjectionMatrix();
  1548.  
  1549.     // setup attribute table
  1550.     pmcMesh->ptmDrawMesh->GetAttributeTable(NULL, &pmcMesh->m_caeAttributeTable);
  1551.  
  1552.     delete pmcMesh->m_rgaeAttributeTable;
  1553.     pmcMesh->m_rgaeAttributeTable = new D3DXATTRIBUTERANGE[pmcMesh->m_caeAttributeTable];
  1554.     if (pmcMesh->m_rgaeAttributeTable == NULL)
  1555.     {
  1556.         hr = E_OUTOFMEMORY;
  1557.         goto e_Exit;
  1558.     }
  1559.  
  1560.     pmcMesh->ptmDrawMesh->GetAttributeTable(pmcMesh->m_rgaeAttributeTable, &pmcMesh->m_caeAttributeTable);
  1561.  
  1562. e_Exit:
  1563.  
  1564.     if (FAILED(hr))
  1565.         delete pdeMesh;
  1566.  
  1567.     return hr;
  1568. }
  1569.  
  1570. struct SLoadMeshData
  1571. {
  1572.     BOOL bFlattenHierarchy;
  1573. };
  1574.  
  1575. UINT_PTR CALLBACK DlgProcLoadMesh(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  1576. {
  1577.     SLoadMeshData *plmdData;
  1578.     LPOPENFILENAME lpOFN;
  1579.  
  1580.     switch (message)
  1581.     {
  1582.         case WM_INITDIALOG:
  1583.             // Save off the long pointer to the OPENFILENAME structure.
  1584.             SetWindowLongPtr(hDlg, DWLP_USER, lParam);
  1585.  
  1586.             lpOFN = (LPOPENFILENAME)lParam;
  1587.             plmdData = (SLoadMeshData *)lpOFN->lCustData;
  1588.             SendDlgItemMessage(hDlg, IDC_FLATTENHIERARCHY, BM_SETCHECK, plmdData->bFlattenHierarchy ? BST_CHECKED : BST_UNCHECKED, 0);
  1589.             break;
  1590.  
  1591.         case WM_DESTROY:
  1592.             lpOFN = (LPOPENFILENAME)GetWindowLongPtr(hDlg, DWLP_USER);
  1593.             plmdData = (SLoadMeshData *)lpOFN->lCustData;
  1594.  
  1595.             plmdData->bFlattenHierarchy = (BST_CHECKED == SendDlgItemMessage(hDlg, IDC_FLATTENHIERARCHY, BM_GETCHECK, 0, 0));
  1596.             break;
  1597.  
  1598.         default:
  1599.             return FALSE;
  1600.     }
  1601.     return TRUE;
  1602. }
  1603.  
  1604. HRESULT
  1605. TrivialData::LoadNewMesh()
  1606. {
  1607.     HRESULT hr = S_OK;
  1608.     OPENFILENAME ofn;
  1609.     memset( &ofn, 0, sizeof(ofn) );
  1610.     SLoadMeshData lmdData;
  1611.     static TCHAR file[256];
  1612.     static TCHAR fileTitle[256];
  1613.     static TCHAR filter[] =
  1614.                            TEXT("Mesh files (*.x,*.m)\0*.x;*.m\0")
  1615.                            TEXT("X files (*.x)\0*.x\0")
  1616.                            TEXT("MESH files (*.m)\0*.m\0")
  1617.                            TEXT("All Files (*.*)\0*.*\0");
  1618.     _tcscpy( file, TEXT(""));
  1619.     _tcscpy( fileTitle, TEXT(""));
  1620.  
  1621.     ofn.lStructSize       = sizeof(OPENFILENAME);
  1622.     ofn.hwndOwner         = m_hwnd;
  1623.     ofn.hInstance         = m_hInstance;
  1624.     ofn.lpstrFilter       = filter;
  1625.     ofn.lpstrCustomFilter = NULL;
  1626.     ofn.nMaxCustFilter    = 0L;
  1627.     ofn.nFilterIndex      = 1L;
  1628.     ofn.lpstrFile         = file;
  1629.     ofn.nMaxFile          = sizeof(file);
  1630.     ofn.lpstrFileTitle    = fileTitle;
  1631.     ofn.nMaxFileTitle     = sizeof(fileTitle);
  1632.     ofn.lpstrInitialDir   = NULL;
  1633.     ofn.nFileOffset       = 0;
  1634.     ofn.nFileExtension    = 0;
  1635.     ofn.lpstrDefExt       = TEXT("*.x");
  1636.     ofn.lCustData         = (LPARAM)&lmdData;
  1637.  
  1638.     ofn.lpfnHook          = DlgProcLoadMesh;
  1639.     ofn.lpTemplateName    = MAKEINTRESOURCE(IDD_LOADMESHEX);
  1640.     lmdData.bFlattenHierarchy = FALSE;
  1641.  
  1642.     ofn.Flags = OFN_ENABLESIZING | OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_ENABLETEMPLATE | OFN_ENABLEHOOK;
  1643.     if ( ! GetOpenFileName( &ofn) )
  1644.     {
  1645.         char s[40];
  1646.         DWORD dwErr = CommDlgExtendedError();
  1647.         if ( 0 != dwErr )
  1648.         {
  1649.             memset( &ofn, 0, sizeof(ofn) );
  1650.             ofn.lStructSize       = sizeof(OPENFILENAME_NT4W);
  1651.             ofn.hwndOwner         = m_hwnd;
  1652.             ofn.hInstance         = m_hInstance;
  1653.             ofn.lpstrFilter       = filter;
  1654.             ofn.lpstrCustomFilter = NULL;
  1655.             ofn.nMaxCustFilter    = 0L;
  1656.             ofn.nFilterIndex      = 1L;
  1657.             ofn.lpstrFile         = file;
  1658.             ofn.nMaxFile          = sizeof(file);
  1659.             ofn.lpstrFileTitle    = fileTitle;
  1660.             ofn.nMaxFileTitle     = sizeof(fileTitle);
  1661.             ofn.lpstrInitialDir   = NULL;
  1662.             ofn.nFileOffset       = 0;
  1663.             ofn.nFileExtension    = 0;
  1664.             ofn.lpstrDefExt       = TEXT("*.x");
  1665.             ofn.lCustData         = (LPARAM)&lmdData;
  1666.  
  1667.             ofn.lpfnHook          = DlgProcLoadMesh;
  1668.             ofn.lpTemplateName    = MAKEINTRESOURCE(IDD_LOADMESHEX);
  1669.             lmdData.bFlattenHierarchy = FALSE;
  1670.  
  1671.             ofn.Flags = OFN_ENABLESIZING | OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_ENABLETEMPLATE | OFN_ENABLEHOOK;
  1672.  
  1673.         // if the first one failed, retry with old dialog style
  1674.             if ( ! GetOpenFileName( &ofn) )
  1675.             {
  1676.                 dwErr = CommDlgExtendedError();
  1677.                 if ( 0 != dwErr )
  1678.                 {
  1679.                     sprintf( s, "GetOpenFileName failed with %x", dwErr );
  1680.                     MessageBox( m_hwnd, s, "TexWin", MB_OK | MB_SYSTEMMODAL );
  1681.                 }
  1682.  
  1683.                 goto e_Exit;
  1684.             }
  1685.         }
  1686.         else
  1687.         {
  1688.             goto e_Exit;
  1689.         }
  1690.     }
  1691.  
  1692.     hr = LoadMesh( file, lmdData.bFlattenHierarchy );
  1693.  
  1694. e_Exit:
  1695.     return hr;
  1696. }
  1697.  
  1698.  
  1699. HRESULT
  1700. TrivialData::LoadMesh( TCHAR* file, BOOL bFlattenHierarchy )
  1701. {
  1702.     LPD3DXMESH ptmMesh = NULL;
  1703.     LPD3DXMESH ptmMeshTemp = NULL;
  1704.     HRESULT hr = S_OK;
  1705.     bool b3dsFile;
  1706.     bool bXFile;
  1707.     IStream *pstream = NULL;
  1708.     DWORD dwOptions;
  1709.     int cchFileName;
  1710.     int cchFilePath;
  1711.     LPD3DXBUFFER pbufAdjacency = NULL;
  1712.     LPD3DXBUFFER pbufMaterials = NULL;
  1713.     LPD3DXBUFFER pbufEffectInstances = NULL;
  1714.     DWORD cMaterials = 0;
  1715.     char szPath[256];
  1716.     char *szTemp;
  1717.     DWORD cchPath;
  1718.     D3DVERTEXELEMENT9 pDecl[MAX_FVF_DECL_SIZE];
  1719.     CD3DXCrackDecl1 cd;
  1720.  
  1721.     // create a mesh of the correct type
  1722.     dwOptions = D3DXMESH_MANAGED;
  1723.  
  1724.     cchFileName = strlen(file);
  1725.     if (cchFileName < 2)
  1726.     {
  1727.         hr = E_FAIL;
  1728.         goto e_Exit;
  1729.     }
  1730.  
  1731.     b3dsFile = true;
  1732.     bXFile = false;
  1733.     if ((toupper(file[cchFileName - 1]) == 'M') && (file[cchFileName - 2] == '.'))
  1734.     {
  1735.         b3dsFile = false;
  1736.         bXFile = false;
  1737.     }
  1738.     else if ((toupper(file[cchFileName - 1]) == 'X') && (file[cchFileName - 2] == '.'))
  1739.     {
  1740.         b3dsFile = false;
  1741.         bXFile = true;
  1742.     }
  1743.  
  1744.     static TCHAR szFilepath[256];
  1745.     memcpy(szFilepath, file, sizeof(file));
  1746.     cchFileName = strlen(szFilepath);
  1747.     int i;
  1748.     for (i=cchFileName; i > 0; i--)
  1749.     {
  1750.         if (szFilepath[i] == '\\')
  1751.         {
  1752.             szFilepath[i] = '\0';
  1753.             break;
  1754.         }
  1755.     }
  1756.     cchFilePath = strlen(szFilepath);
  1757.  
  1758.     // if loading the hierarchy and it is an xfile (can have one)
  1759.     //   call off to hierarchy loader
  1760.     if (!bFlattenHierarchy && bXFile)
  1761.     {
  1762.         hr = LoadMeshHierarchyFromFile(file);
  1763.         if (FAILED(hr))
  1764.             goto e_Exit;
  1765.     }
  1766.     else  // either Flatten specified, or the file is already flat
  1767.     {           // do a "normal" load without the hierarchy
  1768.  
  1769.         if (bXFile)
  1770.         {
  1771.             hr = D3DXLoadMeshFromX(file, dwOptions, m_pDevice, &pbufAdjacency, &pbufMaterials, &pbufEffectInstances, &cMaterials, &ptmMesh);
  1772.             if (FAILED(hr))
  1773.                 goto e_Exit;
  1774.         }
  1775.         else if (!b3dsFile)
  1776.         {
  1777.             pstream = new CFileStream(file, true, false, &hr);
  1778.             if (FAILED(hr))
  1779.                 goto e_Exit;
  1780.  
  1781.             hr = GXU::LoadMeshFromM(pstream, dwOptions, m_dwFVF, m_pDevice, &ptmMesh, &pbufAdjacency);
  1782.             if (FAILED(hr))
  1783.                 goto e_Exit;
  1784.         }
  1785.         else 
  1786.         {
  1787.             hr = E_INVALIDARG;
  1788.             goto e_Exit;
  1789.         }
  1790.  
  1791.         cchPath = GetFullPathName(file, sizeof(szPath), szPath, &szTemp);
  1792.         if ((cchPath == 0) || (sizeof(szPath) <= cchPath))
  1793.         {
  1794.             hr = E_FAIL;
  1795.             goto e_Exit;
  1796.         }
  1797.  
  1798.         // remove the filename from the path part
  1799.         szPath[szTemp - szPath] = '\0';
  1800.  
  1801.         // set the current directory, so that textures will be searched from there
  1802.         SetCurrentDirectory(szPath);
  1803.  
  1804.         ptmMesh->GetDeclaration(pDecl);
  1805.         cd.SetDeclaration(pDecl);
  1806.  
  1807.         // if no normals in the mesh, then clone the mesh to add the normals and then compute them
  1808.         if (cd.GetSemanticElement(D3DDECLUSAGE_NORMAL, 0) == NULL)
  1809.         {
  1810.             ptmMeshTemp = ptmMesh;
  1811.             ptmMesh = NULL;
  1812.  
  1813.             AddNormal(cd, pDecl);
  1814.  
  1815.             hr = ptmMeshTemp->CloneMesh(ptmMeshTemp->GetOptions(), pDecl, m_pDevice, &ptmMesh);
  1816.             if (FAILED(hr))
  1817.                 goto e_Exit;
  1818.  
  1819.             hr = D3DXComputeNormals(ptmMesh, NULL);
  1820.             if (FAILED(hr))
  1821.                 goto e_Exit;
  1822.         }
  1823.  
  1824.         SendMessage(m_hwndStatus, SB_SETTEXT , (WPARAM) 1, (LPARAM) "Polygon Mode"); 
  1825.  
  1826.         hr = AddMeshToDrawList(file, ptmMesh, NULL, pbufAdjacency, pbufMaterials, pbufEffectInstances, cMaterials);
  1827.         if (FAILED(hr))
  1828.             goto e_Exit;
  1829.     }
  1830.  
  1831.     UpdateAnimationsMenu();
  1832.  
  1833. e_Exit:
  1834.     GXRELEASE(ptmMesh);
  1835.     GXRELEASE(ptmMeshTemp);
  1836.     GXRELEASE(pbufAdjacency);
  1837.     GXRELEASE(pbufMaterials);
  1838.     GXRELEASE(pbufEffectInstances);
  1839.  
  1840.     if (pstream != NULL)
  1841.     {
  1842.         pstream->Release();
  1843.     }
  1844.  
  1845.     if (FAILED(hr))
  1846.     {
  1847.         MessageBox( m_hwnd, "Unabled to load the specified file.", "Load failed!", MB_OK);
  1848.     }
  1849.  
  1850.     return hr;
  1851. }
  1852.  
  1853. HRESULT
  1854. TrivialData::FindBones(SFrame *pframeCur, SDrawElement *pde)
  1855. {
  1856.     HRESULT hr = S_OK;
  1857.     SMeshContainer *pmcMesh;
  1858.     SFrame *pframeChild;
  1859.  
  1860.     pmcMesh = pframeCur->pmcMesh;
  1861.     while (pmcMesh != NULL)
  1862.     {
  1863.         if (pmcMesh->pSkinInfo)
  1864.         {
  1865.             for (DWORD i = 0; i < pmcMesh->pSkinInfo->GetNumBones(); ++i)
  1866.             {
  1867.                 SFrame* pFrame = pde->FindFrame((char*)pmcMesh->pSkinInfo->GetBoneName(i));
  1868.                 GXASSERT(pFrame);
  1869.                 pmcMesh->m_pBoneMatrix[i] = &(pFrame->matCombined);
  1870.             }
  1871.         }
  1872.         pmcMesh = (SMeshContainer*)pmcMesh->pNextMeshContainer;
  1873.     }
  1874.  
  1875.     pframeChild = pframeCur->pframeFirstChild;
  1876.     while (pframeChild != NULL)
  1877.     {
  1878.         hr = FindBones(pframeChild, pde);
  1879.         if (FAILED(hr))
  1880.             return hr;
  1881.  
  1882.         pframeChild = pframeChild->pframeSibling;
  1883.     }
  1884.  
  1885.     return S_OK;
  1886. }
  1887.  
  1888.  
  1889. HRESULT GenerateMesh(SMeshContainer *pmcMesh)
  1890. {
  1891.     // ASSUMPTION:  pmcMesh->rgdwAdjacency contains the current adjacency
  1892.  
  1893.     HRESULT hr  = S_OK;
  1894.     LPDIRECT3DDEVICE9       pDevice = NULL;        
  1895.  
  1896.     DWORD   cFaces  = pmcMesh->m_pOrigMesh->GetNumFaces();
  1897.  
  1898.     GXRELEASE(pmcMesh->pMesh);
  1899.     GXRELEASE(pmcMesh->m_pSkinnedMesh);
  1900.     GXRELEASE(pmcMesh->m_pBoneCombinationBuf);
  1901.  
  1902.     hr  = pmcMesh->m_pOrigMesh->GetDevice(&pDevice);
  1903.     if (FAILED(hr))
  1904.         goto e_ExitNONINDEXED;
  1905.  
  1906.     pmcMesh->pMesh      = NULL;
  1907.     
  1908.     if (pmcMesh->m_Method == D3DNONINDEXED)
  1909.     {
  1910.         LPD3DXBONECOMBINATION   rgBoneCombinations;
  1911.         D3DCAPS9                caps;
  1912.  
  1913.         hr  = pDevice->GetDeviceCaps(&caps);
  1914.         if (FAILED(hr))
  1915.             goto e_ExitNONINDEXED;
  1916.  
  1917.         // UNDONE UNDONE fix to only be Managed, once only one mesh is required
  1918.         //          NOTE: might break crease mode!
  1919.         hr = pmcMesh->pSkinInfo->ConvertToBlendedMesh
  1920.                                    (
  1921.                                        pmcMesh->m_pOrigMesh,
  1922.                                        D3DXMESH_MANAGED|D3DXMESHOPT_VERTEXCACHE, 
  1923.                                        pmcMesh->rgdwAdjacency, 
  1924.                                        pmcMesh->rgdwAdjacency,  
  1925.                                        NULL, NULL, 
  1926.                                        &pmcMesh->m_maxFaceInfl,
  1927.                                        &pmcMesh->m_cAttributeGroups, 
  1928.                                        &pmcMesh->m_pBoneCombinationBuf, 
  1929.                                        &pmcMesh->pMesh
  1930.                                    );
  1931.         if (FAILED(hr))
  1932.             goto e_ExitNONINDEXED;
  1933.  
  1934.         /* If the device can only do 2 matrix blends, ConvertToBlendedMesh cannot approximate all meshes to it
  1935.            Thus we split the mesh in two parts: The part that uses at most 2 matrices and the rest. The first is
  1936.            drawn using the device's HW vertex processing and the rest is drawn using SW vertex processing. */
  1937.         if (caps.MaxVertexBlendMatrices == 2)       
  1938.         {    
  1939.             // calculate the index of the attribute table to split on
  1940.             rgBoneCombinations  = reinterpret_cast<LPD3DXBONECOMBINATION>(pmcMesh->m_pBoneCombinationBuf->GetBufferPointer());
  1941.             for (pmcMesh->iAttrSplit = 0; pmcMesh->iAttrSplit < pmcMesh->m_cAttributeGroups; pmcMesh->iAttrSplit++)
  1942.             {
  1943.                 DWORD   cInfl   = 0;
  1944.  
  1945.                 for (DWORD iInfl = 0; iInfl < pmcMesh->m_maxFaceInfl; iInfl++)
  1946.                 {
  1947.                     if (rgBoneCombinations[pmcMesh->iAttrSplit].BoneId[iInfl] != UINT_MAX)
  1948.                     {
  1949.                         ++cInfl;
  1950.                     }
  1951.                 }
  1952.  
  1953.                 if (cInfl > 2)
  1954.                 {
  1955.                     break;
  1956.                 }
  1957.             }
  1958.  
  1959.             // if there is both HW and SW, add the Software Processing flag
  1960.             if (pmcMesh->iAttrSplit < pmcMesh->m_cAttributeGroups)
  1961.             {
  1962.                 LPD3DXMESH pMeshTmp;
  1963.  
  1964.                 hr = pmcMesh->pMesh->CloneMeshFVF(D3DXMESH_SOFTWAREPROCESSING|pmcMesh->pMesh->GetOptions(), 
  1965.                                                     pmcMesh->pMesh->GetFVF(),
  1966.                                                     pDevice, &pMeshTmp);
  1967.                 if (FAILED(hr))
  1968.                 {
  1969.                     goto e_Exit;
  1970.                 }
  1971.  
  1972.                 pmcMesh->pMesh->Release();
  1973.                 pmcMesh->pMesh = pMeshTmp;
  1974.                 pMeshTmp = NULL;
  1975.             }
  1976.         }
  1977.  
  1978.  
  1979. e_ExitNONINDEXED:
  1980.  
  1981.         if (FAILED(hr))
  1982.             goto e_Exit;
  1983.  
  1984.     }
  1985.     else if (pmcMesh->m_Method == D3DINDEXED)
  1986.     {
  1987.         hr = pmcMesh->pSkinInfo->ConvertToIndexedBlendedMesh
  1988.                                 (
  1989.                                 pmcMesh->m_pOrigMesh, 
  1990.                                 pmcMesh->m_iPaletteSize == x_iDefaultSkinningPaletteSize ? D3DXMESH_SYSTEMMEM : D3DXMESH_MANAGED, 
  1991.                                 g_pData->m_iPaletteSize, 
  1992.                                 pmcMesh->rgdwAdjacency, 
  1993.                                 pmcMesh->rgdwAdjacency,
  1994.                                 NULL, NULL, 
  1995.                                 &pmcMesh->m_maxFaceInfl,
  1996.                                 &pmcMesh->m_cAttributeGroups, 
  1997.                                 &pmcMesh->m_pBoneCombinationBuf, 
  1998.                                 &pmcMesh->pMesh);
  1999.         if (FAILED(hr))
  2000.             goto e_Exit;
  2001.  
  2002.     }
  2003.     else if (pmcMesh->m_Method == SOFTWARE)
  2004.     {
  2005.         GXRELEASE(pmcMesh->m_pBoneCombinationBuf);
  2006.  
  2007.         hr = pmcMesh->m_pOrigMesh->CloneMeshFVF(/*D3DXMESH_WRITEONLY | */D3DXMESH_DYNAMIC, pmcMesh->m_pOrigMesh->GetFVF(),
  2008.                                               pDevice, &pmcMesh->pMesh);
  2009.         if (FAILED(hr))
  2010.             goto e_Exit;
  2011.  
  2012.         if (FAILED(hr = pmcMesh->pMesh->OptimizeInplace(D3DXMESHOPT_IGNOREVERTS | D3DXMESHOPT_ATTRSORT | D3DXMESHOPT_DONOTSPLIT, pmcMesh->rgdwAdjacency, pmcMesh->rgdwAdjacency, NULL, NULL)))
  2013.             goto e_Exit;
  2014.  
  2015.         hr = pmcMesh->pMesh->GetAttributeTable(NULL, &pmcMesh->m_cAttributeGroups);
  2016.         if (FAILED(hr))
  2017.             goto e_Exit;
  2018.     }
  2019.  
  2020.     GXRELEASE(pmcMesh->m_pSkinnedMesh);
  2021.  
  2022.     hr = pmcMesh->m_pOrigMesh->CloneMeshFVF(D3DXMESH_SYSTEMMEM, pmcMesh->m_pOrigMesh->GetFVF(),
  2023.                                           pDevice, &pmcMesh->m_pSkinnedMesh);
  2024.     if (FAILED(hr))
  2025.         goto e_Exit;
  2026.  
  2027.     GXRELEASE(pmcMesh->ptmDrawMesh);
  2028.     pmcMesh->ptmDrawMesh = pmcMesh->pMesh;
  2029.     pmcMesh->ptmDrawMesh->AddRef();
  2030.  
  2031.     pmcMesh->UpdateSkinInfo();
  2032.  
  2033.     pmcMesh->ptmDrawMesh->GetAttributeTable(0, &pmcMesh->m_cAttributeGroups);
  2034.  
  2035.     delete []pmcMesh->m_rgaeAttributeTable;
  2036.     pmcMesh->m_rgaeAttributeTable = new D3DXATTRIBUTERANGE[pmcMesh->m_cAttributeGroups];
  2037.     if (pmcMesh->m_rgaeAttributeTable == NULL)
  2038.     {
  2039.         hr = E_OUTOFMEMORY;
  2040.         goto e_Exit;
  2041.     }
  2042.  
  2043.     pmcMesh->ptmDrawMesh->GetAttributeTable(pmcMesh->m_rgaeAttributeTable, 0);
  2044.  
  2045. e_Exit:
  2046.     GXRELEASE(pDevice);
  2047.  
  2048.     return hr;
  2049. }
  2050.  
  2051.  
  2052.  
  2053.  
  2054.  
  2055.  
  2056. HRESULT
  2057. TrivialData::LoadNewProgressiveMesh( )
  2058. {
  2059.     HRESULT hr = S_OK;
  2060.     OPENFILENAME ofn;
  2061.     CFileStream *pstream = NULL;
  2062.     LPD3DXPMESH ptmPMesh = NULL;
  2063.     LPD3DXBUFFER pbufMaterials = NULL;
  2064.     LPD3DXBUFFER pbufEffectInstances = NULL;
  2065.     DWORD cMaterials;
  2066.  
  2067.     memset( &ofn, 0, sizeof(ofn) );
  2068.     static TCHAR file[256];
  2069.     static TCHAR fileTitle[256];
  2070.     static TCHAR filter[] = TEXT("PMESH files (*.x)\0*.x\0")
  2071.                            TEXT("All Files (*.*)\0*.*\0");
  2072.     _tcscpy( file, TEXT(""));
  2073.     _tcscpy( fileTitle, TEXT(""));
  2074.  
  2075.     ofn.lStructSize       = sizeof(OPENFILENAME);
  2076.     ofn.hwndOwner         = m_hwnd;
  2077.     ofn.hInstance         = m_hInstance;
  2078.     ofn.lpstrFilter       = filter;
  2079.     ofn.lpstrCustomFilter = NULL;
  2080.     ofn.nMaxCustFilter    = 0L;
  2081.     ofn.nFilterIndex      = 1L;
  2082.     ofn.lpstrFile         = file;
  2083.     ofn.nMaxFile          = sizeof(file);
  2084.     ofn.lpstrFileTitle    = fileTitle;
  2085.     ofn.nMaxFileTitle     = sizeof(fileTitle);
  2086.     ofn.lpstrInitialDir   = NULL;
  2087.     ofn.nFileOffset       = 0;
  2088.     ofn.nFileExtension    = 0;
  2089.     ofn.lpstrDefExt       = TEXT("*.m");
  2090.     ofn.lCustData         = 0;
  2091.  
  2092.     ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
  2093.     if ( ! GetOpenFileName( &ofn) )
  2094.     {
  2095.         char s[40];
  2096.         DWORD dwErr = CommDlgExtendedError();
  2097.  
  2098.         // if the first one failed, retry with old dialog style
  2099.         if ( 0 != dwErr )
  2100.         {
  2101.             memset( &ofn, 0, sizeof(ofn) );
  2102.             ofn.lStructSize       = sizeof(OPENFILENAME_NT4W);
  2103.             ofn.hwndOwner         = m_hwnd;
  2104.             ofn.hInstance         = m_hInstance;
  2105.             ofn.lpstrFilter       = filter;
  2106.             ofn.lpstrCustomFilter = NULL;
  2107.             ofn.nMaxCustFilter    = 0L;
  2108.             ofn.nFilterIndex      = 1L;
  2109.             ofn.lpstrFile         = file;
  2110.             ofn.nMaxFile          = sizeof(file);
  2111.             ofn.lpstrFileTitle    = fileTitle;
  2112.             ofn.nMaxFileTitle     = sizeof(fileTitle);
  2113.             ofn.lpstrInitialDir   = NULL;
  2114.             ofn.nFileOffset       = 0;
  2115.             ofn.nFileExtension    = 0;
  2116.             ofn.lpstrDefExt       = TEXT("*.m");
  2117.             ofn.lCustData         = 0;
  2118.  
  2119.             ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
  2120.  
  2121.             if ( ! GetOpenFileName( &ofn) )
  2122.             {
  2123.                 dwErr = CommDlgExtendedError();
  2124.                 if ( 0 != dwErr )
  2125.                 {
  2126.                     sprintf( s, "GetOpenFileName failed with %x", dwErr );
  2127.                     MessageBox( m_hwnd, s, "TexWin", MB_OK | MB_SYSTEMMODAL );
  2128.                 }
  2129.  
  2130.                 goto e_Exit;
  2131.  
  2132.             }
  2133.         }
  2134.         else
  2135.         {
  2136.             goto e_Exit;
  2137.         }
  2138.     }
  2139.  
  2140.     pstream = new CFileStream(ofn.lpstrFile, true, false, &hr);
  2141.     if ((pstream == NULL) || FAILED(hr))
  2142.         goto e_Exit;
  2143.  
  2144.     hr = D3DXCreatePMeshFromStream(pstream, D3DXMESH_MANAGED, m_pDevice, &pbufMaterials, &pbufEffectInstances, &cMaterials, &ptmPMesh);
  2145.     if (FAILED(hr))
  2146.         goto e_Exit;
  2147.  
  2148.     // go to max lod so that bounding sphere stuff works, etc.
  2149.     hr = ptmPMesh->SetNumVertices(0xffffffff);
  2150.     if (FAILED(hr))
  2151.         goto e_Exit;
  2152.  
  2153.     hr = AddMeshToDrawList(ofn.lpstrFile, NULL, ptmPMesh, NULL, pbufMaterials, pbufEffectInstances, cMaterials);
  2154.     if (FAILED(hr))
  2155.         goto e_Exit;
  2156.  
  2157. e_Exit:
  2158.     GXRELEASE(pstream);
  2159.     GXRELEASE(ptmPMesh);
  2160.     GXRELEASE(pbufMaterials);
  2161.     GXRELEASE(pbufEffectInstances);
  2162.  
  2163.     return hr;
  2164. }
  2165.  
  2166. HRESULT SaveMeshToM
  2167.     (
  2168.     char *szFilename, 
  2169.     LPD3DXMESH pMesh,
  2170.     D3DXMATERIAL *rgMaterials
  2171.     )
  2172. {
  2173.     DWORD iFace;
  2174.     DWORD iVertex;
  2175.     D3DXVECTOR3 *pvPos;
  2176.     D3DXVECTOR3 *pvNormal;
  2177.     WORD *pwFace;
  2178.     FILE *file;
  2179.     WORD *pwFaces = NULL;
  2180.     PBYTE pvPoints = NULL;
  2181.     DWORD cVertices;
  2182.     DWORD cFaces;
  2183.     DWORD *rgdwAttributes;
  2184.     CD3DXCrackDecl1 cd;
  2185.     D3DVERTEXELEMENT9 pDecl[MAX_FVF_DECL_SIZE];
  2186.  
  2187.     pMesh->GetDeclaration(pDecl);
  2188.     cd.SetDeclaration(pDecl);    
  2189.  
  2190.     file = fopen(szFilename, "w+");
  2191.     if (file == NULL)
  2192.         return E_FAIL;
  2193.  
  2194.     cVertices = pMesh->GetNumVertices();
  2195.     cFaces = pMesh->GetNumFaces();
  2196.  
  2197.     pMesh->LockVertexBuffer(0, (LPVOID*)&pvPoints);
  2198.     pMesh->LockIndexBuffer(0, (LPVOID*)&pwFaces);
  2199.     pMesh->LockAttributeBuffer(0, &rgdwAttributes);
  2200.  
  2201.     for (iVertex = 0; iVertex < cVertices; iVertex++)
  2202.     {
  2203.         pvPos = cd.PvGetPosition(cd.GetArrayElem(pvPoints, iVertex));
  2204.         pvNormal = cd.PvGetNormal(cd.GetArrayElem(pvPoints, iVertex));
  2205.  
  2206.         fprintf(file, "Vertex %d %f %f %f {normal=(%f %f %f)}\n",
  2207.                     iVertex+1, pvPos->x, pvPos->y, pvPos->z, 
  2208.                              pvNormal->x, pvNormal->y, pvNormal->z);
  2209.     }
  2210.  
  2211.     pwFace = pwFaces;
  2212.     for (iFace = 0; iFace < cFaces; iFace++)
  2213.     {
  2214.         fprintf(file, "Face %d %d %d %d {rgb=(%f %f %f)}\n",
  2215.                     iFace+1, pwFace[0]+1, pwFace[1]+1, pwFace[2]+1,
  2216.                     rgMaterials[rgdwAttributes[iFace]].MatD3D.Diffuse.r,
  2217.                     rgMaterials[rgdwAttributes[iFace]].MatD3D.Diffuse.g,
  2218.                     rgMaterials[rgdwAttributes[iFace]].MatD3D.Diffuse.b);
  2219.  
  2220.         pwFace += 3;
  2221.     }
  2222.  
  2223.     fclose(file);
  2224.  
  2225.     pMesh->UnlockVertexBuffer();
  2226.     pMesh->UnlockIndexBuffer();
  2227.     pMesh->UnlockAttributeBuffer();
  2228.  
  2229.     return S_OK;
  2230. }
  2231.  
  2232. struct SSaveMeshData
  2233. {
  2234.     BOOL bSaveSelectedOnly;
  2235.     BOOL bSaveHierarchy;
  2236.     BOOL bSaveAnimation;
  2237.     DWORD xFormat;
  2238. };
  2239.  
  2240. UINT_PTR CALLBACK DlgProcSaveMesh(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  2241. {
  2242.     SSaveMeshData *psmdData;
  2243.     LPOPENFILENAME lpOFN;
  2244.  
  2245.     switch (message)
  2246.     {
  2247.         case WM_INITDIALOG:
  2248.             // Save off the long pointer to the OPENFILENAME structure.
  2249.             SetWindowLongPtr(hDlg, DWLP_USER, lParam);
  2250.  
  2251.             lpOFN = (LPOPENFILENAME)lParam;
  2252.             psmdData = (SSaveMeshData *)lpOFN->lCustData;
  2253.             SendDlgItemMessage(hDlg, IDC_SAVESELECTEDONLY, BM_SETCHECK, psmdData->bSaveSelectedOnly ? BST_CHECKED : BST_UNCHECKED, 0);
  2254.             SendDlgItemMessage(hDlg, IDC_SAVEHIERARCHY, BM_SETCHECK, psmdData->bSaveHierarchy ? BST_CHECKED : BST_UNCHECKED, 0);
  2255.             SendDlgItemMessage(hDlg, IDC_SAVEANIMATION, BM_SETCHECK, psmdData->bSaveAnimation ? BST_CHECKED : BST_UNCHECKED, 0);
  2256.  
  2257.             switch (psmdData->xFormat)
  2258.             {
  2259.                 case D3DXF_FILEFORMAT_BINARY:
  2260.                     CheckRadioButton(hDlg,IDC_TEXT,IDC_BINARYCOMPRESSED,IDC_BINARY);
  2261.                     break;
  2262.  
  2263.                 case D3DXF_FILEFORMAT_TEXT:
  2264.                     CheckRadioButton(hDlg,IDC_TEXT,IDC_BINARYCOMPRESSED,IDC_TEXT);
  2265.                     break;
  2266.  
  2267.                 case D3DXF_FILEFORMAT_BINARY | D3DXF_FILEFORMAT_COMPRESSED:
  2268.                     CheckRadioButton(hDlg,IDC_TEXT,IDC_BINARYCOMPRESSED,IDC_BINARYCOMPRESSED);
  2269.                     break;
  2270.             }
  2271.  
  2272.             break;
  2273.  
  2274.         case WM_DESTROY:
  2275.             lpOFN = (LPOPENFILENAME)GetWindowLongPtr(hDlg, DWLP_USER);
  2276.             psmdData = (SSaveMeshData *)lpOFN->lCustData;
  2277.  
  2278.             psmdData->bSaveSelectedOnly = (BST_CHECKED == IsDlgButtonChecked(hDlg, IDC_SAVESELECTEDONLY));
  2279.             psmdData->bSaveHierarchy = (BST_CHECKED == IsDlgButtonChecked(hDlg, IDC_SAVEHIERARCHY));
  2280.             psmdData->bSaveAnimation = (BST_CHECKED == IsDlgButtonChecked(hDlg, IDC_SAVEANIMATION));
  2281.  
  2282.             if (BST_CHECKED == IsDlgButtonChecked(hDlg, IDC_TEXT))
  2283.                 psmdData->xFormat = D3DXF_FILEFORMAT_TEXT;
  2284.             else if (BST_CHECKED == IsDlgButtonChecked(hDlg, IDC_BINARY))
  2285.                 psmdData->xFormat = D3DXF_FILEFORMAT_BINARY;
  2286.             else if (BST_CHECKED == IsDlgButtonChecked(hDlg, IDC_BINARYCOMPRESSED))
  2287.                 psmdData->xFormat = D3DXF_FILEFORMAT_BINARY | D3DXF_FILEFORMAT_COMPRESSED;
  2288.  
  2289.             break;
  2290.  
  2291.         default:
  2292.             return FALSE;
  2293.     }
  2294.     return TRUE;
  2295. }
  2296.  
  2297.  
  2298. // this function tries to generate point reps using the adjacency in the mesh container
  2299. //          if it fails, the user is asked if they would like to skip saving it to disk
  2300. DWORD *CheckAdjacencyForSaving
  2301.     (
  2302.     SMeshContainer *pmcMesh
  2303.     )
  2304. {
  2305.     HRESULT hr;
  2306.     DWORD cVertices;
  2307.     DWORD *rgdwPointReps;
  2308.  
  2309.     if ((pmcMesh->pMesh != NULL) && (pmcMesh->rgdwAdjacency != NULL))
  2310.     {
  2311.         cVertices = pmcMesh->pMesh->GetNumVertices();
  2312.  
  2313.         rgdwPointReps = new DWORD[cVertices];
  2314.  
  2315.         // if allocation failed, just assume the adjacency is correct, will be checked again by D3DX function
  2316.         if (rgdwPointReps == NULL)
  2317.             return pmcMesh->rgdwAdjacency;
  2318.  
  2319.         hr = pmcMesh->pMesh->ConvertAdjacencyToPointReps(pmcMesh->rgdwAdjacency, rgdwPointReps);
  2320.         delete []rgdwPointReps;
  2321.  
  2322.         // if the function failed, there is something wrong with the adjacency, ask user if they want to skip saving it
  2323.         if (FAILED(hr))
  2324.         {
  2325.             // return NULL if user wants to skip adjacency, will not be saved to file as point reps then
  2326.             if (IDYES == MessageBox(NULL, "The adjacency for the current mesh is invalid for saving, do you want to skip saving it?  NOTE: you can try to fix the adjaceny by doing Validate Mesh", "Adjaceny invalid!", MB_YESNO) )
  2327.             {
  2328.                 return NULL;
  2329.             }
  2330.         }
  2331.     }
  2332.  
  2333.     return pmcMesh->rgdwAdjacency;
  2334.  
  2335. }
  2336.  
  2337. // this function allows for the user not specifying the saving of "bad" adjacency
  2338. //   and MORE IMPORTANTLY sets up the MeshData structure for saving purpose
  2339. void 
  2340. SetupForSaveMeshHierarchy(SFrame *pFrame)
  2341. {
  2342.     SMeshContainer *pmcCur;
  2343.     DWORD *rgdwAdjacencySave;
  2344.  
  2345.     pmcCur = pFrame->pmcMesh;
  2346.     while (pmcCur != NULL)
  2347.     {
  2348.         // check to see if we should save the adjacency
  2349.         rgdwAdjacencySave = CheckAdjacencyForSaving(pmcCur);
  2350.  
  2351.         // if CheckAdjacency returned NULL, then swap out the adjacency and DON'T save it
  2352.         if (rgdwAdjacencySave == NULL)
  2353.         {
  2354.             pmcCur->m_rgdwAdjacencyBackup = pmcCur->rgdwAdjacency;
  2355.             pmcCur->rgdwAdjacency = NULL;
  2356.         }
  2357.  
  2358.         // if doing skinning (the orig mesh is not NULL), then we need to SAVE that mesh with the skin info
  2359.         //   instead of saving the HW friendly mesh with the skin info, so swap the pMesh out for the save
  2360.         if (pmcCur->m_pOrigMesh != NULL)
  2361.         {
  2362.             GXASSERT(pmcCur->m_pMeshBackup == NULL);
  2363.  
  2364.             pmcCur->m_pMeshBackup = pmcCur->pMesh;
  2365.             pmcCur->pMesh = pmcCur->m_pOrigMesh;
  2366.             pmcCur->pMesh->AddRef();
  2367.         }
  2368.  
  2369.         // NOTE!!! This needs to be done after handling m_pOrigMesh
  2370.         if (pmcCur->bPMMeshMode)
  2371.         {
  2372.             pmcCur->MeshData.Type = D3DXMESHTYPE_PMESH;
  2373.             pmcCur->MeshData.pPMesh = pmcCur->pPMMesh;
  2374.         }
  2375.         else if (pmcCur->bTesselateMode)
  2376.         {
  2377.             pmcCur->MeshData.Type = D3DXMESHTYPE_PATCHMESH;
  2378.             pmcCur->MeshData.pPatchMesh = pmcCur->pPatchMesh;
  2379.         }
  2380.         else // standard mesh case
  2381.         {
  2382.             pmcCur->MeshData.Type = D3DXMESHTYPE_MESH;
  2383.             pmcCur->MeshData.pMesh = pmcCur->pMesh;
  2384.         }
  2385.  
  2386.         pmcCur = pmcCur->pNextMeshContainer;
  2387.     }
  2388.  
  2389.     if (pFrame->pframeSibling != NULL)
  2390.     {
  2391.         SetupForSaveMeshHierarchy(pFrame->pframeSibling);
  2392.     }
  2393.  
  2394.     if (pFrame->pframeFirstChild != NULL)
  2395.     {
  2396.         SetupForSaveMeshHierarchy(pFrame->pframeFirstChild);
  2397.     }
  2398. }
  2399.  
  2400. void 
  2401. RestoreAfterSaveMeshHierarchy(SFrame *pFrame)
  2402. {
  2403.     SMeshContainer *pmcCur;
  2404.  
  2405.     pmcCur = pFrame->pmcMesh;
  2406.     while (pmcCur != NULL)
  2407.     {
  2408.         // if we didn't save the adjacency (swapped it out), swap it back in
  2409.         if (pmcCur->m_rgdwAdjacencyBackup != NULL)
  2410.         {
  2411.             GXASSERT(pmcCur->rgdwAdjacency == NULL);
  2412.             pmcCur->rgdwAdjacency = pmcCur->m_rgdwAdjacencyBackup;
  2413.             pmcCur->m_rgdwAdjacencyBackup = NULL;
  2414.         }
  2415.  
  2416.         // if skinning required the orig mesh to be in pMesh, swap the backed up pMesh back in
  2417.         if (pmcCur->m_pMeshBackup != NULL)
  2418.         {
  2419.             GXRELEASE(pmcCur->pMesh);
  2420.             pmcCur->pMesh = pmcCur->m_pMeshBackup;
  2421.             pmcCur->m_pMeshBackup = NULL;
  2422.         }
  2423.  
  2424.         pmcCur = pmcCur->pNextMeshContainer;
  2425.     }
  2426.  
  2427.     if (pFrame->pframeSibling != NULL)
  2428.     {
  2429.         RestoreAfterSaveMeshHierarchy(pFrame->pframeSibling);
  2430.     }
  2431.  
  2432.     if (pFrame->pframeFirstChild != NULL)
  2433.     {
  2434.         RestoreAfterSaveMeshHierarchy(pFrame->pframeFirstChild);
  2435.     }
  2436. }
  2437.  
  2438. HRESULT
  2439. TrivialData::SaveMesh( )
  2440. {
  2441.     HRESULT hr = S_OK;
  2442.     LPD3DXMESH pMeshMerged = NULL;
  2443.     LPD3DXBUFFER pbufAdjacencyMerged = NULL;
  2444.     LPD3DXBUFFER pbufMaterialsMerged = NULL;
  2445.     DWORD cMaterialsMerged;
  2446.     DWORD *rgdwAdjacency;
  2447.  
  2448.     SSaveMeshData smdData;
  2449.     OPENFILENAME ofn;
  2450.     BOOL bXFile;
  2451.     DWORD cchFileName;
  2452.     static TCHAR file[256];
  2453.     static TCHAR szFilepath[256];
  2454.     static TCHAR fileTitle[256];
  2455.     static TCHAR filter[] =
  2456.                            TEXT("X files (*.x)\0*.x\0")
  2457.                            TEXT("M files (*.m)\0*.m\0")
  2458.                            TEXT("All Files (*.*)\0*.*\0");
  2459.     _tcscpy( file, TEXT(""));
  2460.     _tcscpy( fileTitle, TEXT(""));
  2461.  
  2462.     memset( &ofn, 0, sizeof(ofn) );
  2463.     ofn.lStructSize       = sizeof(OPENFILENAME);
  2464.     ofn.hwndOwner         = m_hwnd;
  2465.     ofn.hInstance         = m_hInstance;
  2466.     ofn.lpstrFilter       = filter;
  2467.     ofn.lpstrCustomFilter = NULL;
  2468.     ofn.nMaxCustFilter    = 0L;
  2469.     ofn.nFilterIndex      = 1L;
  2470.     ofn.lpstrFile         = file;
  2471.     ofn.nMaxFile          = sizeof(file);
  2472.     ofn.lpstrFileTitle    = fileTitle;
  2473.     ofn.nMaxFileTitle     = sizeof(fileTitle);
  2474.     ofn.lpstrInitialDir   = NULL;
  2475.     ofn.lpstrDefExt       = NULL;
  2476.     ofn.lCustData         = (LPARAM)&smdData;
  2477.     ofn.lpfnHook          = DlgProcSaveMesh;
  2478.     ofn.lpTemplateName    = MAKEINTRESOURCE(IDD_SAVEMESHEX);
  2479.     ofn.Flags = OFN_OVERWRITEPROMPT | OFN_EXPLORER | OFN_ENABLETEMPLATE | OFN_ENABLEHOOK;
  2480.  
  2481.     smdData.bSaveSelectedOnly = FALSE;
  2482.     smdData.bSaveHierarchy = TRUE;
  2483.     smdData.bSaveAnimation = TRUE;
  2484.     smdData.xFormat = D3DXF_FILEFORMAT_TEXT;
  2485.  
  2486.  
  2487.     if ( ! GetSaveFileName( &ofn) )
  2488.     {
  2489.         char s[40];
  2490.         DWORD dwErr = CommDlgExtendedError();
  2491.         if ( 0 != dwErr )
  2492.         {
  2493.             memset( &ofn, 0, sizeof(OPENFILENAME) );
  2494.             ofn.lStructSize       = sizeof(OPENFILENAME_NT4W);
  2495.             ofn.hwndOwner         = m_hwnd;
  2496.             ofn.hInstance         = m_hInstance;
  2497.             ofn.lpstrFilter       = filter;
  2498.             ofn.lpstrCustomFilter = NULL;
  2499.             ofn.nMaxCustFilter    = 0L;
  2500.             ofn.nFilterIndex      = 1L;
  2501.             ofn.lpstrFile         = file;
  2502.             ofn.nMaxFile          = sizeof(file);
  2503.             ofn.lpstrFileTitle    = fileTitle;
  2504.             ofn.nMaxFileTitle     = sizeof(fileTitle);
  2505.             ofn.lpstrInitialDir   = NULL;
  2506.             ofn.lpstrDefExt       = NULL;
  2507.             ofn.lCustData         = (LPARAM)&smdData;
  2508.             ofn.lpfnHook          = DlgProcSaveMesh;
  2509.             ofn.lpTemplateName    = MAKEINTRESOURCE(IDD_SAVEMESHEX);
  2510.             ofn.Flags = OFN_OVERWRITEPROMPT | OFN_EXPLORER | OFN_ENABLETEMPLATE | OFN_ENABLEHOOK;
  2511.  
  2512.             if ( ! GetSaveFileName( &ofn) )
  2513.             {
  2514.                 dwErr = CommDlgExtendedError();
  2515.                 if ( 0 != dwErr )
  2516.                 {
  2517.                     sprintf( s, "GetOpenFileName failed with %x", dwErr );
  2518.                     MessageBox( m_hwnd, s, "TexWin", MB_OK | MB_SYSTEMMODAL );
  2519.                 }
  2520.  
  2521.                 goto e_Exit;
  2522.             }
  2523.         }
  2524.         else  // just a cancel, return
  2525.         {
  2526.             goto e_Exit;
  2527.         }
  2528.     }
  2529.     
  2530.     if (smdData.bSaveSelectedOnly && ((m_pmcSelectedMesh == NULL) || (m_pmcSelectedMesh->pMesh == NULL)))
  2531.     {
  2532.         MessageBox(m_hwnd, "No Mesh selected to save!", "No Selection", MB_OK);
  2533.         goto e_Exit;
  2534.     }
  2535.  
  2536.     bXFile = TRUE;
  2537.     cchFileName = strlen(ofn.lpstrFile);
  2538.     if ((toupper(ofn.lpstrFile[cchFileName - 1]) == 'M') && (ofn.lpstrFile[cchFileName - 2] == '.'))
  2539.     {
  2540.         bXFile = FALSE;
  2541.     }
  2542.  
  2543.     if (smdData.bSaveHierarchy && bXFile)
  2544.     {
  2545.         // UNDONE UNDONE - doesn't support subset of info yet!
  2546.         GXASSERT(smdData.bSaveAnimation);
  2547.         GXASSERT(!smdData.bSaveSelectedOnly);
  2548.  
  2549.         // UNDONE UNDONE Need to check adjacency before saving!!!!
  2550.  
  2551.         SetupForSaveMeshHierarchy(m_pdeHead->pframeRoot);
  2552.  
  2553.         hr = D3DXSaveMeshHierarchyToFile(ofn.lpstrFile, smdData.xFormat, (LPD3DXFRAME)m_pdeHead->pframeRoot->pframeFirstChild, m_pdeHead->m_pAnimMixer, NULL);
  2554.  
  2555.         RestoreAfterSaveMeshHierarchy(m_pdeHead->pframeRoot);
  2556.  
  2557.         if (FAILED(hr))
  2558.             goto e_Exit;
  2559.     }
  2560.     else
  2561.     {
  2562.  
  2563.         if (smdData.bSaveSelectedOnly)
  2564.         {
  2565.             if (m_pmcSelectedMesh->pSkinInfo)
  2566.             {
  2567.                 MessageBox(m_hwnd, "Skinned Meshes cannot be flattened!", "Skinned Mesh Found", MB_OK);
  2568.                 hr = E_FAIL;
  2569.                 goto e_Exit;
  2570.             }
  2571.             else if (m_pmcSelectedMesh->pPMMesh)
  2572.             {
  2573.                 MessageBox(m_hwnd, "Progressive Meshes cannot be flattened!  Take a snapshot before saving.", "Progressive Mesh Found", MB_OK);
  2574.                 hr = E_FAIL;
  2575.                 goto e_Exit;
  2576.             }
  2577.  
  2578.             if (bXFile)
  2579.             {
  2580.                 rgdwAdjacency = CheckAdjacencyForSaving(m_pmcSelectedMesh);
  2581.  
  2582.                 hr = D3DXSaveMeshToX(ofn.lpstrFile, m_pmcSelectedMesh->pMesh, rgdwAdjacency,
  2583.                                         m_pmcSelectedMesh->rgMaterials, m_pmcSelectedMesh->pEffects, m_pmcSelectedMesh->NumMaterials, smdData.xFormat);
  2584.                 if (FAILED(hr))
  2585.                     goto e_Exit;
  2586.             }
  2587.             else  // save out the M file
  2588.             {
  2589.                 hr = SaveMeshToM(ofn.lpstrFile, m_pmcSelectedMesh->pMesh, m_pmcSelectedMesh->rgMaterials);
  2590.                 if (FAILED(hr))
  2591.                     goto e_Exit;
  2592.             }
  2593.         }
  2594.         else
  2595.         {
  2596.             if (m_pdeHead->pframeRoot->PMeshPresent())
  2597.             {
  2598.                 MessageBox(m_hwnd, "Progressive Meshes cannot be flattened!  Take a snapshot before saving.", "Progressive Mesh Found", MB_OK);
  2599.                 hr = E_FAIL;
  2600.                 goto e_Exit;
  2601.             }
  2602.             else if (m_pdeHead->bSkinnedMeshInHeirarchy)
  2603.             {
  2604.                 MessageBox(m_hwnd, "Skinned Meshes cannot be flattened!", "Skinned Mesh Found", MB_OK);
  2605.                 hr = E_FAIL;
  2606.                 goto e_Exit;
  2607.             }
  2608.  
  2609.             D3DXMATRIX matRot;
  2610.             D3DXMATRIX matTrans;
  2611.             D3DXMATRIX matIdent;
  2612.  
  2613.             // recalculate matCombined, without rot/trans in root
  2614.             matRot = m_pdeHead->pframeRoot->matRot;
  2615.             matTrans = m_pdeHead->pframeRoot->matTrans;
  2616.             D3DXMatrixIdentity(&m_pdeHead->pframeRoot->matRot);
  2617.             D3DXMatrixIdentity(&m_pdeHead->pframeRoot->matTrans);
  2618.             D3DXMatrixIdentity(&matIdent);
  2619.  
  2620.             hr = UpdateFrames(m_pdeHead->pframeRoot, matIdent);
  2621.             if (FAILED(hr))
  2622.                 return hr;
  2623.  
  2624.             hr = ::MergeMeshes(m_pdeHead->pframeRoot, m_pDevice,    
  2625.                                     &pMeshMerged, &pbufAdjacencyMerged,
  2626.                                     &pbufMaterialsMerged, &cMaterialsMerged);
  2627.             if (FAILED(hr))
  2628.                 goto e_Exit;
  2629.  
  2630.             // put the original rot/trans back 
  2631.             m_pdeHead->pframeRoot->matRot = matRot;
  2632.             m_pdeHead->pframeRoot->matTrans = matTrans;
  2633.             D3DXMatrixIdentity(&matIdent);
  2634.  
  2635.             hr = UpdateFrames(m_pdeHead->pframeRoot, matIdent);
  2636.             if (FAILED(hr))
  2637.                 return hr;
  2638.  
  2639.             if (bXFile)
  2640.             {
  2641.                 hr = D3DXSaveMeshToX(ofn.lpstrFile, pMeshMerged, (DWORD*)(pbufAdjacencyMerged->GetBufferPointer()),
  2642.                            (D3DXMATERIAL*)(pbufMaterialsMerged->GetBufferPointer()), NULL, cMaterialsMerged, smdData.xFormat);
  2643.                 if (FAILED(hr))
  2644.                     goto e_Exit;
  2645.             }
  2646.             else  // save out the M file
  2647.             {
  2648.                 hr = SaveMeshToM(ofn.lpstrFile, pMeshMerged, (D3DXMATERIAL*)(pbufMaterialsMerged->GetBufferPointer()));
  2649.                 if (FAILED(hr))
  2650.                     goto e_Exit;
  2651.             }
  2652.         }
  2653.     }
  2654.  
  2655. e_Exit:
  2656.     GXRELEASE(pMeshMerged);
  2657.     GXRELEASE(pbufAdjacencyMerged);
  2658.     GXRELEASE(pbufMaterialsMerged);
  2659.  
  2660.     if (FAILED(hr))
  2661.     {
  2662.         MessageBox( m_hwnd, "Unabled to save the specified file!", "Save failed!", MB_OK);
  2663.     }
  2664.  
  2665.     return hr;
  2666. }
  2667.  
  2668. #if 1
  2669. HRESULT
  2670. TrivialData::SavePMesh( )
  2671. {
  2672.     HRESULT hr = S_OK;
  2673.     IStream *pstream = NULL;
  2674.  
  2675.     OPENFILENAME ofn;
  2676.     memset( &ofn, 0, sizeof(ofn) );
  2677.     static TCHAR file[256];
  2678.     static TCHAR szFilepath[256];
  2679.     static TCHAR fileTitle[256];
  2680.     static TCHAR filter[] =
  2681.                            TEXT("X files (*.x)\0*.x\0")
  2682.                            TEXT("All Files (*.*)\0*.*\0");
  2683.     _tcscpy( file, TEXT(""));
  2684.     _tcscpy( fileTitle, TEXT(""));
  2685.  
  2686.     ofn.lStructSize       = sizeof(ofn);
  2687.     ofn.hwndOwner         = m_hwnd;
  2688.     ofn.hInstance         = m_hInstance;
  2689.     ofn.lpstrFilter       = filter;
  2690.     ofn.lpstrCustomFilter = NULL;
  2691.     ofn.nMaxCustFilter    = 0L;
  2692.     ofn.nFilterIndex      = 1L;
  2693.     ofn.lpstrFile         = file;
  2694.     ofn.nMaxFile          = sizeof(file);
  2695.     ofn.lpstrFileTitle    = fileTitle;
  2696.     ofn.nMaxFileTitle     = sizeof(fileTitle);
  2697.     ofn.lpstrInitialDir   = NULL;
  2698.     ofn.nFileOffset       = 0;
  2699.     ofn.nFileExtension    = 0;
  2700.     ofn.lpstrDefExt       = TEXT("*.m");
  2701.     ofn.lCustData         = 0;
  2702.  
  2703.     if ((m_pmcSelectedMesh == NULL) || !m_pmcSelectedMesh->bPMMeshMode )
  2704.         return S_OK;
  2705.  
  2706.     ofn.Flags = OFN_OVERWRITEPROMPT;
  2707.     if ( ! GetSaveFileName( &ofn) )
  2708.     {
  2709.         char s[40];
  2710.         DWORD dwErr = CommDlgExtendedError();
  2711.         if ( 0 != dwErr )
  2712.         {
  2713.             sprintf( s, "GetOpenFileName failed with %x", dwErr );
  2714.             MessageBox( m_hwnd, s, "TexWin", MB_OK | MB_SYSTEMMODAL );
  2715.         }
  2716.         goto e_Exit;
  2717.     }
  2718.  
  2719.     pstream = new CFileStream(ofn.lpstrFile, false, true, &hr);
  2720.     if (pstream == NULL || FAILED(hr))
  2721.         goto e_Exit;
  2722.  
  2723.     hr = m_pmcSelectedMesh->pPMMesh->Save(pstream, m_pmcSelectedMesh->rgMaterials, m_pmcSelectedMesh->pEffects, m_pmcSelectedMesh->NumMaterials);
  2724.     if (FAILED(hr))
  2725.         goto e_Exit;
  2726.  
  2727. e_Exit:
  2728.     if (FAILED(hr))
  2729.     {
  2730.         MessageBox( m_hwnd, "Unabled to save the specified file!", "Save failed!", MB_OK);
  2731.     }
  2732.  
  2733.     GXRELEASE(pstream);
  2734.     return hr;
  2735. }
  2736. #endif
  2737.  
  2738. void
  2739. TrivialData::AddAnimation()
  2740. {
  2741.     OPENFILENAME ofn;
  2742.     HRESULT hr = S_OK;
  2743.     memset( &ofn, 0, sizeof(ofn) );
  2744.     static TCHAR file[256];
  2745.     static TCHAR szFilepath[256];
  2746.     static TCHAR fileTitle[256];
  2747.     static TCHAR filter[] =
  2748.                            TEXT("Mesh files (*.x,*.m)\0*.x;*.m\0")
  2749.                            TEXT("X files (*.x)\0*.x\0")
  2750.                            TEXT("MESH files (*.m)\0*.m\0")
  2751.                            TEXT("All Files (*.*)\0*.*\0");
  2752.     _tcscpy( file, TEXT(""));
  2753.     _tcscpy( fileTitle, TEXT(""));
  2754.     int cchFileName;
  2755.     int cchFilePath;
  2756.  
  2757.     SFrame *pFrameToDelete = NULL;
  2758.     LPD3DXANIMATIONCONTROLLER pAnimMixerToDelete = NULL;
  2759.     LPD3DXANIMATIONCONTROLLER pAnimMixer = NULL;
  2760.     LPD3DXANIMATIONSET pAnimSet;
  2761.     CAllocateHierarchy Alloc;
  2762.     UINT iAnimSet;
  2763.     UINT cAnimSets;
  2764.  
  2765.     ofn.lStructSize       = sizeof(OPENFILENAME);
  2766.     ofn.hwndOwner         = m_hwnd;
  2767.     ofn.hInstance         = m_hInstance;
  2768.     ofn.lpstrFilter       = filter;
  2769.     ofn.lpstrCustomFilter = NULL;
  2770.     ofn.nMaxCustFilter    = 0L;
  2771.     ofn.nFilterIndex      = 1L;
  2772.     ofn.lpstrFile         = file;
  2773.     ofn.nMaxFile          = sizeof(file);
  2774.     ofn.lpstrFileTitle    = fileTitle;
  2775.     ofn.nMaxFileTitle     = sizeof(fileTitle);
  2776.     ofn.lpstrInitialDir   = NULL;
  2777.     ofn.nFileOffset       = 0;
  2778.     ofn.nFileExtension    = 0;
  2779.     ofn.lpstrDefExt       = TEXT("*.x");
  2780.     ofn.lCustData         = NULL;
  2781.  
  2782.     ofn.lpfnHook          = DlgProcLoadMesh;
  2783.     ofn.lpTemplateName    = NULL;
  2784.  
  2785.     ofn.Flags = OFN_ENABLESIZING | OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
  2786.     if ( ! GetOpenFileName( &ofn) )
  2787.     {
  2788.         char s[40];
  2789.         DWORD dwErr = CommDlgExtendedError();
  2790.         if ( 0 != dwErr )
  2791.         {
  2792.             memset( &ofn, 0, sizeof(ofn) );
  2793.             ofn.lStructSize       = sizeof(OPENFILENAME_NT4W);
  2794.             ofn.hwndOwner         = m_hwnd;
  2795.             ofn.hInstance         = m_hInstance;
  2796.             ofn.lpstrFilter       = filter;
  2797.             ofn.lpstrCustomFilter = NULL;
  2798.             ofn.nMaxCustFilter    = 0L;
  2799.             ofn.nFilterIndex      = 1L;
  2800.             ofn.lpstrFile         = file;
  2801.             ofn.nMaxFile          = sizeof(file);
  2802.             ofn.lpstrFileTitle    = fileTitle;
  2803.             ofn.nMaxFileTitle     = sizeof(fileTitle);
  2804.             ofn.lpstrInitialDir   = NULL;
  2805.             ofn.nFileOffset       = 0;
  2806.             ofn.nFileExtension    = 0;
  2807.             ofn.lpstrDefExt       = TEXT("*.x");
  2808.             ofn.lCustData         = NULL;
  2809.  
  2810.             ofn.lpfnHook          = DlgProcLoadMesh;
  2811.             ofn.lpTemplateName    = NULL;
  2812.  
  2813.             ofn.Flags = OFN_ENABLESIZING | OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
  2814.  
  2815.         // if the first one failed, retry with old dialog style
  2816.             if ( ! GetOpenFileName( &ofn) )
  2817.             {
  2818.                 dwErr = CommDlgExtendedError();
  2819.                 if ( 0 != dwErr )
  2820.                 {
  2821.                     sprintf( s, "GetOpenFileName failed with %x", dwErr );
  2822.                     MessageBox( m_hwnd, s, "TexWin", MB_OK | MB_SYSTEMMODAL );
  2823.                 }
  2824.  
  2825.                 goto e_Exit;
  2826.             }
  2827.         }
  2828.         else
  2829.         {
  2830.             goto e_Exit;
  2831.         }
  2832.     }
  2833.  
  2834.     // load the file to get the animation data
  2835.     hr = D3DXLoadMeshHierarchyFromX(file, D3DXMESH_SYSTEMMEM, m_pDevice, &Alloc, NULL, (LPD3DXFRAME*)&pFrameToDelete, &pAnimMixerToDelete);
  2836.     if (FAILED(hr))
  2837.         goto e_Exit;
  2838.  
  2839.     if (pAnimMixerToDelete == NULL)
  2840.     {
  2841.         MessageBox(NULL, "No animation data in file!", "Warning", MB_OK);
  2842.         goto e_Exit;
  2843.     }
  2844.  
  2845.     cAnimSets = pAnimMixerToDelete->GetNumAnimationSets();
  2846.  
  2847.     hr = m_pdeHead->m_pAnimMixer->CloneAnimationController(
  2848.                                 m_pdeHead->m_pAnimMixer->GetMaxNumAnimationOutputs(),
  2849.                                 m_pdeHead->m_pAnimMixer->GetMaxNumAnimationSets() + cAnimSets,
  2850.                                 m_pdeHead->m_pAnimMixer->GetMaxNumTracks(),
  2851.                                 m_pdeHead->m_pAnimMixer->GetMaxNumEvents(),
  2852.                                 &pAnimMixer);
  2853.     if (FAILED(hr))
  2854.         goto e_Exit;
  2855.  
  2856.     GXRELEASE(m_pdeHead->m_pAnimMixer);
  2857.     m_pdeHead->m_pAnimMixer = pAnimMixer;
  2858.     pAnimMixer = NULL;
  2859.     
  2860.  
  2861.     for (iAnimSet = 0; iAnimSet < cAnimSets; iAnimSet++)
  2862.     {
  2863.         pAnimMixerToDelete->GetAnimationSet(iAnimSet, &pAnimSet);
  2864.         m_pdeHead->m_pAnimMixer->RegisterAnimationSet(pAnimSet);
  2865.  
  2866.         GXRELEASE(pAnimSet);
  2867.     }
  2868.     
  2869.     m_pdeHead->m_pAnimMixer->AdvanceTime(m_pdeHead->fCurTime - m_pdeHead->m_pAnimMixer->GetTime(), NULL);
  2870.  
  2871.     UpdateAnimationsMenu();
  2872. e_Exit:
  2873.     //D3DXFrameDestroy(pFrameToDelete, &Alloc);
  2874.     GXRELEASE(pAnimMixerToDelete);
  2875.  
  2876.     delete pFrameToDelete;
  2877.  
  2878.     return;
  2879. }
  2880.