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 / gxu / stripoutline.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2004-09-30  |  26.2 KB  |  910 lines

  1. /*//////////////////////////////////////////////////////////////////////////////
  2. //
  3. // File: stripoutline.cpp
  4. //
  5. // Copyright (C) 1999 Microsoft Corporation. All Rights Reserved.
  6. //
  7. //
  8. //////////////////////////////////////////////////////////////////////////////*/
  9.  
  10. #include "pchgxu.h"
  11.  
  12. #include "StripOutline.h"
  13.  
  14. #define SKINNEDFVF D3DFVF_XYZB4|D3DFVF_TEX5|D3DFVF_TEXCOORDSIZE3(0)|D3DFVF_TEXCOORDSIZE4(1)|D3DFVF_TEXCOORDSIZE3(2)|D3DFVF_TEXCOORDSIZE4(3)|D3DFVF_TEXCOORDSIZE3(4)
  15. #define INDEXSKINNEDFVF D3DFVF_XYZB5|D3DFVF_TEX7|D3DFVF_TEXCOORDSIZE3(0)|D3DFVF_TEXCOORDSIZE4(1)|D3DFVF_TEXCOORDSIZE1(2)|D3DFVF_TEXCOORDSIZE3(3)|D3DFVF_TEXCOORDSIZE4(4)|D3DFVF_TEXCOORDSIZE1(5)|D3DFVF_TEXCOORDSIZE3(6)|D3DFVF_LASTBETA_D3DCOLOR
  16.  
  17.  
  18. void CopyWeights
  19.     (
  20.     float *pfWeightSrc,
  21.     DWORD cWeightsSrc,
  22.     float *pfWeightDest,
  23.     DWORD cWeightsDest
  24.     );
  25.  
  26. void CopyIndexedWeights
  27.     (
  28.     float *pfWeightSrc,
  29.     DWORD cWeightsSrc,
  30.     float *pfWeightDest,
  31.     DWORD cWeightsDest
  32.     );
  33.  
  34. CStripOutline::CStripOutline()
  35.     :m_cfvf(D3DFVF_XYZ),
  36.      m_bSkinning(FALSE),
  37.      m_bIndexSkinning(FALSE),
  38.      m_bHWVertexShaders(FALSE),
  39.      m_pVertexBuffer(NULL),
  40.      m_rgaeAttributeTable(NULL),
  41.      m_caeAttributeTable(0),
  42.      m_cLines(0),
  43.      m_cVertices(0),
  44.      m_pDecl(NULL)
  45. {
  46. }
  47.  
  48. CStripOutline::~CStripOutline()
  49. {
  50.     GXRELEASE(m_pVertexBuffer);
  51.     GXRELEASE(m_pDecl);
  52.     delete []m_rgaeAttributeTable;
  53. }
  54.  
  55. bool BConnected(PUINT pwFace1, PUINT pwFace2)
  56. {
  57.     UINT cSharedPoints;
  58.     UINT iPoint1;
  59.     UINT iPoint2;
  60.  
  61.     cSharedPoints = 0;
  62.     for (iPoint1 = 0; iPoint1 < 3; iPoint1++)
  63.     {
  64.         for (iPoint2 = 0; iPoint2 < 3; iPoint2++)
  65.         {
  66.             if (pwFace1[iPoint1] == pwFace2[iPoint2])
  67.             {
  68.                 cSharedPoints += 1;
  69.  
  70.                 break;
  71.             }
  72.         }
  73.     }
  74.  
  75.     GXASSERT(cSharedPoints <= 3);
  76.  
  77.     return cSharedPoints >= 2;
  78. }
  79.  
  80. void
  81. CStripOutline::AppendPoint
  82.     (
  83.     CD3DXCrackDecl1 &cdMesh, 
  84.     PUINT pwFace, 
  85.     PBYTE pvMeshPoints, 
  86.     PBYTE pvLinePoints, 
  87.     UINT &iCurPoint
  88.     )
  89. {
  90.     D3DXVECTOR3 vTemp(0,0,0);
  91.     UINT iPoint;
  92.     PVOID pvPoint;
  93.  
  94.     for (iPoint = 0; iPoint < 3; iPoint++)
  95.     {
  96.         pvPoint = cdMesh.GetArrayElem((PBYTE)pvMeshPoints, pwFace[iPoint]);
  97.         vTemp += *cdMesh.PvGetPosition((PBYTE)pvPoint);
  98.     }
  99.  
  100.     vTemp /= 3.0f;
  101.  
  102.     pvPoint = m_cfvf.GetArrayElem(pvLinePoints, iCurPoint);
  103.  
  104.     m_cfvf.SetPosition(pvPoint, (D3DXVECTOR3*)&vTemp);
  105.  
  106.     iCurPoint += 1;
  107. }
  108.  
  109. void
  110. CStripOutline::AppendMidpoint
  111.     (
  112.     CD3DXCrackDecl1 &cdMesh, 
  113.     PUINT pwFace1, 
  114.     PUINT pwFace2, 
  115.     PBYTE pvMeshPoints, 
  116.     PBYTE pvLinePoints, 
  117.     UINT &iCurPoint
  118.     )
  119. {
  120.     D3DXVECTOR3 vTemp(0,0,0);
  121.     UINT iPoint1;
  122.     UINT iPoint2;
  123.     PVOID pvPoint;
  124.  
  125.     GXASSERT(BConnected(pwFace1, pwFace2));
  126.  
  127.     for (iPoint1 = 0; iPoint1 < 3; iPoint1++)
  128.     {
  129.         for (iPoint2 = 0; iPoint2 < 3; iPoint2++)
  130.         {
  131.             if (pwFace1[iPoint1] == pwFace2[iPoint2])
  132.             {
  133.                 pvPoint = cdMesh.GetArrayElem(pvMeshPoints, pwFace1[iPoint1]);
  134.                 vTemp += *cdMesh.PvGetPosition((PBYTE)pvPoint);
  135.  
  136.                 break;
  137.             }
  138.         }
  139.     }
  140.  
  141.     vTemp /= 2.0f;
  142.  
  143.     pvPoint = m_cfvf.GetArrayElem(pvLinePoints, iCurPoint);
  144.  
  145.     m_cfvf.SetPosition(pvPoint, (D3DXVECTOR3*)&vTemp);
  146.  
  147.     iCurPoint += 1;
  148. }
  149.  
  150. void
  151. CStripOutline::AppendSkinnedMidpoint
  152.     (
  153.     CD3DXCrackDecl1 &cdMesh, 
  154.     PUINT pwFace1, 
  155.     PUINT pwFace2, 
  156.     PBYTE pvMeshPoints, 
  157.     PBYTE pvLinePoints, 
  158.     UINT &iCurPoint
  159.     )
  160. {
  161.     PBYTE pvDestPoint;
  162.     D3DXVECTOR3 vMidPoint(0.5f, 0.5f, 0.0f);
  163.     DWORD iPoint1;
  164.     DWORD iPoint2;
  165.     DWORD iEdge = UNUSED32;
  166.  
  167.     GXASSERT(BConnected(pwFace1, pwFace2));
  168.  
  169.     // find the edge connecting the two faces
  170.     for (iPoint1 = 0; iPoint1 < 3; iPoint1++)
  171.     {
  172.         for (iPoint2 = 0; iPoint2 < 3; iPoint2++)
  173.         {
  174.             if ((pwFace1[iPoint1] == pwFace2[(iPoint2+1)%3]) && (pwFace1[(iPoint1+1)%3] == pwFace2[iPoint2]))
  175.             {
  176.                 iEdge = iPoint1;
  177.                 break;
  178.             }
  179.         }
  180.     }
  181.  
  182.     pvDestPoint = m_cfvf.GetArrayElem(pvLinePoints, iCurPoint);
  183.  
  184.     AppendSkinnedPoint(cdMesh, pwFace1, iEdge, pvMeshPoints, pvLinePoints, iCurPoint);
  185.  
  186.     // the third position should be ignored!
  187.     m_cfvf.SetTexCoord(pvDestPoint, 4, &vMidPoint);
  188. }
  189.  
  190. void
  191. CStripOutline::AppendSkinnedPoint
  192.     (
  193.     CD3DXCrackDecl1 &cdMesh, 
  194.     PUINT pwFace1, 
  195.     DWORD iEdge,
  196.     PBYTE pvMeshPoints, 
  197.     PBYTE pvLinePoints, 
  198.     UINT &iCurPoint
  199.     )
  200. {
  201.     PBYTE pvDestPoint;
  202.     PBYTE pvPoint;
  203.     D3DXVECTOR3 vAvg(1.0f/3.0f,1.0f/3.0f,1.0f/3.0f);
  204.  
  205.     pvDestPoint = m_cfvf.GetArrayElem(pvLinePoints, iCurPoint);
  206.  
  207.     // Point 0 - first point on edge shared with another triangle
  208.     pvPoint = cdMesh.GetArrayElem(pvMeshPoints, pwFace1[iEdge]);
  209.  
  210.     // first position goes in standard position spot
  211.     m_cfvf.SetPosition(pvDestPoint, cdMesh.PvGetPosition(pvPoint));
  212.  
  213.     // first set of weights go in standard spot - expand to standard length
  214.     CopyWeights(cdMesh.PfGetWeights(pvPoint), cdMesh.CWeights(), m_cfvf.PfGetWeights(pvDestPoint), m_cfvf.CWeights());
  215.  
  216.     // Point 1 - other point on edge shared with another triangle
  217.     pvPoint = cdMesh.GetArrayElem(pvMeshPoints, pwFace1[(iEdge+1)%3]);
  218.  
  219.     // second position goes in first texture coord
  220.     m_cfvf.SetTexCoord(pvDestPoint, 0, cdMesh.PvGetPosition(pvPoint));
  221.  
  222.     // second set of weights go in second texture coord- expand to standard length
  223.     CopyWeights(cdMesh.PfGetWeights(pvPoint), cdMesh.CWeights(), (float*)m_cfvf.PxyzwGetTexCoord(pvDestPoint, 1), m_cfvf.CWeights());
  224.  
  225.     // Point 2 - point NOT on edge shared with another triangle
  226.     pvPoint = cdMesh.GetArrayElem(pvMeshPoints, pwFace1[(iEdge+2)%3]);
  227.  
  228.     // third position goes in the third texture coordinate
  229.     m_cfvf.SetTexCoord(pvDestPoint, 2, cdMesh.PvGetPosition(pvPoint));
  230.  
  231.     // third set of weights go in fourth texture coord- expand to standard length
  232.     CopyWeights(cdMesh.PfGetWeights(pvPoint), cdMesh.CWeights(), (float*)m_cfvf.PxyzwGetTexCoord(pvDestPoint, 3), m_cfvf.CWeights());
  233.  
  234.  
  235.     // the third position should be added in
  236.     m_cfvf.SetTexCoord(pvDestPoint, 4, &vAvg);
  237.  
  238.     iCurPoint += 1;
  239. }
  240.  
  241. void
  242. CStripOutline::AppendIndexSkinnedMidpoint
  243.     (
  244.     CD3DXCrackDecl1 &cdMesh, 
  245.     PUINT pwFace1, 
  246.     PUINT pwFace2, 
  247.     PBYTE pvMeshPoints, 
  248.     PBYTE pvLinePoints, 
  249.     UINT &iCurPoint
  250.     )
  251. {
  252.     PBYTE pvDestPoint;
  253.     D3DXVECTOR3 vMidPoint(0.5f, 0.5f, 0.0f);
  254.     DWORD iPoint1;
  255.     DWORD iPoint2;
  256.     DWORD iEdge = UNUSED32;
  257.  
  258.     GXASSERT(BConnected(pwFace1, pwFace2));
  259.  
  260.     // find the edge connecting the two faces
  261.     for (iPoint1 = 0; iPoint1 < 3; iPoint1++)
  262.     {
  263.         for (iPoint2 = 0; iPoint2 < 3; iPoint2++)
  264.         {
  265.             if ((pwFace1[iPoint1] == pwFace2[(iPoint2+1)%3]) && (pwFace1[(iPoint1+1)%3] == pwFace2[iPoint2]))
  266.             {
  267.                 iEdge = iPoint1;
  268.                 break;
  269.             }
  270.         }
  271.     }
  272.  
  273.     pvDestPoint = m_cfvf.GetArrayElem(pvLinePoints, iCurPoint);
  274.  
  275.     AppendIndexSkinnedPoint(cdMesh, pwFace1, iEdge, pvMeshPoints, pvLinePoints, iCurPoint);
  276.  
  277.     // the third position should be ignored!
  278.     m_cfvf.SetTexCoord(pvDestPoint, 6, &vMidPoint);
  279. }
  280.  
  281. void
  282. CStripOutline::AppendIndexSkinnedPoint
  283.     (
  284.     CD3DXCrackDecl1 &cdMesh, 
  285.     PUINT pwFace1, 
  286.     DWORD iEdge,
  287.     PBYTE pvMeshPoints, 
  288.     PBYTE pvLinePoints, 
  289.     UINT &iCurPoint
  290.     )
  291. {
  292.     PBYTE pvDestPoint;
  293.     PBYTE pvPoint;
  294.     D3DXVECTOR3 vAvg(1.0f/3.0f,1.0f/3.0f,1.0f/3.0f);
  295.  
  296.     pvDestPoint = m_cfvf.GetArrayElem(pvLinePoints, iCurPoint);
  297.  
  298.     // Point 0 - first point on edge shared with another triangle
  299.     pvPoint = cdMesh.GetArrayElem(pvMeshPoints, pwFace1[iEdge]);
  300.  
  301.     // first position goes in standard position spot
  302.     m_cfvf.SetPosition(pvDestPoint, cdMesh.PvGetPosition(pvPoint));
  303.  
  304.     // first set of weights go in standard spot - expand to standard length
  305.     CopyIndexedWeights(cdMesh.PfGetWeights(pvPoint), cdMesh.CWeights() + 1, m_cfvf.PfGetWeights(pvDestPoint), m_cfvf.CWeights());
  306.  
  307.     // Point 1 - other point on edge shared with another triangle
  308.     pvPoint = cdMesh.GetArrayElem(pvMeshPoints, pwFace1[(iEdge+1)%3]);
  309.  
  310.     // second position goes in first texture coord
  311.     m_cfvf.SetTexCoord(pvDestPoint, 0, cdMesh.PvGetPosition(pvPoint));
  312.  
  313.     // second set of weights go in second texture coord- expand to standard length
  314.     CopyIndexedWeights(cdMesh.PfGetWeights(pvPoint), cdMesh.CWeights() + 1, (float*)m_cfvf.PxyzwGetTexCoord(pvDestPoint, 1), m_cfvf.CWeights());
  315.  
  316.     // Point 2 - point NOT on edge shared with another triangle
  317.     pvPoint = cdMesh.GetArrayElem(pvMeshPoints, pwFace1[(iEdge+2)%3]);
  318.  
  319.     // third position goes in the third texture coordinate
  320.     m_cfvf.SetTexCoord(pvDestPoint, 3, cdMesh.PvGetPosition(pvPoint));
  321.  
  322.     // third set of weights go in fourth texture coord- expand to standard length
  323.     CopyIndexedWeights(cdMesh.PfGetWeights(pvPoint), cdMesh.CWeights() + 1, (float*)m_cfvf.PxyzwGetTexCoord(pvDestPoint, 4), m_cfvf.CWeights());
  324.  
  325.  
  326.     // the third position should be added in
  327.     m_cfvf.SetTexCoord(pvDestPoint, 6, &vAvg);
  328.  
  329.     iCurPoint += 1;
  330. }
  331.  
  332. HRESULT
  333. CStripOutline::Init(ID3DXBaseMesh *ptmMesh)
  334. {
  335.     HRESULT hr = S_OK;
  336.     DWORD cFaces;
  337.     DWORD iFace;
  338.     DWORD iEndOfStrips;
  339.     UINT *rgiStrips = NULL;
  340.     DWORD cConnections;
  341.     DWORD cStrips;
  342.     DWORD cPointsMax;
  343.     DWORD iStripIndex;
  344.     UINT iCurPoint;
  345.     DWORD iCurLine;
  346.     PBYTE pvLinePoints = NULL;
  347.     PBYTE pvMeshPoints = NULL;
  348.     LPDIRECT3DVERTEXBUFFER9 pVBVertices = NULL;
  349.     LPDIRECT3DINDEXBUFFER9 pibFaces= NULL;
  350.     PUINT pdwFaceCur;
  351.     PUINT pdwFacePrev;
  352.     PUINT rgdwFaces = NULL;
  353.     CD3DXCrackDecl1 cdMesh;
  354.     PWORD rgwFaces = NULL;
  355.     bool b16BitMesh;
  356.     UINT iIndex;
  357.     LPDIRECT3DDEVICE9 pDevice;
  358.     D3DXATTRIBUTERANGE *rgaeAttributeTableMesh = NULL;
  359.     DWORD iattr;
  360.     DWORD cStripsCur;
  361.     DWORD cVerticesCur;
  362.     DWORD dwFVFAdjVertices;
  363.     D3DCAPS9 Caps;
  364.     DWORD iFaceEnd;
  365.     DWORD iFaceStart;
  366.     D3DVERTEXELEMENT9 pDecl[MAX_FVF_DECL_SIZE];
  367.     LPD3DVERTEXELEMENT9 pDeclCur;
  368.  
  369.     hr = CreateEmptyOutline();
  370.     if (FAILED(hr))
  371.         goto e_Exit;
  372.  
  373.  
  374.     if (ptmMesh == NULL)
  375.         goto e_Exit;
  376.  
  377.     ptmMesh->GetDeclaration(pDecl);
  378.     cdMesh.SetDeclaration(pDecl);
  379.  
  380.     ptmMesh->GetDevice(&pDevice);
  381.     pDevice->Release();
  382.  
  383.     pDevice->GetDeviceCaps(&Caps);
  384.     m_bHWVertexShaders = Caps.VertexShaderVersion >= D3DVS_VERSION(1,1);
  385.  
  386.     // is the mesh 16 bit?
  387.     b16BitMesh = !(ptmMesh->GetOptions() & D3DXMESH_32BIT);
  388.  
  389.     hr = ptmMesh->GetAttributeTable(NULL, &m_caeAttributeTable);
  390.     if (FAILED(hr))
  391.         goto e_Exit;
  392.  
  393.     if (m_caeAttributeTable == 0)
  394.     {
  395.         // not attribute sorted!  just return for now
  396.         goto e_Exit;
  397.     }
  398.  
  399.     rgaeAttributeTableMesh = new D3DXATTRIBUTERANGE[m_caeAttributeTable];
  400.     m_rgaeAttributeTable = new D3DXATTRIBUTERANGE[m_caeAttributeTable];
  401.     if ((rgaeAttributeTableMesh == NULL) || (rgaeAttributeTableMesh == NULL))
  402.     {
  403.         hr = E_OUTOFMEMORY;
  404.         goto e_Exit;
  405.     }
  406.  
  407.     hr = ptmMesh->GetAttributeTable(rgaeAttributeTableMesh, NULL);
  408.     if (FAILED(hr))
  409.         goto e_Exit;
  410.  
  411.     cFaces = 0;
  412.     for (iattr = 0; iattr < m_caeAttributeTable; iattr++)
  413.     {
  414.         cFaces = max(cFaces, rgaeAttributeTableMesh[iattr].FaceStart + rgaeAttributeTableMesh[iattr].FaceCount);
  415.     }
  416.  
  417.     if (cdMesh.CWeights() > 0)
  418.     {
  419.         m_bSkinning = TRUE;
  420.  
  421.         if (cdMesh.BIndexedWeights())
  422.         {
  423.             dwFVFAdjVertices = INDEXSKINNEDFVF;
  424.             m_bIndexSkinning = TRUE;
  425.         }
  426.         else
  427.         {
  428.             dwFVFAdjVertices = SKINNEDFVF;
  429.             m_bIndexSkinning = FALSE;
  430.         }
  431.     }
  432.     else
  433.     {
  434.         dwFVFAdjVertices = D3DFVF_XYZ;
  435.         m_bSkinning = FALSE;
  436.         m_bIndexSkinning = FALSE;
  437.     }
  438.     m_cfvf = DXCrackFVF(dwFVFAdjVertices);
  439.  
  440.     // allocate a temporary array to track the triangles to connect with lines
  441.     rgiStrips = new UINT[cFaces*2];
  442.     if (rgiStrips == NULL)
  443.     {
  444.         hr = E_OUTOFMEMORY;
  445.         goto e_Exit;
  446.     }
  447.  
  448.     if (b16BitMesh)
  449.     {
  450.         // allocate a temporary, so that the follow code
  451.         //   can work on just 32bit indices
  452.         rgdwFaces = new UINT[cFaces*3];
  453.         if (rgdwFaces == NULL)
  454.         {
  455.             hr = E_OUTOFMEMORY;
  456.             goto e_Exit;
  457.         }
  458.  
  459.         // get the index buffer
  460.         hr = ptmMesh->GetIndexBuffer(&pibFaces);
  461.         if (FAILED(hr))
  462.             goto e_Exit;
  463.  
  464.         hr = pibFaces->Lock(0,0, (PVOID*)&rgwFaces, D3DLOCK_NOSYSLOCK );
  465.         if (FAILED(hr))
  466.             goto e_Exit;
  467.  
  468.         // UpConvert from 16 bit to 32 bit
  469.         for (iIndex = 0; iIndex < cFaces * 3; iIndex++)
  470.         {
  471.             if (rgwFaces[iIndex] != UNUSED16)
  472.                 rgdwFaces[iIndex] = rgwFaces[iIndex];
  473.             else
  474.                 rgdwFaces[iIndex] = UNUSED32;
  475.         }
  476.     }
  477.     else
  478.     {
  479.         // get the index buffer
  480.         hr = ptmMesh->GetIndexBuffer(&pibFaces);
  481.         if (FAILED(hr))
  482.             goto e_Exit;
  483.  
  484.         hr = pibFaces->Lock(0,0, (PVOID*)&rgdwFaces, D3DLOCK_NOSYSLOCK );
  485.         if (FAILED(hr))
  486.             goto e_Exit;
  487.     }
  488.  
  489.  
  490.     // start out with zero entries in each attribute table
  491.             // fixup the rest of the entries after figuring out the counts
  492.     for (iattr = 0; iattr < m_caeAttributeTable; iattr++)
  493.     {
  494.         m_rgaeAttributeTable[iattr].FaceCount = 0;
  495.         m_rgaeAttributeTable[iattr].VertexCount = 0;
  496.  
  497.         m_rgaeAttributeTable[iattr].AttribId = rgaeAttributeTableMesh[iattr].AttribId;
  498.  
  499.     }
  500.  
  501.     iEndOfStrips = 0;
  502.     cConnections = 0;
  503.     cStrips = 0;
  504.  
  505.     for (iattr = 0; iattr < m_caeAttributeTable; iattr++)
  506.     {
  507.         if (rgaeAttributeTableMesh[iattr].FaceCount == 0)
  508.             continue;
  509.  
  510.         m_rgaeAttributeTable[iattr].VertexCount = 0;
  511.  
  512.         iFaceStart = rgaeAttributeTableMesh[iattr].FaceStart;
  513.         iFaceEnd = iFaceStart + rgaeAttributeTableMesh[iattr].FaceCount;
  514.  
  515.         pdwFacePrev = &rgdwFaces[iFaceStart * 3];
  516.         pdwFaceCur = pdwFacePrev + 3;
  517.         rgiStrips[iEndOfStrips] = iFaceStart;
  518.         iEndOfStrips += 1;
  519.         cStrips += 1;
  520.         for (iFace = iFaceStart + 1; iFace < iFaceEnd; iFace++)
  521.         {
  522.             // if the part of the same strip, extend the strip
  523.             if (BConnected(pdwFaceCur, pdwFacePrev))
  524.             {
  525.                 rgiStrips[iEndOfStrips] = iFace;
  526.                 iEndOfStrips += 1;
  527.  
  528.                 m_rgaeAttributeTable[iattr].FaceCount += 2;
  529.                 m_rgaeAttributeTable[iattr].VertexCount += 4;
  530.  
  531.                 // how many faces are connected to another in a strip-like fashion
  532.                 cConnections += 1;
  533.             }
  534.             else // end the strip, and restart a new one with the current face
  535.             {
  536.                 rgiStrips[iEndOfStrips] = UNUSED32;
  537.                 iEndOfStrips += 1;
  538.  
  539.  
  540.                 rgiStrips[iEndOfStrips] = iFace;
  541.                 iEndOfStrips += 1;
  542.  
  543.                 cStrips += 1;
  544.             }
  545.  
  546.             // move the current to the previous, then increment the current one
  547.             pdwFacePrev = pdwFaceCur;
  548.             pdwFaceCur += 3;
  549.         }
  550.  
  551.         // for consistency end the last strip
  552.         rgiStrips[iEndOfStrips] = UNUSED32;
  553.         iEndOfStrips += 1;
  554.     }
  555.  
  556.  
  557.     // start out with zero entries in each attribute table
  558.             // fixup the rest of the entries after figuring out the counts
  559.     cStripsCur = 0;
  560.     cVerticesCur = 0;
  561.     for (iattr = 0; iattr < m_caeAttributeTable; iattr++)
  562.     {
  563.         m_rgaeAttributeTable[iattr].FaceStart = cStripsCur;
  564.         m_rgaeAttributeTable[iattr].VertexStart = cVerticesCur;
  565.  
  566.         cStripsCur += m_rgaeAttributeTable[iattr].FaceCount;
  567.         cVerticesCur += m_rgaeAttributeTable[iattr].VertexCount;
  568.     }
  569.  
  570.     cPointsMax = cConnections * 4;
  571.  
  572.     if (cConnections == 0)
  573.         goto e_Exit;
  574.  
  575.     hr = pDevice->CreateVertexBuffer(m_cfvf.m_cBytesPerVertex * cPointsMax, 
  576.                     D3DUSAGE_WRITEONLY|(m_bHWVertexShaders ? 0:D3DUSAGE_SOFTWAREPROCESSING), 
  577.                     m_cfvf.m_dwFVF, D3DPOOL_MANAGED, &m_pVertexBuffer, NULL);
  578.     if (FAILED(hr))
  579.         goto e_Exit;
  580.  
  581.     hr = m_pVertexBuffer->Lock(0,0, (PVOID*)&pvLinePoints, D3DLOCK_NOSYSLOCK );
  582.     if (FAILED(hr))
  583.         goto e_Exit;
  584.  
  585.     hr = ptmMesh->GetVertexBuffer(&pVBVertices);
  586.     if (FAILED(hr))
  587.         goto e_Exit;
  588.  
  589.     hr = pVBVertices->Lock(0,0, (PVOID*)&pvMeshPoints, D3DLOCK_NOSYSLOCK );
  590.     if (FAILED(hr))
  591.         goto e_Exit;
  592.  
  593.  
  594.     iStripIndex = 0;
  595.     iCurPoint = 0;
  596.     iCurLine = 0;
  597.     while (iStripIndex < iEndOfStrips)
  598.     {
  599.         iFace = rgiStrips[iStripIndex];
  600.         iStripIndex += 1;
  601.  
  602.         // for pref reasons, there are a lot of unconnected triangles sometimes
  603.         if (iFace == UNUSED32)
  604.             continue;
  605.  
  606.         pdwFacePrev = &rgdwFaces[iFace * 3];
  607.         if (pdwFacePrev[0] == UNUSED32)
  608.             continue;
  609.  
  610.  
  611.         while(rgiStrips[iStripIndex] != UNUSED32)
  612.         {
  613.             if (m_bIndexSkinning)
  614.                 AppendIndexSkinnedPoint(cdMesh, pdwFacePrev, 0, pvMeshPoints, pvLinePoints, iCurPoint);
  615.             else if (m_bSkinning)
  616.                 AppendSkinnedPoint(cdMesh, pdwFacePrev, 0, pvMeshPoints, pvLinePoints, iCurPoint);
  617.             else
  618.                 AppendPoint(cdMesh, pdwFacePrev, pvMeshPoints, pvLinePoints, iCurPoint);
  619.  
  620.             iFace = rgiStrips[iStripIndex];
  621.  
  622.             pdwFaceCur = &rgdwFaces[iFace * 3];
  623.             if (pdwFaceCur[0] == UNUSED32)
  624.                 break;
  625.  
  626.             iCurLine += 1;
  627.  
  628.             if (m_bIndexSkinning)
  629.                 AppendIndexSkinnedMidpoint(cdMesh, pdwFaceCur, pdwFacePrev, pvMeshPoints, pvLinePoints, iCurPoint);
  630.             else if (m_bSkinning)
  631.                 AppendSkinnedMidpoint(cdMesh, pdwFaceCur, pdwFacePrev, pvMeshPoints, pvLinePoints, iCurPoint);
  632.             else
  633.                 AppendMidpoint(cdMesh, pdwFaceCur, pdwFacePrev, pvMeshPoints, pvLinePoints, iCurPoint);
  634.  
  635.             if (m_bIndexSkinning)
  636.                 AppendIndexSkinnedMidpoint(cdMesh, pdwFaceCur, pdwFacePrev, pvMeshPoints, pvLinePoints, iCurPoint);
  637.             else if (m_bSkinning)
  638.                 AppendSkinnedMidpoint(cdMesh, pdwFaceCur, pdwFacePrev, pvMeshPoints, pvLinePoints, iCurPoint);
  639.             else
  640.                 AppendMidpoint(cdMesh, pdwFaceCur, pdwFacePrev, pvMeshPoints, pvLinePoints, iCurPoint);
  641.  
  642.             iCurLine += 1;
  643.  
  644.             if (m_bIndexSkinning)
  645.                 AppendIndexSkinnedPoint(cdMesh, pdwFaceCur, 0, pvMeshPoints, pvLinePoints, iCurPoint);
  646.             else if (m_bSkinning)
  647.                 AppendSkinnedPoint(cdMesh, pdwFaceCur, 0, pvMeshPoints, pvLinePoints, iCurPoint);
  648.             else
  649.                 AppendPoint(cdMesh, pdwFaceCur, pvMeshPoints, pvLinePoints, iCurPoint);
  650.  
  651.             iStripIndex += 1;
  652.  
  653.             pdwFacePrev = pdwFaceCur;
  654.         }
  655.     }
  656.     // make sure that the points generated by walking the strips is
  657.     //   not greater than what is possible
  658.     GXASSERT(iCurPoint == cPointsMax);
  659.     GXASSERT(iCurLine == cConnections*2);
  660.  
  661.     m_cLines = iCurLine;
  662.     m_cVertices = cPointsMax;
  663.  
  664.     // create a vertex declaration, so that we can have D3DCOLOR instead of UBYTE4 for the matrix indices 
  665.     hr = D3DXDeclaratorFromFVF(m_cfvf.m_dwFVF, pDecl);
  666.     if (FAILED(hr))
  667.         goto e_Exit;
  668.  
  669.     // swap the type of any blendilndices to D3DCOLOR
  670.     pDeclCur = pDecl;
  671.     while (pDeclCur->Stream != 0xff)
  672.     {
  673.         if ((pDeclCur->Usage == D3DDECLUSAGE_BLENDINDICES) || (pDeclCur->Type == D3DDECLTYPE_FLOAT1))
  674.         {
  675.             //pDeclCur->Type = D3DDECLTYPE_UBYTE4;
  676.             pDeclCur->Type = D3DDECLTYPE_D3DCOLOR;
  677.         }
  678.         pDeclCur++;
  679.     }
  680.  
  681.     GXRELEASE(m_pDecl);
  682.     hr = pDevice->CreateVertexDeclaration(pDecl, &m_pDecl);
  683.     if (FAILED(hr))
  684.         goto e_Exit;
  685.  
  686. e_Exit:
  687.     // if a 16 bit mesh, then rgdwFaces is a temporary array
  688.     if (b16BitMesh)
  689.     {
  690.         delete []rgdwFaces;
  691.  
  692.         if (rgwFaces != NULL)
  693.         {
  694.             pibFaces->Unlock();
  695.         }
  696.     }
  697.     else
  698.     {
  699.         if (rgdwFaces != NULL)
  700.         {
  701.             pibFaces->Unlock();
  702.         }
  703.     }
  704.     GXRELEASE(pibFaces);
  705.  
  706.     if (pvMeshPoints)
  707.     {
  708.         GXASSERT(pVBVertices != NULL);
  709.         pVBVertices->Unlock();
  710.     }
  711.     GXRELEASE(pVBVertices);
  712.  
  713.     delete []rgiStrips;
  714.     delete []rgaeAttributeTableMesh;
  715.  
  716.     if (pvLinePoints != NULL)
  717.     {
  718.         m_pVertexBuffer->Unlock();
  719.         pvLinePoints = NULL;
  720.     }
  721.  
  722.     return hr;
  723. }
  724.  
  725. // matrix names for variables in FX file
  726. static const char *x_rgszMatrix[] =
  727. {
  728.  "mWd1", "mWd2", "mWd3", "mWd4", "mWd5", "mWd6", "mWd7", "mWd8", "mWd9",
  729.  "mWd10", "mWd11", "mWd12", "mWd13", "mWd14", "mWd15", "mWd16", "mWd17", "mWd18", "mWd19",
  730.  "mWd20", "mWd21", "mWd22", "mWd23", "mWd24", "mWd25", "mWd26", "mWd27", "mWd28"
  731. };
  732.  
  733. HRESULT
  734. CStripOutline::Draw
  735.     (
  736.     LPDIRECT3DDEVICE9 pDevice, 
  737.     DWORD iAttrib,
  738.     LPD3DXEFFECT pfxSkinnedAdjacency, 
  739.     LPD3DXEFFECT pfxColor, 
  740.     DWORD dwColor,
  741.     D3DXMATRIX *rgmIndexedMatrices,
  742.     DWORD cIndexedMatrices
  743.     )
  744. {
  745.     HRESULT hr;
  746.     LPD3DXEFFECT pfxCurrent;
  747.     DWORD dwFVF;
  748.     UINT iPass;
  749.     UINT cPasses;
  750.     DWORD cBytesPerVertex;
  751.     D3DXMATRIX matWorld;
  752.     D3DXMATRIX matView;
  753.     D3DXMATRIX matProj;
  754.     D3DXMATRIX matTot;
  755.     D3DXCOLOR vClr(dwColor);
  756.     DWORD cLines;
  757.     DWORD cLinesCur;
  758.     DWORD iVertexStart;
  759.     BOOL  dwSoftwareMode;
  760.     BOOL bChangedSWMode = FALSE;
  761.     DWORD iMatrix;
  762.     DWORD iSubset;
  763.  
  764.     if (m_bSkinning)
  765.     {
  766.         if (!m_bIndexSkinning)
  767.         {
  768.             // non-indexed skinning setup
  769.             pfxCurrent = pfxSkinnedAdjacency;
  770.             pfxSkinnedAdjacency->SetTechnique(pfxSkinnedAdjacency->GetTechnique(0));
  771.  
  772.             pDevice->GetTransform(D3DTS_VIEW,&matView);
  773.             pDevice->GetTransform(D3DTS_PROJECTION,&matProj);
  774.             pDevice->GetTransform(D3DTS_WORLD,&matWorld);
  775.  
  776.             D3DXMatrixMultiply(&matTot,&matView,&matProj);
  777.             pfxSkinnedAdjacency->SetMatrix("mTot", &matTot);                       
  778.  
  779.             pDevice->GetTransform(D3DTS_WORLD,&matWorld);
  780.             pfxSkinnedAdjacency->SetMatrix("mWd1", &matWorld);                       
  781.  
  782.             pDevice->GetTransform(D3DTS_WORLD1,&matWorld);
  783.             pfxSkinnedAdjacency->SetMatrix("mWd2", &matWorld);                       
  784.  
  785.             pDevice->GetTransform(D3DTS_WORLD2,&matWorld);
  786.             pfxSkinnedAdjacency->SetMatrix("mWd3", &matWorld);                       
  787.  
  788.             pDevice->GetTransform(D3DTS_WORLD3,&matWorld);
  789.             pfxSkinnedAdjacency->SetMatrix("mWd4", &matWorld);        
  790.         }        
  791.         else  // indexed skinning setup
  792.         {
  793.             pfxCurrent = pfxSkinnedAdjacency;
  794.             pfxSkinnedAdjacency->SetTechnique(pfxSkinnedAdjacency->GetTechnique(1));
  795.  
  796.             pDevice->GetTransform(D3DTS_VIEW,&matView);
  797.             pDevice->GetTransform(D3DTS_PROJECTION,&matProj);
  798.  
  799.             D3DXMatrixMultiply(&matTot,&matView,&matProj);
  800.             pfxSkinnedAdjacency->SetMatrix("mTot", &matTot);                       
  801.  
  802.             pfxSkinnedAdjacency->SetMatrixArray("mWorlds", rgmIndexedMatrices, cIndexedMatrices);
  803.  
  804.             for (iMatrix = 0; iMatrix < cIndexedMatrices; iMatrix++)
  805.             {
  806.                 pfxSkinnedAdjacency->SetMatrix(x_rgszMatrix[iMatrix], &rgmIndexedMatrices[iMatrix]);
  807.             }
  808.         }
  809.  
  810.         pfxSkinnedAdjacency->SetVector("vClr", (D3DXVECTOR4*)&vClr);                       
  811.  
  812.         dwSoftwareMode = pDevice->GetSoftwareVertexProcessing();
  813.         if (!m_bHWVertexShaders)
  814.         {
  815.             bChangedSWMode = TRUE;
  816.             pDevice->SetSoftwareVertexProcessing(TRUE);
  817.         }
  818.         // if in the wrong mode, then switch
  819.         else if (dwSoftwareMode && m_bHWVertexShaders)
  820.         {
  821.             bChangedSWMode = TRUE;
  822.             pDevice->SetSoftwareVertexProcessing(FALSE);
  823.         }
  824.     }
  825.     else
  826.     {
  827.         pfxCurrent = pfxColor;
  828.  
  829.         pfxCurrent->SetVector("vClr", (D3DXVECTOR4*)&vClr);                       
  830.     }
  831.  
  832.  
  833.     if ((iAttrib < m_caeAttributeTable) && (m_rgaeAttributeTable[iAttrib].AttribId == iAttrib))
  834.     {
  835.         iSubset = iAttrib;
  836.     }
  837.     else
  838.     {
  839.         // look for the correct attribute table entry to draw
  840.         for (iSubset = 0; iSubset < m_caeAttributeTable; iSubset++)
  841.         {
  842.             if (m_rgaeAttributeTable[iSubset].AttribId == iAttrib)
  843.             {
  844.                 break;
  845.             }
  846.         }
  847.     }
  848.  
  849.     if (iSubset < m_caeAttributeTable)
  850.     {
  851.         DWORD iVertexStart;
  852.         if (m_rgaeAttributeTable[iSubset].FaceCount > 0)
  853.         {
  854.             pfxCurrent->Begin(&cPasses, 0);
  855.  
  856.             for (iPass = 0; iPass < cPasses; iPass++)
  857.             {
  858.                 pDevice->SetVertexDeclaration(m_pDecl);
  859.  
  860.                 pfxCurrent->BeginPass(iPass);
  861.  
  862.                 pDevice->SetStreamSource(0, m_pVertexBuffer, 0, m_cfvf.m_cBytesPerVertex);
  863.  
  864.                 iVertexStart = m_rgaeAttributeTable[iSubset].VertexStart;
  865.                 cLines = m_rgaeAttributeTable[iSubset].VertexCount / 2;
  866.  
  867.                 while (cLines > 0)
  868.                 {
  869.                     cLinesCur = min(cLines, (0xffff / 2));
  870.  
  871.                     hr = pDevice->DrawPrimitive(D3DPT_LINELIST, 
  872.                                                  iVertexStart, 
  873.                                                  cLinesCur);
  874.                     if (FAILED(hr))
  875.                         return hr;
  876.  
  877.                     iVertexStart += cLinesCur * 2;
  878.                     cLines -= cLinesCur;
  879.                 }
  880.  
  881.                 pfxCurrent->EndPass();
  882.             }
  883.  
  884.             pfxCurrent->End();
  885.         }
  886.     }
  887.  
  888.     if (bChangedSWMode)
  889.     {
  890.         pDevice->SetSoftwareVertexProcessing(dwSoftwareMode);
  891.     }
  892.  
  893.     return S_OK;
  894. }
  895.  
  896. HRESULT
  897. CStripOutline::CreateEmptyOutline()
  898. {
  899.     GXRELEASE(m_pVertexBuffer);
  900.     m_caeAttributeTable = 0;
  901.     delete []m_rgaeAttributeTable;
  902.     m_rgaeAttributeTable = NULL;
  903.  
  904.     m_cLines = 0;
  905.     m_cVertices = 0;
  906.     m_bSkinning = FALSE;
  907.  
  908.     return S_OK;
  909. }
  910.