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 / savemesh.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2004-09-30  |  32.2 KB  |  1,169 lines

  1. /*//////////////////////////////////////////////////////////////////////////////
  2. //
  3. // File: savemesh.cpp
  4. //
  5. // Copyright (C) 1999 Microsoft Corporation. All Rights Reserved.
  6. //
  7. //
  8. //////////////////////////////////////////////////////////////////////////////*/
  9.  
  10. #include "mviewpch.h"
  11.  
  12. #if 0
  13. #include "XSkinExpTemplates.h"
  14. #include "rmxfguid.h"
  15. #define D3DRM_XTEMPLATES _D3DRM_XTEMPLATES2
  16. #include "rmxftmpl.h"
  17. typedef HRESULT (STDAPICALLTYPE *LPDIRECTXFILECREATE)(LPDIRECTXFILE*);
  18.  
  19. #include <locale.h>
  20.  
  21. extern const GUID* x_rgTemplateIds[];
  22. extern const GUID* x_rgPMTemplateIds[];
  23. //const GUID* x_rgTemplateIds[] = {&DXFILEOBJ_VertexDuplicationIndices, &DXFILEOBJ_FVFData};
  24. //const GUID* x_rgPMTemplateIds[] = {&DXFILEOBJ_PMAttributeRange, &DXFILEOBJ_PMVSplitRecord, &DXFILEOBJ_PMInfo};
  25.  
  26. #define WRITE_DWORD(pbCur, dword) {*(DWORD*)pbCur = dword; pbCur += sizeof(DWORD); }
  27. #define WRITE_FLOAT(pbCur, value) {*(float*)pbCur = value; pbCur += sizeof(float); }
  28. #define WRITE_VECTOR3(pbCur, vPos) {*(D3DXVECTOR3*)pbCur = vPos; pbCur += sizeof(D3DXVECTOR3); }
  29. #define WRITE_RGBA(pbCur, vPos) {*(D3DCOLORVALUE*)pbCur = vPos; pbCur += sizeof(D3DCOLORVALUE); }
  30. #define WRITE_RGB(pbCur, vColor) { WRITE_FLOAT(pbCur, vColor.r); WRITE_FLOAT(pbCur, vColor.g); WRITE_FLOAT(pbCur, vColor.b);}
  31.  
  32. struct SStringList
  33. {
  34.     SStringList(char *szString, SStringList *pHead)
  35.         :m_szString(szString), m_pNext(NULL)
  36.         {
  37.             // add self to list if one is provided
  38.             if (pHead != NULL)
  39.             {
  40.                 m_pNext = pHead->m_pNext;
  41.                 pHead->m_pNext = this;
  42.             }
  43.         }
  44.  
  45.     ~SStringList()
  46.     {
  47.         delete []m_szString;
  48.         delete m_pNext;
  49.     }
  50.  
  51.     char *m_szString;
  52.     SStringList *m_pNext;
  53. };
  54.  
  55. HRESULT
  56. AddNormals
  57.     (
  58.     LPDIRECTXFILESAVEOBJECT pxofsave,
  59.     PBYTE pbVertices,
  60.     DWORD cVertices,
  61.     PWORD rgwFaces,
  62.     PDWORD rgdwFaces,
  63.     DWORD cFaces,
  64.     DXCrackFVF &cfvf,
  65.     LPDIRECTXFILEDATA pParent
  66.     )
  67. {
  68.     HRESULT        hr = S_OK;
  69.     LPDIRECTXFILEDATA pDataObject = NULL;
  70.     LPBYTE         pbData;
  71.     LPBYTE         pbCur = NULL;
  72.     DWORD          cbSize;
  73.     PWORD          pwFace;
  74.     PDWORD         pdwFace;
  75.     DWORD          iFace;
  76.     DWORD          iVertex;
  77.  
  78.     GXASSERT(pbVertices != NULL);
  79.     GXASSERT(rgwFaces != NULL);
  80.     GXASSERT(pParent != NULL);
  81.  
  82.     cbSize = sizeof(DWORD) // nNormals
  83.              + 3*sizeof(float)*cVertices // normals
  84.              + sizeof(DWORD) // nFaces
  85.              + cFaces* // MeshFace array
  86.                 (sizeof(DWORD) //nFaceVertexIndices (number of normal indices)
  87.                  + 3*sizeof(DWORD)); // faceVertexIndices (normal indices)
  88.  
  89.     pbCur = pbData = new BYTE[cbSize];
  90.     if (pbData == NULL)
  91.     {
  92.         hr = E_OUTOFMEMORY;
  93.         goto e_Exit;
  94.     }
  95.  
  96.     // nNormals
  97.     WRITE_DWORD(pbCur, cVertices);
  98.  
  99.     // normals
  100.     for (iVertex = 0; iVertex < cVertices; iVertex++)
  101.     {
  102.         WRITE_VECTOR3(pbCur, *cfvf.PvGetNormal(cfvf.GetArrayElem(pbVertices, iVertex)));
  103.     }
  104.  
  105.     // nFaces
  106.     WRITE_DWORD(pbCur, cFaces);
  107.  
  108.     if (rgdwFaces != NULL)
  109.     {
  110.         // MeshFace array
  111.         for( iFace = 0; iFace < cFaces; iFace++ )
  112.         {
  113.             WRITE_DWORD(pbCur, 3); // nFaceVertexIndices (number of normal indices)
  114.  
  115.             pdwFace = rgdwFaces + iFace * 3;
  116.             WRITE_DWORD(pbCur, pdwFace[0]);
  117.             WRITE_DWORD(pbCur, pdwFace[1]);
  118.             WRITE_DWORD(pbCur, pdwFace[2]);
  119.         }
  120.     }
  121.     else
  122.     {
  123.         // MeshFace array
  124.         for( iFace = 0; iFace < cFaces; iFace++ )
  125.         {
  126.             WRITE_DWORD(pbCur, 3); // nFaceVertexIndices (number of normal indices)
  127.  
  128.             pwFace = rgwFaces + iFace * 3;
  129.             WRITE_DWORD(pbCur, pwFace[0]);
  130.             WRITE_DWORD(pbCur, pwFace[1]);
  131.             WRITE_DWORD(pbCur, pwFace[2]);
  132.         }
  133.     }
  134.  
  135.     hr = pxofsave->CreateDataObject(TID_D3DRMMeshNormals,
  136.                                     NULL,
  137.                                     NULL,
  138.                                     cbSize,
  139.                                     pbData,
  140.                                     &pDataObject
  141.                                     );
  142.     if (FAILED(hr))
  143.     {
  144.         OutputDebugString("Failed to create x file data object!");
  145.         goto e_Exit;
  146.     }
  147.  
  148.     hr = pParent->AddDataObject(pDataObject);
  149.     if (FAILED(hr))
  150.     {
  151.         OutputDebugString("Failed to add x file data object!");
  152.         goto e_Exit;
  153.     }
  154.  
  155.     // falling through
  156. e_Exit:
  157.     GXRELEASE(pDataObject);
  158.     delete []pbData;
  159.     return hr;
  160. }
  161.  
  162. HRESULT
  163. AddMaterial
  164.     (
  165.     LPDIRECTXFILESAVEOBJECT pxofsave,
  166.     CONST D3DXMATERIAL *pMaterial,
  167.     DWORD xFormat,
  168.     SStringList *pHead,
  169.     LPDIRECTXFILEDATA pParent
  170.     )
  171. {
  172.     LPDIRECTXFILEDATA pDataObject = NULL;
  173.     LPDIRECTXFILEDATA pTextureObject = NULL;
  174.     LPBYTE pbData = NULL;
  175.     DWORD          cbSize;
  176.     LPBYTE pbCur = NULL;
  177.     HRESULT    hr = S_OK;
  178.     char *szTextureFilename = NULL;
  179.     DWORD cchFilename;
  180.     SStringList *pNewStringTracker;
  181.  
  182.     GXASSERT(pMaterial != NULL);
  183.     GXASSERT(pxofsave != NULL);
  184.  
  185.     cbSize = 4*sizeof(float) // colorRGBA
  186.              + sizeof(float) //power
  187.              + 3*sizeof(float) //specularColor
  188.              + 3*sizeof(float); //emissiveColor
  189.  
  190.     pbCur = pbData = new BYTE[cbSize];
  191.     if (pbData == NULL)
  192.     {
  193.         OutputDebugString("Out of memory!");
  194.         hr = E_OUTOFMEMORY;
  195.         goto e_Exit;
  196.     }
  197.  
  198.     //RGBA
  199.     WRITE_RGBA(pbCur, pMaterial->MatD3D.Diffuse);
  200.     //power
  201.     WRITE_FLOAT(pbCur, pMaterial->MatD3D.Power);
  202.     // specular color
  203.     WRITE_RGB(pbCur, pMaterial->MatD3D.Specular);
  204.     // emissiveColor 
  205.     WRITE_RGB(pbCur, pMaterial->MatD3D.Emissive);
  206.  
  207.     hr = pxofsave->CreateDataObject(TID_D3DRMMaterial,
  208.                                     NULL,
  209.                                     NULL,
  210.                                     cbSize,
  211.                                     pbData,
  212.                                     &pDataObject
  213.                                     );
  214.     if (FAILED(hr))
  215.     {
  216.         OutputDebugString("Failed to create x file data object!");
  217.         goto e_Exit;
  218.     }
  219.  
  220.     hr = pParent->AddDataObject(pDataObject);
  221.     if (FAILED(hr))
  222.     {
  223.         OutputDebugString("Failed to add x file data object!");
  224.         goto e_Exit;
  225.     }
  226.  
  227.     // if text format, insert '\\', else just add texture file name
  228.     if (pMaterial->pTextureFilename != NULL)
  229.     {
  230.         char *pchCur;
  231.         char *pchDest;
  232.         DWORD cBackslashes;
  233.  
  234.         cchFilename = strlen(pMaterial->pTextureFilename) + 1;
  235.         if (xFormat == DXFILEFORMAT_TEXT)
  236.         {
  237.             pchCur = pMaterial->pTextureFilename;
  238.             cBackslashes = 0;
  239.             while (*pchCur != '\0')
  240.             {
  241.                 if (*pchCur == '\\')
  242.                     cBackslashes++;
  243.  
  244.                 pchCur += 1;
  245.             }
  246.  
  247.             szTextureFilename = new char[cchFilename + cBackslashes];
  248.             if (szTextureFilename == NULL)
  249.             {
  250.                 hr = E_OUTOFMEMORY;
  251.                 goto e_Exit;
  252.             }
  253.  
  254.             // allocate a node to track the string and add it to the list
  255.             pNewStringTracker = new SStringList(szTextureFilename, pHead);
  256.             if (pNewStringTracker == NULL)
  257.             {
  258.                 delete []szTextureFilename;
  259.                 hr = E_OUTOFMEMORY;
  260.                 goto e_Exit;
  261.             }
  262.  
  263.             pchDest = szTextureFilename;
  264.             pchCur = pMaterial->pTextureFilename;
  265.             while (*pchCur != '\0')
  266.             {
  267.                 *pchDest = *pchCur;
  268.  
  269.                 if (*pchCur == '\\')
  270.                 {
  271.                     pchDest += 1;
  272.                     *pchDest = *pchCur;
  273.                 }
  274.  
  275.                 pchCur += 1;
  276.                 pchDest += 1;
  277.             }
  278.             *pchDest = '\0';
  279.         }
  280.         else  // binary, just copy the filename... technically doesn't need to be copied, but cleans up exit code
  281.         {
  282.             szTextureFilename = new char[cchFilename];
  283.             if (szTextureFilename == NULL)
  284.             {
  285.                 hr = E_OUTOFMEMORY;
  286.                 goto e_Exit;
  287.             }
  288.             memcpy(szTextureFilename, pMaterial->pTextureFilename, sizeof(char) * cchFilename);
  289.         }
  290.  
  291.         cbSize = sizeof(TCHAR**);
  292.  
  293.         hr = pxofsave->CreateDataObject(TID_D3DRMTextureFilename,
  294.                                         NULL,
  295.                                         NULL,
  296.                                         cbSize,
  297.                                         &szTextureFilename,
  298.                                         &pTextureObject
  299.                                         );
  300.         if (FAILED(hr))
  301.         {
  302.             OutputDebugString("Failed to create x file data object!");
  303.             goto e_Exit;
  304.         }
  305.  
  306.         hr = pDataObject->AddDataObject(pTextureObject);
  307.         if (FAILED(hr))
  308.         {
  309.             OutputDebugString("Failed to add x file data object!");
  310.             goto e_Exit;
  311.         }
  312.     }
  313.  
  314.  
  315.     // falling through
  316. e_Exit:
  317.     // UNDONE UNDONE - need to figure how how to delete the texturefilename later
  318.     //delete []szTextureFilename;
  319.     GXRELEASE(pTextureObject);
  320.     GXRELEASE(pDataObject);
  321.     delete []pbData;
  322.     return hr;
  323. }
  324.  
  325. HRESULT AddTextureCoordinates
  326.     (
  327.     LPDIRECTXFILESAVEOBJECT pxofsave,
  328.     PBYTE pbVertices,
  329.     DWORD cVertices,
  330.     DXCrackFVF &cfvf,
  331.     LPDIRECTXFILEDATA pParent
  332.     )
  333. {
  334.     LPDIRECTXFILEDATA pDataObject = NULL;
  335.     LPBYTE pbData = NULL;
  336.     DWORD          cbSize;
  337.     LPBYTE pbCur = NULL;
  338.     HRESULT    hr = S_OK;
  339.     DWORD iVertex;
  340.     D3DXVECTOR2 *pvTexPos;
  341.  
  342.     GXASSERT(pxofsave != NULL);
  343.     GXASSERT(pbVertices != NULL);
  344.     GXASSERT(pParent != NULL);
  345.     GXASSERT(cVertices > 0);
  346.  
  347.     cbSize = sizeof(DWORD) //nTextureCoords
  348.              + cVertices * 2 * sizeof(float); //texture coords
  349.  
  350.     pbCur = pbData = new BYTE[cbSize];
  351.     if (pbData == NULL)
  352.     {
  353.         hr = E_OUTOFMEMORY;
  354.         goto e_Exit;
  355.     }
  356.  
  357.     WRITE_DWORD(pbCur, cVertices); //nTextureCoords
  358.  
  359.     for (iVertex = 0; iVertex < cVertices; iVertex++)
  360.     {
  361.         pvTexPos = cfvf.PuvGetTex1(cfvf.GetArrayElem(pbVertices, iVertex));
  362.  
  363.         WRITE_FLOAT(pbCur, pvTexPos->x); //u
  364.         WRITE_FLOAT(pbCur, pvTexPos->y); //v
  365.     }
  366.  
  367.     hr = pxofsave->CreateDataObject(TID_D3DRMMeshTextureCoords,
  368.                                     NULL,
  369.                                     NULL,
  370.                                     cbSize,
  371.                                     pbData,
  372.                                     &pDataObject
  373.                                     );
  374.     if (FAILED(hr))
  375.     {
  376.         OutputDebugString("Failed to create x file data object!");
  377.         goto e_Exit;
  378.     }
  379.  
  380.     hr = pParent->AddDataObject(pDataObject);
  381.     if (FAILED(hr))
  382.     {
  383.         OutputDebugString("Failed to add x file data object!");
  384.         goto e_Exit;
  385.     }
  386.  
  387.     // falling through
  388. e_Exit:
  389.     GXRELEASE(pDataObject);
  390.     delete []pbData;
  391.  
  392.     return hr;
  393. }
  394.  
  395. HRESULT AddVertexColors
  396.     (
  397.     LPDIRECTXFILESAVEOBJECT pxofsave,
  398.     PBYTE pbVertices,
  399.     DWORD cVertices,
  400.     DXCrackFVF &cfvf,
  401.     LPDIRECTXFILEDATA pParent
  402.     )
  403. {
  404.     LPDIRECTXFILEDATA pDataObject = NULL;
  405.     LPBYTE pbData = NULL;
  406.     DWORD cbSize;
  407.     LPBYTE pbCur = NULL;
  408.     HRESULT    hr = S_OK;
  409.     DWORD iVertex;
  410.     D3DXCOLOR color;
  411.  
  412.     GXASSERT(pxofsave != NULL);
  413.     GXASSERT(pbVertices != NULL);
  414.     GXASSERT(pParent != NULL);
  415.     GXASSERT(cVertices > 0);
  416.  
  417.     cbSize = sizeof(DWORD) //cVertexColorEntries
  418.              + cVertices * 5 * sizeof(float); //indexed color entries(index + RGBA)
  419.  
  420.     pbCur = pbData = new BYTE[cbSize];
  421.     if (pbData == NULL)
  422.     {
  423.         hr = E_OUTOFMEMORY;
  424.         goto e_Exit;
  425.     }
  426.  
  427.     WRITE_DWORD(pbCur, cVertices); //cVertexColorEntries
  428.  
  429.     for (iVertex = 0; iVertex < cVertices; iVertex++)
  430.     {
  431.         color = D3DXCOLOR(cfvf.ColorGetDiffuse(cfvf.GetArrayElem(pbVertices, iVertex)));
  432.  
  433.         WRITE_DWORD(pbCur, iVertex); // index
  434.         WRITE_FLOAT(pbCur, color.r); // r
  435.         WRITE_FLOAT(pbCur, color.g); // g
  436.         WRITE_FLOAT(pbCur, color.b); // b
  437.         WRITE_FLOAT(pbCur, color.a); // a
  438.     }
  439.  
  440.     hr = pxofsave->CreateDataObject(TID_D3DRMMeshVertexColors,
  441.                                     NULL,
  442.                                     NULL,
  443.                                     cbSize,
  444.                                     pbData,
  445.                                     &pDataObject
  446.                                     );
  447.     if (FAILED(hr))
  448.     {
  449.         OutputDebugString("Failed to create x file data object!");
  450.         goto e_Exit;
  451.     }
  452.  
  453.     hr = pParent->AddDataObject(pDataObject);
  454.     if (FAILED(hr))
  455.     {
  456.         OutputDebugString("Failed to add x file data object!");
  457.         goto e_Exit;
  458.     }
  459.  
  460.     // falling through
  461. e_Exit:
  462.     GXRELEASE(pDataObject);
  463.     delete []pbData;
  464.  
  465.     return hr;
  466. }
  467.  
  468. HRESULT AddVertexDuplicationIndices
  469.     (
  470.     LPDIRECTXFILESAVEOBJECT pxofsave,
  471.     LPD3DXMESH ptmMesh,
  472.     CONST DWORD *rgdwAdjacency,
  473.     LPDIRECTXFILEDATA pParent
  474.     )
  475. {
  476.     LPDIRECTXFILEDATA pDataObject = NULL;
  477.     PBYTE          pbData = NULL;
  478.     PBYTE          pbCur = NULL;
  479.     DWORD          cbSize;
  480.     DWORD          cVertices;
  481.     DWORD          cVerticesBeforeDuplication;
  482.     HRESULT        hr = S_OK;
  483.     DWORD          *rgiPointRep;
  484.     DWORD          iVertex;
  485.  
  486.     GXASSERT(pxofsave != NULL);
  487.     GXASSERT(ptmMesh != NULL);
  488.     GXASSERT(pParent != NULL);
  489.  
  490.     cVertices = ptmMesh->GetNumVertices();
  491.     cbSize = sizeof(DWORD) //nIndices
  492.              + sizeof(DWORD) //nVerticesBeforeDuplication
  493.              + cVertices*sizeof(DWORD); // array of indices
  494.  
  495.     pbCur = pbData = new BYTE[cbSize];
  496.     if (pbData == NULL)
  497.     {
  498.         hr = E_OUTOFMEMORY;
  499.         goto e_Exit;
  500.     }
  501.  
  502.     // the point reps go immediately after the two counts
  503.     rgiPointRep = (DWORD*)(pbCur + sizeof(DWORD) * 2);
  504.  
  505.     // compute the point reps directly into the buffer
  506.     hr = ptmMesh->ConvertAdjacencyToPointReps(rgdwAdjacency, rgiPointRep);
  507.     if (FAILED(hr))
  508.         goto e_Exit;
  509.  
  510.     // how many "logical" vertices are there
  511.     cVerticesBeforeDuplication = 0;
  512.     for (iVertex = 0; iVertex < cVertices; iVertex++)
  513.     {
  514.         if (rgiPointRep[iVertex] == iVertex)
  515.         {
  516.             cVerticesBeforeDuplication += 1;
  517.         }
  518.     }
  519.  
  520.     // if the point rep array is "identity", then there is no reason to save it
  521.     if (cVerticesBeforeDuplication == cVertices)
  522.     {
  523.         // skip saving an identity point rep array
  524.         goto e_Exit;
  525.     }
  526.  
  527.     WRITE_DWORD(pbCur, cVertices) // nIndices;
  528.     WRITE_DWORD(pbCur, cVerticesBeforeDuplication) // nVerticesBeforeDuplication
  529.  
  530.     hr = pxofsave->CreateDataObject(DXFILEOBJ_VertexDuplicationIndices,
  531.                                     NULL,
  532.                                     NULL,
  533.                                     cbSize,
  534.                                     pbData,
  535.                                     &pDataObject
  536.                                     );
  537.     if (FAILED(hr))
  538.     {
  539.         OutputDebugString("Failed to create x file data object!");
  540.         goto e_Exit;
  541.     }
  542.  
  543.     hr = pParent->AddDataObject(pDataObject);
  544.     if (FAILED(hr))
  545.     {
  546.         OutputDebugString("Failed to add x file data object!");
  547.         goto e_Exit;
  548.     }
  549.  
  550.     // falling through
  551. e_Exit:
  552.     GXRELEASE(pDataObject);
  553.  
  554.     delete []pbData;
  555.     return hr;
  556. }
  557.  
  558. HRESULT AddFaceMaterials
  559.     (
  560.     LPDIRECTXFILESAVEOBJECT pxofsave,
  561.     PDWORD rgiAttribIds,
  562.     DWORD cFaces,
  563.     CONST D3DXMATERIAL *rgMaterials,
  564.     DWORD cMaterials,
  565.     DWORD xFormat,
  566.     SStringList *pHead,
  567.     LPDIRECTXFILEDATA pParent
  568.     )
  569. {
  570.     HRESULT     hr = S_OK;
  571.     LPDIRECTXFILEDATA pDataObject = NULL;
  572.     LPBYTE      pbData = NULL;
  573.     LPBYTE      pbCur = NULL;
  574.     DWORD       cbSize;
  575.     DWORD       iFace;
  576.     //DWORD       iVertex;
  577.     DWORD       iMaterial;
  578.  
  579.     GXASSERT(pParent != NULL);
  580.     GXASSERT(rgMaterials != NULL);
  581.     GXASSERT(pxofsave != NULL);
  582.     GXASSERT(rgiAttribIds != NULL);
  583.     GXASSERT(cFaces > 0 && cMaterials > 0);
  584.  
  585.     cbSize = sizeof(DWORD) // nMaterials
  586.                 + sizeof(DWORD) // nFaceIndexes
  587.                 + cFaces * sizeof(DWORD); // face indexes
  588.  
  589.     pbCur = pbData = new BYTE[cbSize];
  590.     if (pbData == NULL)
  591.     {
  592.         return E_OUTOFMEMORY;
  593.     }
  594.  
  595.     WRITE_DWORD(pbCur, cMaterials); // nMaterials
  596.  
  597.     // face indexes
  598.     WRITE_DWORD(pbCur, cFaces); // nFaceIndexes
  599.     for( iFace = 0; iFace < cFaces; iFace++ )
  600.     {
  601.         WRITE_DWORD(pbCur, rgiAttribIds[iFace]);
  602.     }
  603.  
  604.     hr = pxofsave->CreateDataObject(TID_D3DRMMeshMaterialList,
  605.                                     NULL,
  606.                                     NULL,
  607.                                     cbSize,
  608.                                     pbData,
  609.                                     &pDataObject
  610.                                     );
  611.     if (FAILED(hr))
  612.     {
  613.         OutputDebugString("Failed to create x file data object!");
  614.         goto e_Exit;
  615.     }
  616.  
  617.     hr = pParent->AddDataObject(pDataObject);
  618.     if (FAILED(hr))
  619.     {
  620.         OutputDebugString("Failed to add x file data object!");
  621.         goto e_Exit;
  622.     }
  623.  
  624.     for (iMaterial = 0; iMaterial < cMaterials; iMaterial++)
  625.     {
  626.         hr = AddMaterial(pxofsave, &rgMaterials[iMaterial], xFormat, pHead, pDataObject);
  627.         if (FAILED(hr))
  628.             goto e_Exit;
  629.     }
  630.  
  631.     // falling through
  632. e_Exit:
  633.     GXRELEASE(pDataObject);
  634.  
  635.     delete []pbData;
  636.     return hr;
  637. }
  638.  
  639. HRESULT AddOtherFVFData
  640.     (
  641.     LPDIRECTXFILESAVEOBJECT pxofsave,
  642.     PBYTE pbPoints,
  643.     DWORD cVertices,
  644.     DWORD dwFVF,
  645.     DXCrackFVF &cfvfOrig,
  646.     LPDIRECTXFILEDATA pParent
  647.     )
  648. {
  649.     HRESULT     hr = S_OK;
  650.     LPDIRECTXFILEDATA pDataObject = NULL;
  651.     LPBYTE      pbData = NULL;
  652.     LPBYTE      pbCur = NULL;
  653.     DWORD       cbSize;
  654.     DWORD       iVertex;
  655.     DWORD       cbBytesPerVertex;
  656.     DXCrackFVF  cfvf(D3DFVF_XYZ);
  657.     DWORD       iWeight;
  658.     DWORD       iTexCoord;
  659.     DWORD       dwFVFOther;
  660.     PBYTE       pbCurVertex;
  661.     BOOL        bCopyTex1;
  662.     DWORD       rgdwTexCoordSizes[8];
  663.  
  664.     GXASSERT(pxofsave != NULL);
  665.     GXASSERT(pbPoints != NULL);
  666.     GXASSERT(cVertices > 0);
  667.     GXASSERT(pParent != NULL);
  668.  
  669.     dwFVFOther = dwFVF;
  670.  
  671.     // remove data added other places in the xfile
  672.     dwFVFOther &= ~D3DFVF_NORMAL;
  673.     dwFVFOther &= ~D3DFVF_DIFFUSE;
  674.  
  675.     // remove the texture if it is 2d
  676.     bCopyTex1 = cfvfOrig.BTex1();
  677.     if (cfvfOrig.BTex1() && (cfvfOrig.CbTexCoordSize(0) == 8))
  678.     {
  679.         // need to remove a texture coordinate and shift all other texture bits down
  680.         dwFVFOther = ((dwFVFOther & 0xffff) - D3DFVF_TEX1)
  681.                             | ((dwFVFOther & 0xffff0000) >> 2);
  682.  
  683.         bCopyTex1 = FALSE;
  684.     }
  685.     cfvfOrig.GetTexCoordSizes(rgdwTexCoordSizes);
  686.  
  687.     cfvf = DXCrackFVF(dwFVFOther);
  688.  
  689.     // even though the position is specified by the FVF, it is not stored there
  690.     cbBytesPerVertex = cfvf.m_cBytesPerVertex - 12;
  691.  
  692.     // if nothing left, skip adding this structure
  693.     if (cbBytesPerVertex == 0)
  694.     {
  695.         goto e_Exit;
  696.     }
  697.  
  698.     // had better be a multiple of 4
  699.     if (cbBytesPerVertex % 4 != 0)
  700.     {
  701.         hr = D3DERR_INVALIDCALL;
  702.         goto e_Exit;
  703.     }
  704.  
  705.     cbSize = sizeof(DWORD) // nMaterials
  706.                 + sizeof(DWORD) // nFaceIndexes
  707.                 + cVertices * cbBytesPerVertex; // face indexes
  708.  
  709.     pbCur = pbData = new BYTE[cbSize];
  710.     if (pbData == NULL)
  711.     {
  712.         return E_OUTOFMEMORY;
  713.     }
  714.  
  715.     WRITE_DWORD(pbCur, dwFVFOther);
  716.     WRITE_DWORD(pbCur, cVertices * cbBytesPerVertex / 4); // nFaceIndexes
  717.     pbCurVertex = pbPoints;
  718.     for( iVertex = 0; iVertex < cVertices; iVertex++ )
  719.     {
  720.         // skip position
  721.         pbCurVertex += sizeof(D3DXVECTOR3);
  722.  
  723.         for (iWeight = 0; iWeight < cfvfOrig.CWeights(); iWeight++)
  724.         {
  725.             WRITE_DWORD(pbCur, *(DWORD*)pbCurVertex);
  726.             pbCurVertex += sizeof(DWORD);
  727.         }
  728.  
  729.         if (cfvfOrig.BNormal())
  730.         {
  731.             pbCurVertex += sizeof(D3DXVECTOR3);
  732.         }
  733.  
  734.         if (cfvfOrig.BDiffuse())
  735.         {
  736.             if (cfvf.BDiffuse())
  737.                 WRITE_DWORD(pbCur, *(DWORD*)pbCurVertex);
  738.  
  739.             pbCurVertex += sizeof(DWORD);
  740.         }
  741.  
  742.         if (cfvfOrig.BSpecular())
  743.         {
  744.             WRITE_DWORD(pbCur, *(DWORD*)pbCurVertex);
  745.             pbCurVertex += sizeof(DWORD);
  746.         }
  747.  
  748.         // first either skip or copy the first texture coordinate
  749.         if (bCopyTex1)
  750.         {
  751.             memcpy(pbCur, pbCurVertex, rgdwTexCoordSizes[0]);
  752.             pbCur += rgdwTexCoordSizes[0];
  753.             pbCurVertex += rgdwTexCoordSizes[0];
  754.         }
  755.         else
  756.         {
  757.             pbCurVertex += rgdwTexCoordSizes[0];
  758.         }
  759.  
  760.         // next copy the other texture coordinates
  761.         if (cfvfOrig.CTexCoords() > 1)
  762.         {
  763.             for (iTexCoord = 1; iTexCoord < cfvfOrig.CTexCoords(); iTexCoord++)
  764.             {
  765.                 memcpy(pbCur, pbCurVertex, rgdwTexCoordSizes[iTexCoord]);
  766.                 pbCur += rgdwTexCoordSizes[iTexCoord];
  767.                 pbCurVertex += rgdwTexCoordSizes[iTexCoord];
  768.             }
  769.         }
  770.     }
  771.  
  772.     hr = pxofsave->CreateDataObject(DXFILEOBJ_FVFData,
  773.                                     NULL,
  774.                                     NULL,
  775.                                     cbSize,
  776.                                     pbData,
  777.                                     &pDataObject
  778.                                     );
  779.     if (FAILED(hr))
  780.     {
  781.         OutputDebugString("Failed to create x file data object!");
  782.         goto e_Exit;
  783.     }
  784.  
  785.     hr = pParent->AddDataObject(pDataObject);
  786.     if (FAILED(hr))
  787.     {
  788.         OutputDebugString("Failed to add x file data object!");
  789.         goto e_Exit;
  790.     }
  791.  
  792.     // falling through
  793. e_Exit:
  794.     GXRELEASE(pDataObject);
  795.  
  796.     delete []pbData;
  797.     return hr;
  798. }
  799.  
  800. // implements mesh saving with pm data
  801. //
  802. HRESULT WINAPI D3DXSaveMeshToXofEx
  803.     (
  804.     LPDIRECTXFILESAVEOBJECT pxofsave,
  805.     LPD3DXMESH pMesh,
  806.     CONST DWORD *rgdwAdjacency,
  807.     CONST LPD3DXMATERIAL rgMaterials,
  808.     DWORD cMaterials,
  809.     DWORD xFormat,
  810.     PBYTE pbPMData,
  811.     DWORD cbPMData,
  812.     LPDIRECTXFILEDATA *ppDataObject
  813.     )
  814. {
  815.     HRESULT hr = S_OK;
  816.  
  817.     DWORD cFaces;
  818.     DWORD cVertices;
  819.     DWORD iVertex;
  820.     DWORD iFace;
  821.     PBYTE pbPoints = NULL;
  822.     PBYTE pbPoint;
  823.     LPDIRECT3DVERTEXBUFFER9 pVertexBuffer = NULL;
  824.     UINT16 *rgwFaces = NULL;
  825.     DWORD *rgdwFaces = NULL;
  826.     LPDIRECT3DINDEXBUFFER9 pIndexBuffer = NULL;
  827.     LPDIRECTXFILEDATA pDataObject = NULL;
  828.     LPDIRECTXFILEDATA pPMDataObject = NULL;
  829.     PBYTE pbCur;
  830.     PBYTE pbData = NULL;
  831.     DWORD cbSize;
  832.     DWORD *rgiAttribIds = NULL;
  833.     DXCrackFVF cfvf(D3DFVF_XYZ);
  834.     DWORD dwOptions;
  835.     LPSTR szLocale;
  836.     SStringList StringHead(NULL, NULL);  // head of list and will be deleted on exit of function
  837.  
  838.     szLocale = _strdup(setlocale(LC_NUMERIC, NULL));
  839.  
  840.     if(!szLocale || strcmp(szLocale, "C"))
  841.         setlocale(LC_NUMERIC, "C");
  842.  
  843.     if ((pMesh == NULL) || ((rgMaterials == NULL) && (cMaterials > 0)) || (ppDataObject == NULL) || (pxofsave == NULL))
  844.     {
  845. #if DBG
  846.         if (pMesh == NULL)
  847.             DPF(0, "D3DXSaveMeshToXof: No mesh specified to save");
  848.         else if (ppDataObject == NULL)
  849.             DPF(0, "D3DXSaveMeshToXof: No data object buffer provided for returning saved mesh");
  850.         else if (pxofsave == NULL)
  851.             DPF(0, "D3DXSaveMeshToXof: No save object provided to save into");
  852.         else if ((rgMaterials == NULL) && (cMaterials > 0))
  853.             DPF(0, "D3DXSaveMeshToXof: Non-zero material count when material array is NULL");
  854. #endif
  855.         hr = D3DERR_INVALIDCALL;
  856.         goto e_Exit;
  857.     }
  858.  
  859.     dwOptions = pMesh->GetOptions();
  860.     if (dwOptions & D3DXMESH_WRITEONLY)
  861.     {
  862. #if DBG
  863.         if (dwOptions & D3DXMESH_IB_WRITEONLY)
  864.             DPF(0, "D3DXSaveMeshToX:  Cannot save when index buffer is read only.");
  865.         else // if (dwOptions & D3DXMESH_VB_WRITEONLY)
  866.             DPF(0, "D3DXSaveMeshToX:  Cannot save when vertex buffer is read only.");
  867. #endif
  868.         hr = D3DERR_INVALIDCALL;
  869.         goto e_Exit;
  870.     }
  871.  
  872.     hr = pMesh->GetVertexBuffer(&pVertexBuffer);
  873.     if (FAILED(hr))
  874.         goto e_Exit;
  875.  
  876.     hr = pVertexBuffer->Lock(0,0, &pbPoints, D3DLOCK_NOSYSLOCK );
  877.     if (FAILED(hr))
  878.         goto e_Exit;
  879.  
  880.     hr = pMesh->GetIndexBuffer(&pIndexBuffer);
  881.     if (FAILED(hr))
  882.         goto e_Exit;
  883.  
  884.     hr = pMesh->LockAttributeBuffer(D3DLOCK_READONLY, &rgiAttribIds);
  885.     if (FAILED(hr))
  886.         goto e_Exit;
  887.  
  888.     hr = pIndexBuffer->Lock(0,0, (PVOID*)&rgwFaces, D3DLOCK_NOSYSLOCK );
  889.     if (FAILED(hr))
  890.         goto e_Exit;
  891.  
  892.     if (pMesh->GetOptions() & D3DXMESH_32BIT)
  893.     {
  894.         rgdwFaces = (DWORD*)rgwFaces;
  895.     }
  896.  
  897.     cVertices = pMesh->GetNumVertices();
  898.     cFaces = pMesh->GetNumFaces();
  899.     cbSize = sizeof(DWORD) // nVertices
  900.              + cVertices*sizeof(float)*3 // vertices
  901.              + sizeof(DWORD) // nFaces
  902.              + cFaces*(sizeof(DWORD) /*nFaceVertexIndices*/
  903.                             + sizeof(DWORD)*3 /*faceVertexIndices*/); // faces
  904.  
  905.     cfvf = DXCrackFVF(pMesh->GetFVF());
  906.  
  907.     pbCur = pbData = new BYTE[cbSize];
  908.     if( NULL == pbData )
  909.     {
  910.         hr = E_OUTOFMEMORY;
  911.         goto e_Exit;;
  912.     }
  913.  
  914.     // write cVertices
  915.     WRITE_DWORD(pbCur, cVertices);
  916.  
  917.     for (iVertex = 0; iVertex < cVertices; iVertex++)
  918.     {
  919.         pbPoint = cfvf.GetArrayElem(pbPoints, iVertex);
  920.         WRITE_VECTOR3(pbCur, *cfvf.PvGetPosition(pbPoint));
  921.     }
  922.  
  923.     // write cFaces
  924.     WRITE_DWORD(pbCur, cFaces);
  925.  
  926.     if (rgdwFaces == NULL)
  927.     {
  928.         for (iFace = 0; iFace < cFaces; iFace++)
  929.         {
  930.             WRITE_DWORD(pbCur, 3);
  931.  
  932.             WRITE_DWORD(pbCur, (DWORD)rgwFaces[iFace * 3 + 0]);
  933.             WRITE_DWORD(pbCur, (DWORD)rgwFaces[iFace * 3 + 1]);
  934.             WRITE_DWORD(pbCur, (DWORD)rgwFaces[iFace * 3 + 2]);
  935.         }
  936.     }
  937.     else
  938.     {
  939.         for (iFace = 0; iFace < cFaces; iFace++)
  940.         {
  941.             WRITE_DWORD(pbCur, 3);
  942.  
  943.             WRITE_DWORD(pbCur, rgdwFaces[iFace * 3 + 0]);
  944.             WRITE_DWORD(pbCur, rgdwFaces[iFace * 3 + 1]);
  945.             WRITE_DWORD(pbCur, rgdwFaces[iFace * 3 + 2]);
  946.         }
  947.     }
  948.  
  949.     hr = pxofsave->CreateDataObject(TID_D3DRMMesh,
  950.                                     NULL,
  951.                                     NULL,
  952.                                     cbSize,
  953.                                     pbData,
  954.                                     &pDataObject
  955.                                     );
  956.     if (FAILED(hr))
  957.         goto e_Exit;
  958.  
  959.     if (cfvf.BNormal())
  960.     {
  961.         hr = AddNormals(pxofsave, pbPoints, cVertices, rgwFaces, rgdwFaces, cFaces, cfvf, pDataObject);
  962.         if (FAILED(hr))
  963.             goto e_Exit;
  964.     }
  965.  
  966.     pIndexBuffer->Unlock();
  967.     rgwFaces = NULL;
  968.  
  969.     // if there is a tex1 that has a sizeof 2 floats, then output it here, 
  970.     //    otherwise it will go in the other fvf data section
  971.     if (cfvf.BTex1() && (cfvf.CbTexCoordSize(0) == 8))
  972.     {
  973.         hr = AddTextureCoordinates(pxofsave, pbPoints, cVertices, cfvf, pDataObject);
  974.         if (FAILED(hr))
  975.             goto e_Exit;
  976.     }
  977.  
  978.     if (cfvf.BDiffuse())
  979.     {
  980.         hr = AddVertexColors(pxofsave, pbPoints, cVertices, cfvf, pDataObject);
  981.         if (FAILED(hr))
  982.             goto e_Exit;
  983.     }
  984.  
  985.     if (cMaterials > 0)
  986.     {
  987.         hr = AddFaceMaterials(pxofsave, rgiAttribIds, cFaces, rgMaterials, cMaterials, xFormat, &StringHead, pDataObject);
  988.         if (FAILED(hr))
  989.             goto e_Exit;
  990.     }
  991.  
  992.     // add adjacency info if present
  993.     if (rgdwAdjacency != NULL)
  994.     {
  995.         hr = AddVertexDuplicationIndices(pxofsave, pMesh, rgdwAdjacency, pDataObject);
  996.         if (FAILED(hr))
  997.             goto e_Exit;
  998.     }
  999.  
  1000.     hr = AddOtherFVFData(pxofsave, pbPoints, cVertices, pMesh->GetFVF(), cfvf, pDataObject);
  1001.     if (FAILED(hr))
  1002.         goto e_Exit;
  1003.  
  1004.     // if PM data provided, save it in a PMInfo group
  1005.     if (pbPMData != NULL)
  1006.     {
  1007.         GXASSERT(cbPMData > 0);
  1008.  
  1009.         hr = pxofsave->CreateDataObject(DXFILEOBJ_PMInfo,
  1010.                                         NULL,
  1011.                                         NULL,
  1012.                                         cbPMData,
  1013.                                         pbPMData,
  1014.                                         &pPMDataObject
  1015.                                         );
  1016.         if (FAILED(hr))
  1017.             goto e_Exit;
  1018.  
  1019.         hr = pDataObject->AddDataObject(pPMDataObject);
  1020.         if (FAILED(hr))
  1021.         {
  1022.             goto e_Exit;
  1023.         }
  1024.     }
  1025.  
  1026.     *ppDataObject = pDataObject;
  1027.     pDataObject = NULL;
  1028.  
  1029. e_Exit:
  1030.     if (pbPoints != NULL)
  1031.     {
  1032.         GXASSERT(pVertexBuffer != NULL);
  1033.         pVertexBuffer->Unlock();
  1034.     }
  1035.     GXRELEASE(pVertexBuffer);
  1036.  
  1037.     if (rgwFaces != NULL)
  1038.     {
  1039.         GXASSERT(pIndexBuffer != NULL);
  1040.         pIndexBuffer->Unlock();
  1041.     }
  1042.     GXRELEASE(pIndexBuffer);
  1043.  
  1044.     if (rgiAttribIds != NULL)
  1045.     {
  1046.         pMesh->UnlockAttributeBuffer();
  1047.     }
  1048.  
  1049.     delete []pbData;
  1050.     GXRELEASE(pDataObject);
  1051.     GXRELEASE(pPMDataObject);
  1052.  
  1053.     if(szLocale && strcmp(szLocale, "C"))
  1054.         setlocale(LC_NUMERIC, szLocale);
  1055.  
  1056.     if(szLocale)
  1057.         free(szLocale);
  1058.  
  1059.     return hr;
  1060. }
  1061.  
  1062.  
  1063. // implements mesh saving with pm data
  1064. //
  1065. HRESULT WINAPI D3DXSaveMeshToXEx
  1066.     (
  1067.     char *szFilename,
  1068.     LPD3DXMESH pMesh,
  1069.     CONST DWORD *rgdwAdjacency,
  1070.     CONST LPD3DXMATERIAL rgMaterials,
  1071.     DWORD cMaterials,
  1072.     DWORD xFormat,
  1073.     PBYTE pbPMData,
  1074.     DWORD cbPMData
  1075.     )
  1076. {
  1077.     HRESULT hr = S_OK;
  1078.  
  1079.     LPDIRECTXFILEDATA pDataObject = NULL;
  1080.     LPDIRECTXFILE pxofapi = NULL;
  1081.     LPDIRECTXFILESAVEOBJECT pxofsave = NULL;
  1082.     HINSTANCE hXof;
  1083.     LPDIRECTXFILECREATE pfnDirectXFileCreate;
  1084.  
  1085.  
  1086.     // Create Xfile parser
  1087.     if(!(hXof = (HINSTANCE) GetModuleHandle("d3dxof.dll")) &&
  1088.        !(hXof = (HINSTANCE) LoadLibrary("d3dxof.dll")))
  1089.     {
  1090.         hr = HRESULT_FROM_WIN32(GetLastError());
  1091.         goto e_Exit;
  1092.     }
  1093.  
  1094.     if(!(pfnDirectXFileCreate = (LPDIRECTXFILECREATE) GetProcAddress(hXof, "DirectXFileCreate")))
  1095.     {
  1096.         hr = HRESULT_FROM_WIN32(GetLastError());
  1097.         goto e_Exit;
  1098.     }
  1099.  
  1100.     hr = pfnDirectXFileCreate(&pxofapi);
  1101.     if (FAILED(hr))
  1102.         goto e_Exit;
  1103.  
  1104.     // Register templates for d3drm.
  1105.     hr = pxofapi->RegisterTemplates((LPVOID)D3DRM_XTEMPLATES,
  1106.                                     D3DRM_XTEMPLATE_BYTES);
  1107.     if (FAILED(hr))
  1108.         goto e_Exit;
  1109.  
  1110.     hr = pxofapi->RegisterTemplates((LPVOID)XSKINEXP_TEMPLATES,
  1111.                                     strlen(XSKINEXP_TEMPLATES));
  1112.     if (FAILED(hr))
  1113.         goto e_Exit;
  1114.  
  1115.     hr = pxofapi->RegisterTemplates((LPVOID)XEXTENSIONS_TEMPLATES,
  1116.                                     strlen(XEXTENSIONS_TEMPLATES));
  1117.     if (FAILED(hr))
  1118.         goto e_Exit;
  1119.  
  1120.     hr = pxofapi->CreateSaveObject(szFilename,    // filename
  1121.                                    xFormat,  // binary or text
  1122.                                    &pxofsave);
  1123.     if (FAILED(hr))
  1124.         goto e_Exit;
  1125.  
  1126.     hr = pxofsave->SaveTemplates(2, x_rgTemplateIds);
  1127.     if (FAILED(hr))
  1128.         goto e_Exit;
  1129.  
  1130.     if (pbPMData != NULL)
  1131.     {
  1132.         hr = pxofsave->SaveTemplates(3, x_rgPMTemplateIds);
  1133.         if (FAILED(hr))
  1134.             goto e_Exit;
  1135.     }
  1136.  
  1137.     hr = D3DXSaveMeshToXofEx(pxofsave, pMesh, rgdwAdjacency, rgMaterials, cMaterials, xFormat, pbPMData, cbPMData,&pDataObject);
  1138.     if (FAILED(hr))
  1139.         goto e_Exit;
  1140.  
  1141.  
  1142.     hr = pxofsave->SaveData(pDataObject);
  1143.     if (FAILED(hr))
  1144.         goto e_Exit;
  1145.  
  1146. e_Exit:
  1147.     GXRELEASE(pDataObject);
  1148.     GXRELEASE(pxofapi);
  1149.     GXRELEASE(pxofsave);
  1150.  
  1151.     return hr;
  1152. }
  1153.  
  1154. HRESULT WINAPI 
  1155.     D3DXSaveMeshToXof(
  1156.         LPDIRECTXFILESAVEOBJECT pSaveObject, 
  1157.         LPD3DXMESH pMesh,
  1158.         CONST DWORD *rgdwAdjacency,
  1159.         CONST LPD3DXMATERIAL rgMaterials,
  1160.         DWORD cMaterials,
  1161.         DWORD xFormat,
  1162.         LPDIRECTXFILEDATA *ppDataObject)
  1163. {
  1164.     return D3DXSaveMeshToXofEx(pSaveObject, pMesh, rgdwAdjacency, rgMaterials, cMaterials, xFormat, NULL, 0, ppDataObject);
  1165. }
  1166.  
  1167.  
  1168. #endif
  1169.