TerrainMesh.cpp
上传用户:sycq158
上传日期:2008-10-22
资源大小:15361k
文件大小:42k
源码类别:

游戏

开发平台:

Visual C++

  1. //-----------------------------------------------------------------------------
  2. // File: terrainmesh.cpp
  3. //
  4. // Copyright (C) Microsoft Corporation. All Rights Reserved.
  5. //-----------------------------------------------------------------------------
  6. #include "stdafx.h"
  7. #define RVALUE(rgb)      ((BYTE)((rgb)>>16))
  8. #define GVALUE(rgb)      ((BYTE)(((WORD)(rgb)) >> 8))
  9. #define BVALUE(rgb)      ((BYTE)(rgb))
  10. extern CProfile g_Profile;
  11. //-----------------------------------------------------------------------------
  12. // Name: 
  13. // Desc: 
  14. //-----------------------------------------------------------------------------
  15. CTerrainMesh::CTerrainMesh( CTerrainEngine* pTerrainEngine )
  16. {
  17.     g_pTerrainEngine = pTerrainEngine;
  18.     m_pMesh         = NULL;
  19.     m_pMap          = NULL;
  20.     m_pTexture      = NULL;
  21.     m_dwNumFaces    = 0;
  22.     m_dwNumVerties  = 0;
  23. }
  24. //-----------------------------------------------------------------------------
  25. // Name: 
  26. // Desc: 
  27. //-----------------------------------------------------------------------------
  28. CTerrainMesh::~CTerrainMesh()
  29. {
  30.     FinalCleanup();
  31. }
  32. //-----------------------------------------------------------------------------
  33. // Name: 
  34. // Desc: 
  35. //-----------------------------------------------------------------------------
  36. HRESULT CTerrainMesh::OneTimeSceneInit( CZoneStyleParameter* pLandStyle, const float fWorldOffsetX, const float fWorldOffsetZ, CTerrainMesh* pNorth, CTerrainMesh* pEast, CTerrainMesh* pNorthEast )
  37. {
  38.     m_pLandStyle = pLandStyle;
  39.     m_pMap = new CHeightMap( g_pTerrainEngine, fWorldOffsetX, fWorldOffsetZ );
  40.     if( m_pMap == NULL )
  41.         return E_OUTOFMEMORY;
  42.     m_pNorth    = pNorth;
  43.     m_pEast     = pEast;
  44.     m_pNorthEast = pNorthEast;
  45.     m_fWorldOffsetX  = fWorldOffsetX;
  46.     m_fWorldOffsetZ  = fWorldOffsetZ;
  47.     return S_OK;
  48. }
  49. //-----------------------------------------------------------------------------
  50. // Name: 
  51. // Desc: 
  52. //-----------------------------------------------------------------------------
  53. HRESULT CTerrainMesh::InitDeviceObjects( D3DFORMAT fmtTexture )
  54. {
  55.     HRESULT hr;
  56.     m_fmtTexture = fmtTexture;
  57.     // Create height map using one of the following methods
  58.     if( m_pLandStyle->HeightCreationType == HCT_FromFile )
  59.     {
  60.         TCHAR strFile[MAX_PATH];
  61.         CMyApplication::FindMediaFileCch( strFile, MAX_PATH, m_pLandStyle->szHeightMap );
  62.         if( FAILED( hr = m_pMap->CreateFromFile( strFile ) ) )
  63.         {
  64.             g_pApp->CleanupAndDisplayError( DONUTSERR_ARTLOADFAILED, m_pLandStyle->szHeightMap, strFile );
  65.             return DXTRACE_ERR( TEXT("CreateFromFile"), hr );;
  66.         }
  67.     }
  68.     else 
  69.     {
  70.         m_pMap->Create( ZONE_WIDTH, ZONE_HEIGHT );
  71.         if( m_pLandStyle->HeightCreationType == HCT_CreateTest )
  72.         {
  73. //            m_pMap->CreateTestMap( 0.0f );
  74. //            m_pMap->CreateSmallHills();
  75.         }
  76.     }
  77.     return S_OK;
  78. }
  79. //-----------------------------------------------------------------------------
  80. // Name: 
  81. // Desc: 
  82. //-----------------------------------------------------------------------------
  83. FLOAT CTerrainMesh::TextureColorFactor( DWORD iTexture, float fValue )
  84. {
  85.     float fHigh, fMid, fLow;
  86.     fMid = m_pLandStyle->aLayerHeight[iTexture];
  87.     if( iTexture==0 )
  88.         fLow = -0.25f;
  89.     else
  90.         fLow = m_pLandStyle->aLayerHeight[iTexture-1];
  91.     if( iTexture==m_pLandStyle->dwNumLayers-1 )
  92.         fHigh = 1.25f;
  93.     else
  94.         fHigh = m_pLandStyle->aLayerHeight[iTexture+1];
  95.     if( fValue > fHigh || fValue < fLow )
  96.         return 0.0f;
  97.     float fPercent;
  98.     if( fValue > fMid )
  99.         fPercent = (fHigh - fValue) / (fHigh - fMid);
  100.     else
  101.         fPercent = (fValue - fLow) / (fMid - fLow); 
  102.     return fPercent;
  103. }
  104. //-----------------------------------------------------------------------------
  105. // Name: 
  106. // Desc: 
  107. //-----------------------------------------------------------------------------
  108. BYTE CTerrainMesh::TextureAlpha( float fHeight, int nIndex )
  109. {
  110.     BYTE aAlpha[MAX_SOURCE_TEXTURES];           
  111.     BYTE aAlpha2[MAX_SOURCE_TEXTURES];           
  112.     int  nTotalAlpha = 0;
  113.     int  nTotalAlpha2 = 0;
  114.     float aFactor[MAX_SOURCE_TEXTURES];
  115.     float aFactor2[MAX_SOURCE_TEXTURES];
  116.     float fTotalFactor = 0.0f;
  117.     DWORD i;
  118.     ZeroMemory( aAlpha, sizeof(BYTE)*MAX_SOURCE_TEXTURES );
  119.     ZeroMemory( aAlpha2, sizeof(BYTE)*MAX_SOURCE_TEXTURES );
  120.     ZeroMemory( aFactor, sizeof(float)*MAX_SOURCE_TEXTURES );
  121.     ZeroMemory( aFactor2, sizeof(float)*MAX_SOURCE_TEXTURES );
  122.     for( i=0; i<m_pLandStyle->dwNumLayers; i++ )
  123.     {
  124.         aFactor[i] = TextureColorFactor( i, fHeight );
  125.         fTotalFactor += aFactor[i];
  126.     }
  127.     for( i=0; i<m_pLandStyle->dwNumLayers; i++ )
  128.         aFactor[i] /= fTotalFactor;
  129.     for( i=0; i<m_pLandStyle->dwNumLayers; i++ )
  130.     {
  131.         aAlpha[i] = (BYTE) (aFactor[i] * (float)0xFF);
  132.         nTotalAlpha += (int) aAlpha[i];
  133.     }
  134.     for( i=0; i<m_pLandStyle->dwNumLayers; i++ )
  135.     {
  136.         aFactor2[i] = (float)aAlpha[i] / (float)nTotalAlpha;
  137.         aAlpha2[i] = (BYTE) ( aFactor2[i] * 0xFF + 0.5f );
  138.         nTotalAlpha2 += aAlpha2[i];
  139.     }
  140.     int nReturn = (int) (aAlpha[nIndex] * m_pLandStyle->fLayerBlendFactor[nIndex] );
  141.     if( nReturn > 0xFF )
  142.         nReturn = 0xFF;
  143.     return (BYTE) nReturn;
  144. }
  145. //-----------------------------------------------------------------------------
  146. // Name: 
  147. // Desc: 
  148. //-----------------------------------------------------------------------------
  149. HRESULT CTerrainMesh::RestoreDeviceObjects( HWND hWndMain )
  150. {
  151.     HRESULT hr;
  152.     int nWidth          = ZONE_WIDTH+1;
  153.     int nHeight         = ZONE_HEIGHT+1;
  154.     // Create texture using one of the following methods
  155.     if( m_pLandStyle->TextureCreationType == TCT_FromFile )
  156.     {
  157.         // Read the texture from a file
  158.         if( FAILED( hr = ReadTextureFromFile( nWidth, nHeight ) ) ) 
  159.             return DXTRACE_ERR( TEXT("ReadTextureFromFile"), hr );
  160.     }
  161.     else if( m_pLandStyle->TextureCreationType == TCT_CreateTest )
  162.     {
  163.         if( FAILED( hr = CreateTestTexture( nWidth, nHeight ) ) ) 
  164.             return DXTRACE_ERR( TEXT("CreateTestTexture"), hr );
  165.     }
  166.     else if( m_pLandStyle->TextureCreationType == TCT_CreateFromHeight )
  167.     {
  168.         // Create the texture based on the height map
  169.         if( FAILED( hr = CreateTextureFromHeight( nWidth, nHeight ) ) ) 
  170.             return DXTRACE_ERR( TEXT("CreateTextureFromHeight"), hr );
  171.     }
  172.     else if( m_pLandStyle->TextureCreationType == TCT_FromLayers )
  173.     {
  174.         if( g_Profile.bLoadFast )
  175.         {
  176.             if( FAILED( hr = CreateTestTexture( nWidth, nHeight ) ) ) 
  177.                 return DXTRACE_ERR( TEXT("CreateTestTexture"), hr );
  178.         }
  179.         else
  180.         {
  181.             // Create the texture by layering a number of detail textures
  182.             if( FAILED( hr = CreateTextureFromLayers( nWidth, nHeight ) ) ) 
  183.                 return DXTRACE_ERR( TEXT("CreateTextureFromLayers"), hr );
  184.         }
  185.     }
  186.     else
  187.     {
  188.         MessageBox( hWndMain, "Unknown texture creation type", "Donuts 4", MB_OK );
  189.         return E_FAIL;
  190.     }
  191.     // Create mesh from the height map
  192.     CreateMeshFromHeightMap( nWidth, nHeight );
  193.     if( m_pLandStyle->bSaveMedia )
  194.     {
  195.         SaveMeshToXFile();
  196.         SaveTextureToFile();
  197.     }
  198.     return S_OK;
  199. }
  200. //-----------------------------------------------------------------------------
  201. // Name: CreateMeshFromHeightMap
  202. // Desc: 
  203. //-----------------------------------------------------------------------------
  204. HRESULT CTerrainMesh::CreateMeshFromHeightMap( int nWidth, int nHeight )
  205. {
  206.     HRESULT hr;
  207.     
  208.     int nNumStrips      = (nWidth-1);
  209.     int nQuadsPerStrip  = (nHeight-1);
  210.     m_dwNumFaces    = nNumStrips * nQuadsPerStrip * 2;
  211.     m_dwNumVerties  = nWidth * nHeight;
  212.     hr = D3DXCreateMeshFVF( m_dwNumFaces, m_dwNumVerties, D3DXMESH_MANAGED, TERRIAN_FVF, g_pd3dDevice, &m_pMesh );
  213.     if( FAILED(hr) )
  214.         return DXTRACE_ERR( TEXT("D3DXCreateMeshFVF"), hr );
  215.     WORD* pIndexBuffer = NULL;
  216.     hr = m_pMesh->LockIndexBuffer( 0, (void**) &pIndexBuffer );
  217.     if( FAILED(hr) )
  218.         return DXTRACE_ERR( TEXT("LockIndexBuffer"), hr );
  219.     int iStrip, iQuad;
  220.     int iRow, iCol;
  221.     float iX, iZ;
  222.     for( iStrip = 0; iStrip<nNumStrips; iStrip++ )
  223.     {
  224.         WORD nCurRow1 = (iStrip+0)*nHeight;
  225.         WORD nCurRow2 = (iStrip+1)*nHeight;
  226.         for( iQuad = 0; iQuad<nQuadsPerStrip; iQuad++ )
  227.         {
  228.             // first tri 
  229.             *pIndexBuffer++ = nCurRow1;
  230.             *pIndexBuffer++ = nCurRow1 + 1;
  231.             *pIndexBuffer++ = nCurRow2;
  232.             // second tri 
  233.             *pIndexBuffer++ = nCurRow1 + 1;
  234.             *pIndexBuffer++ = nCurRow2 + 1;
  235.             *pIndexBuffer++ = nCurRow2;
  236.             nCurRow1++;
  237.             nCurRow2++;
  238.         }
  239.     }
  240.     hr = m_pMesh->UnlockIndexBuffer();
  241.     if( FAILED(hr) )
  242.         return DXTRACE_ERR( TEXT("UnlockIndexBuffer"), hr );
  243.     TERRIANVERTEX* pVertexBuffer = NULL;
  244.     hr = m_pMesh->LockVertexBuffer( 0, (void**) &pVertexBuffer );
  245.     if( FAILED(hr) )
  246.         return DXTRACE_ERR( TEXT("LockVertexBuffer"), hr );
  247.     float fSizeQuadX = 1.0f;
  248.     float fSizeQuadZ = 1.0f;
  249.     D3DSURFACE_DESC surfDesc;
  250.     FLOAT fTexelSizeU;
  251.     FLOAT fTexelSizeV;
  252.     if( m_pTexture )
  253.     {
  254.         hr = m_pTexture->GetLevelDesc( 0, &surfDesc );
  255.         fTexelSizeU = 1.0f/surfDesc.Width;
  256.         fTexelSizeV = 1.0f/surfDesc.Height;
  257.     }
  258.     else
  259.     {
  260.         fTexelSizeU = 1.0f/256.0f;
  261.         fTexelSizeV = 1.0f/256.0f;
  262.     }
  263.     iX = m_fWorldOffsetX;
  264.     for( iCol = 0; iCol<nWidth; iCol++ )
  265.     {
  266.         iZ = m_fWorldOffsetZ;
  267.         
  268.         for( iRow = 0; iRow<nHeight; iRow++ )
  269.         {
  270.             // Add a nudge factor if we're along the edges to 
  271.             // cover any minuate cracks in between the meshs
  272.             FLOAT fNudgeX = 0.0f;
  273.             FLOAT fNudgeZ = 0.0f;
  274.             if( iRow==0 )
  275.                 fNudgeZ = -0.01f;
  276.             if( iRow==nHeight-1 )
  277.                 fNudgeZ = 0.01f;
  278.             if( iCol==0 )
  279.                 fNudgeX = -0.01f;
  280.             if( iCol==nWidth-1 )
  281.                 fNudgeX = 0.01f;
  282.             // Ask the terrain engine what the height is at this point
  283.             pVertexBuffer->p = D3DXVECTOR3( fNudgeX+iX-m_fWorldOffsetX, 
  284.                                             g_pTerrainEngine->GetHeight( iX, iZ ), 
  285.                                             fNudgeZ+iZ-m_fWorldOffsetZ );
  286.             // Compute the normal by hand
  287.             D3DXVECTOR3 vecN;
  288.             D3DXVECTOR3 vPt = D3DXVECTOR3( iX, g_pTerrain->GetHeight( iX, iZ ), iZ );
  289.             D3DXVECTOR3 vN = D3DXVECTOR3( iX, g_pTerrain->GetHeight( iX+0.0f, iZ+1.0f ), iZ+1.0f );
  290.             D3DXVECTOR3 vE = D3DXVECTOR3( iX+1.0f, g_pTerrain->GetHeight( iX+1.0f, iZ+0.0f ), iZ );
  291.             D3DXVECTOR3 v1 = vN - vPt;
  292.             D3DXVECTOR3 v2 = vE - vPt;
  293.             D3DXVec3Cross( &vecN, &v1, &v2 );
  294.             D3DXVec3Normalize(&vecN, &vecN);
  295.             pVertexBuffer->n = vecN;
  296.             // Set the texture coords from (0.0f + 0.5*texel) to (1.0f - 0.5*texel) 
  297.             // to get perfect texel mapping on the mesh
  298.             pVertexBuffer->tu = ( (float) iCol / (float) (nWidth-1)  ) * (1.0f-fTexelSizeU) + 0.5f*fTexelSizeU;
  299.             pVertexBuffer->tv = ( (float) iRow / (float) (nHeight-1) ) * (1.0f-fTexelSizeV) + 0.5f*fTexelSizeV;
  300.             pVertexBuffer++;
  301.             iZ += fSizeQuadZ;
  302.         }
  303.         iX += fSizeQuadX;
  304.     }
  305.     hr = m_pMesh->UnlockVertexBuffer();
  306.     if( FAILED(hr) )
  307.         return DXTRACE_ERR( TEXT("UnlockVertexBuffer"), hr );
  308.     BOOL bGenAdj        = g_Profile.bOptimizeMesh || g_Profile.bCompactMesh || g_Profile.bSimplifyMesh;
  309.     BOOL bOptimize      = g_Profile.bOptimizeMesh && bGenAdj;
  310.     BOOL bCompact       = g_Profile.bCompactMesh && bOptimize;
  311.     BOOL bSimplifyMesh  = g_Profile.bSimplifyMesh && bGenAdj;
  312.     DWORD* pdwAdjaceny  = NULL;
  313.     if( bGenAdj ) 
  314.     {
  315.         pdwAdjaceny = new DWORD[ 3 * m_pMesh->GetNumFaces() ];
  316.         if( pdwAdjaceny == NULL )
  317.             return E_OUTOFMEMORY;
  318.         hr = m_pMesh->GenerateAdjacency( 0.01f, pdwAdjaceny );
  319.         if( FAILED(hr) )
  320.             return DXTRACE_ERR( TEXT("GenerateAdjacency"), hr );
  321.     }
  322.     if( bOptimize )
  323.     {
  324.         DWORD* pdwAdjacenyOut = NULL;
  325.         if( bGenAdj )
  326.         {
  327.             pdwAdjacenyOut = new DWORD[ 3 * m_pMesh->GetNumFaces() ];
  328.             if( pdwAdjacenyOut == NULL )
  329.                 return E_OUTOFMEMORY;
  330.         }
  331.         DWORD dwFlags = D3DXMESHOPT_VERTEXCACHE;
  332.         if( bCompact )
  333.             dwFlags |= D3DXMESHOPT_COMPACT;
  334.         hr = m_pMesh->OptimizeInplace( dwFlags, pdwAdjaceny, pdwAdjacenyOut, NULL, NULL );
  335.         if( FAILED(hr) )
  336.             return DXTRACE_ERR( TEXT("D3DXSimplifyMesh"), hr );
  337.         if( bGenAdj )
  338.         {
  339.             SAFE_DELETE_ARRAY( pdwAdjaceny );
  340.             pdwAdjaceny = pdwAdjacenyOut;
  341.         }
  342.     }
  343.     if( bGenAdj ) 
  344.     {
  345.         if( bSimplifyMesh )
  346.         {
  347.             ID3DXMesh* pMesh;
  348.             D3DXATTRIBUTEWEIGHTS d3daw;
  349.             ZeroMemory( &d3daw, sizeof(D3DXATTRIBUTEWEIGHTS) );
  350.             d3daw.Position = 1.0f;
  351.             d3daw.Boundary = 10000.0f;
  352.             d3daw.Normal   = 1.0f;
  353.             hr = D3DXSimplifyMesh( m_pMesh, pdwAdjaceny, &d3daw, NULL, (DWORD)(m_dwNumFaces*g_Profile.fSimplifyMeshFactor), D3DXMESHSIMP_FACE, &pMesh );
  354.             if( FAILED(hr) )
  355.                 return DXTRACE_ERR( TEXT("D3DXSimplifyMesh"), hr );
  356.             SAFE_RELEASE( m_pMesh );
  357.             m_pMesh = pMesh;
  358.         }
  359.         SAFE_DELETE_ARRAY( pdwAdjaceny );
  360.     }
  361.     assert( m_pMesh != NULL );
  362.     return S_OK;
  363. }
  364. //-----------------------------------------------------------------------------
  365. // Name: 
  366. // Desc: 
  367. //-----------------------------------------------------------------------------
  368. HRESULT CTerrainMesh::CorrectTextureEdge()
  369. {
  370.     HRESULT hr;
  371.     if( NULL == m_pTexture )
  372.         return S_OK;
  373.     DWORD dwLevelCount = m_pTexture->GetLevelCount();
  374.     
  375.     for( DWORD iLevel=0; iLevel<dwLevelCount; iLevel++ )
  376.     {
  377.         D3DSURFACE_DESC surfDesc;
  378.         hr = m_pTexture->GetLevelDesc( iLevel, &surfDesc );
  379.     
  380.         D3DLOCKED_RECT LockedRect;
  381.         hr = m_pTexture->LockRect( iLevel, &LockedRect, NULL, 0 );
  382.         if( FAILED(hr) )
  383.             return S_OK; // can't lock texture if its a rendertarget
  384. //            return DXTRACE_ERR( TEXT("LockRect"), hr );
  385.         switch( surfDesc.Format )
  386.         {
  387.             case D3DFMT_A8R8G8B8:
  388.             case D3DFMT_X8R8G8B8:
  389.             {
  390.                 DWORD* pBits;
  391.                 for( DWORD iTexelZ=0; iTexelZ<surfDesc.Height; iTexelZ++ )
  392.                 {
  393.                     FLOAT fMapZ = (float) iTexelZ / ( (float)surfDesc.Height / (float)m_pMap->m_nZSize );
  394.                     pBits = (DWORD*) ((BYTE*)LockedRect.pBits + LockedRect.Pitch*iTexelZ);
  395.                     pBits += (surfDesc.Width-1);
  396.                     *pBits = g_pTerrainEngine->GetTexelColor( iLevel, 
  397.                                                               m_fWorldOffsetX + m_pMap->m_fXSize,
  398.                                                               m_fWorldOffsetZ + fMapZ );
  399.                 }        
  400.                 pBits = (DWORD*) ((BYTE*)LockedRect.pBits + LockedRect.Pitch*(surfDesc.Height-1));
  401.                 for( DWORD iTexelX=0; iTexelX<surfDesc.Width; iTexelX++ )
  402.                 {
  403.                     FLOAT fMapX = (float) iTexelX / ( (float)surfDesc.Width / (float)m_pMap->m_nXSize );
  404.                     *pBits = g_pTerrainEngine->GetTexelColor( iLevel, 
  405.                                                               m_fWorldOffsetX + fMapX, 
  406.                                                               m_fWorldOffsetZ + m_pMap->m_fZSize );
  407.                     pBits++;
  408.                 }        
  409.                 break;
  410.             }
  411.         }
  412.         hr = m_pTexture->UnlockRect( iLevel );
  413.         if( FAILED(hr) )
  414.             return DXTRACE_ERR( TEXT("UnlockRect"), hr );   
  415.     }
  416.     return S_OK;
  417. }
  418. //-----------------------------------------------------------------------------
  419. // Name: 
  420. // Desc: 
  421. //-----------------------------------------------------------------------------
  422. HRESULT CTerrainMesh::GenerateMipMaps()
  423. {
  424.     if( g_Profile.bGenerateMipMaps )
  425.     {
  426.         HRESULT hr;
  427.         LPDIRECT3DTEXTURE9 pTexture = NULL;
  428.         hr = D3DXCreateTexture( g_pd3dDevice, m_pLandStyle->dwTextureSize, m_pLandStyle->dwTextureSize, D3DX_DEFAULT, 0, 
  429.                                 m_fmtTexture, D3DPOOL_MANAGED, &pTexture );
  430.         if( FAILED(hr) )
  431.             return DXTRACE_ERR( TEXT("D3DXCreateTexture"), hr );
  432.         IDirect3DSurface9* pSurfaceSrc = NULL;
  433.         IDirect3DSurface9* pSurfaceDest = NULL;
  434.         pTexture->GetSurfaceLevel( 0, &pSurfaceDest );
  435.         m_pTexture->GetSurfaceLevel( 0, &pSurfaceSrc );
  436.         hr = D3DXLoadSurfaceFromSurface( pSurfaceDest, NULL, NULL, 
  437.                                          pSurfaceSrc, NULL, NULL, 
  438.                                          D3DX_FILTER_POINT, 0 );
  439.         if( FAILED(hr) )
  440.             return DXTRACE_ERR( TEXT("D3DXLoadSurfaceFromSurface"), hr );
  441.         SAFE_RELEASE( pSurfaceDest );
  442.         SAFE_RELEASE( pSurfaceSrc );
  443.         SAFE_RELEASE( m_pTexture );
  444.         m_pTexture = pTexture;
  445.         pTexture = NULL;
  446.         hr = D3DXFilterTexture( m_pTexture, NULL, 0, D3DX_FILTER_BOX );
  447.     }
  448.     return S_OK;
  449. }
  450. //-----------------------------------------------------------------------------
  451. // Name: 
  452. // Desc: 
  453. //-----------------------------------------------------------------------------
  454. HRESULT CTerrainMesh::CreateTestTexture( int nWidth, int nHeight )
  455. {
  456.     HRESULT hr;
  457.     
  458.     hr = D3DXCreateTexture( g_pd3dDevice, nWidth, nHeight, 1, 0, 
  459.                             D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &m_pTexture );
  460.     if( FAILED(hr) )
  461.         return DXTRACE_ERR( TEXT("D3DXCreateTexture"), hr );
  462.     
  463.     D3DSURFACE_DESC surfDesc;
  464.     hr = m_pTexture->GetLevelDesc( 0, &surfDesc );
  465.     
  466.     D3DLOCKED_RECT LockedRect;
  467.     hr = m_pTexture->LockRect( 0, &LockedRect, NULL, 0 );
  468.     if( FAILED(hr) )
  469.         return DXTRACE_ERR( TEXT("LockRect"), hr );
  470.     DWORD* pBits;
  471.     for( DWORD iTexelZ=0; iTexelZ<surfDesc.Height; iTexelZ++ )
  472.     {
  473.         pBits = (DWORD*) ((BYTE*)LockedRect.pBits + LockedRect.Pitch*iTexelZ);
  474.         for( DWORD iTexelX=0; iTexelX<surfDesc.Width; iTexelX++ )
  475.         {
  476.             *pBits = 0xFF00FF00;
  477.             pBits++;
  478.         }
  479.     }        
  480.     hr = m_pTexture->UnlockRect( 0 );
  481.     if( FAILED(hr) )
  482.         return DXTRACE_ERR( TEXT("UnlockRect"), hr );   
  483.     return S_OK;
  484. }
  485. //-----------------------------------------------------------------------------
  486. // Name: 
  487. // Desc: 
  488. //-----------------------------------------------------------------------------
  489. HRESULT CTerrainMesh::ReadTextureFromFile( int nWidth, int nHeight )
  490. {
  491.     HRESULT hr;
  492.     D3DXIMAGE_INFO d3dxImageInfo;
  493.     D3DXGetImageInfoFromFile( m_pLandStyle->szTextureMap, &d3dxImageInfo );
  494.     // Create a texture w/ a format supported by the video card
  495.     TCHAR strFile[MAX_PATH];
  496.     CMyApplication::FindMediaFileCch( strFile, MAX_PATH, m_pLandStyle->szTextureMap );
  497.     hr = D3DXCreateTextureFromFileEx( g_pd3dDevice, strFile,
  498.                                       m_pLandStyle->dwTextureSize, m_pLandStyle->dwTextureSize, 1, 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_FILTER_LINEAR,
  499.                                       D3DX_FILTER_LINEAR, 0, NULL, NULL, &m_pTexture );
  500.     if( FAILED(hr) )
  501.     {
  502.         g_pApp->CleanupAndDisplayError( DONUTSERR_ARTLOADFAILED, m_pLandStyle->szTextureMap, strFile );
  503.         return DXTRACE_ERR( TEXT("D3DXCreateTexture"), hr );
  504.     }
  505.     return S_OK;
  506. }
  507. //-----------------------------------------------------------------------------
  508. // Name: CreateTextureFromLayers()
  509. // Desc: This function takes a list of texture files and tiles them.  It does a 
  510. //       multipass alpha blend into a final m_pTexture.  The alpha layers are 
  511. //       created for each texture based on the height of the mesh.
  512. //-----------------------------------------------------------------------------
  513. HRESULT CTerrainMesh::CreateTextureFromLayers( int nWidth, int nHeight )
  514. {
  515.     HRESULT hr;
  516.     D3DSURFACE_DESC surfDesc;
  517.     D3DVIEWPORT9 vp;
  518.     DWORD iTexture;
  519.    
  520.     LPDIRECT3DTEXTURE9 pSrcTex[MAX_SOURCE_TEXTURES];           
  521.     ZeroMemory( pSrcTex, sizeof(LPDIRECT3DTEXTURE9)*MAX_SOURCE_TEXTURES );
  522.     LPDIRECT3DTEXTURE9 pAlphaTex[MAX_SOURCE_TEXTURES];           
  523.     ZeroMemory( pAlphaTex, sizeof(LPDIRECT3DTEXTURE9)*MAX_SOURCE_TEXTURES );
  524.     DWORD i;
  525.     // For each src texture, read the texture from a file and create an alpha mask for it
  526.     for( i=0; i<m_pLandStyle->dwNumLayers; i++ )
  527.     {
  528.         // Read source texture from file.  
  529.         TCHAR strFile[MAX_PATH];
  530.         CMyApplication::FindMediaFileCch( strFile, MAX_PATH, m_pLandStyle->aLayerTexture[i] );
  531.         hr = D3DXCreateTextureFromFileEx( g_pd3dDevice, strFile,
  532.                                           D3DX_DEFAULT, D3DX_DEFAULT, 1, 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, 
  533.                                           D3DX_FILTER_LINEAR, D3DX_FILTER_LINEAR, 0, NULL, NULL, &pSrcTex[i] );
  534.         if( FAILED(hr) )
  535.         {
  536.             g_pApp->CleanupAndDisplayError( DONUTSERR_ARTLOADFAILED, m_pLandStyle->aLayerTexture[i], strFile );
  537.             return DXTRACE_ERR( TEXT("D3DXCreateTextureFromFileEx"), hr );
  538.         }
  539.         // Create alpha mask for each source texture.  
  540.         hr = D3DXCreateTexture( g_pd3dDevice, nWidth, nHeight, 
  541.                                 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, 
  542.                                 &pAlphaTex[i] );
  543.         if( FAILED(hr) )
  544.             return DXTRACE_ERR( TEXT("D3DXCreateTexture"), hr );
  545.     }
  546.     // Get the backbuffer format
  547.     LPDIRECT3DSURFACE9 pBackBuffer = NULL;
  548.     D3DSURFACE_DESC    d3dsdBackBuffer;   // Surface desc of the backbuffer
  549.     g_pd3dDevice->GetBackBuffer( 0, 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer );
  550.     pBackBuffer->GetDesc( &d3dsdBackBuffer );
  551.     SAFE_RELEASE( pBackBuffer );
  552.     // Create a render target texture if possible
  553.     hr = D3DXCreateTexture( g_pd3dDevice, m_pLandStyle->dwTextureSize, m_pLandStyle->dwTextureSize, 
  554.                             1, D3DUSAGE_RENDERTARGET, 
  555.                             D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &m_pTexture );
  556.     if( FAILED(hr) )
  557.     {
  558.         // Fallback to a normal texture with the same format as the backbuffer
  559.         // normally a RENDERTARGET surface can be created using the backbuffer format
  560.         hr = D3DXCreateTexture( g_pd3dDevice, m_pLandStyle->dwTextureSize, m_pLandStyle->dwTextureSize, 1, 0, 
  561.                                 D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &m_pTexture );
  562.         if( FAILED(hr) )
  563.             return DXTRACE_ERR( TEXT("D3DXCreateTexture"), hr );
  564.     }
  565.     // Create a ID3DXRenderToSurface using the same height/width/format as the
  566.     // texture that we're are going to use with this ID3DXRenderToSurface
  567.     hr = m_pTexture->GetLevelDesc( 0, &surfDesc );
  568.     ID3DXRenderToSurface* pRenderToSurface = NULL;
  569.     hr = D3DXCreateRenderToSurface( g_pd3dDevice, surfDesc.Width, surfDesc.Height, surfDesc.Format, 
  570.                                     FALSE, D3DFMT_UNKNOWN, &pRenderToSurface );
  571.     if( FAILED(hr) )
  572.         return DXTRACE_ERR( TEXT("D3DXCreateRenderToSurface"), hr );
  573.     // Compute the alpha mask for each layer
  574.     for( iTexture=0; iTexture<m_pLandStyle->dwNumLayers; iTexture++ )
  575.     {
  576.         hr = pAlphaTex[iTexture]->GetLevelDesc( 0, &surfDesc );
  577.         if( FAILED(hr) )
  578.             return DXTRACE_ERR( TEXT("GetLevelDesc"), hr );
  579.         assert( surfDesc.Format == D3DFMT_A8R8G8B8 );
  580.         D3DLOCKED_RECT LockedRect;
  581.         hr = pAlphaTex[iTexture]->LockRect( 0, &LockedRect, NULL, 0 );
  582.         if( FAILED(hr) )
  583.             return DXTRACE_ERR( TEXT("LockRect"), hr );
  584.         DWORD* pBits;
  585.         for( DWORD iTexelZ=0; iTexelZ<surfDesc.Height; iTexelZ++ )
  586.         {
  587.             pBits = (DWORD*) ((BYTE*)LockedRect.pBits + LockedRect.Pitch*iTexelZ);
  588.             for( DWORD iTexelX=0; iTexelX<surfDesc.Width; iTexelX++ )
  589.             {
  590.                 FLOAT fHeight;
  591.                 BYTE  nAlpha;
  592.                 // The final mesh texture 
  593.                 float iMapX = ( (float) iTexelX / (float) surfDesc.Width )  * m_pMap->m_fXSize;
  594.                 float iMapZ = ( (float) iTexelZ / (float) surfDesc.Height ) * m_pMap->m_fZSize;
  595.                 // Get the height of the mesh at this point
  596.                 fHeight = g_pTerrainEngine->GetHeight( iMapX + m_fWorldOffsetX, iMapZ + m_fWorldOffsetZ );
  597.                 fHeight /= MAX_HEIGHT_OF_MAP;
  598.  
  599.                 // The TextureAlpha() function will return the alpha for this
  600.                 // mask.  It also assures that the sum of the alpha mask at each point
  601.                 // adds up to 0xFF.
  602.                 nAlpha = TextureAlpha( fHeight, iTexture );  
  603.                 *pBits = (nAlpha << 24);
  604.                 pBits++;
  605.             }
  606.         }        
  607.         hr = pAlphaTex[iTexture]->UnlockRect( 0 );
  608.         if( FAILED(hr) )
  609.             return DXTRACE_ERR( TEXT("UnlockRect"), hr );   
  610.     } 
  611.     // Create a RHW quad to render all the layers into.  The render target
  612.     // will be the final texture, m_pTexture.
  613.     int nMeshWidth      = 16;
  614.     int nMeshHeight     = 16;
  615.     int nNumStrips      = (nMeshWidth-1);
  616.     int nQuadsPerStrip  = (nMeshHeight-1);
  617.     DWORD dwNumFaces    = nNumStrips * nQuadsPerStrip * 2;
  618.     DWORD dwNumVerties  = nMeshWidth * nMeshHeight;
  619.     LPDIRECT3DINDEXBUFFER9  pIB = NULL;
  620.     LPDIRECT3DVERTEXBUFFER9 pVB = NULL;
  621.     hr = g_pd3dDevice->CreateIndexBuffer( dwNumFaces * 3 * sizeof(WORD),
  622.                                          D3DUSAGE_WRITEONLY,
  623.                                          D3DFMT_INDEX16, D3DPOOL_MANAGED,
  624.                                          &pIB, NULL );
  625.     if( FAILED(hr) )
  626.         return DXTRACE_ERR( TEXT("CreateIndexBuffer"), hr );
  627.     hr = g_pd3dDevice->CreateVertexBuffer( dwNumVerties * sizeof(RHW_VERTEX),
  628.                                          D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY,
  629.                                          RHW_FVF, D3DPOOL_DEFAULT ,
  630.                                          &pVB, NULL );
  631.     if( FAILED(hr) )
  632.         return DXTRACE_ERR( TEXT("CreateVertexBuffer"), hr );
  633.     WORD* pIndexBuffer = NULL;
  634.     hr = pIB->Lock( 0, 0, (void**) &pIndexBuffer, 0 );
  635.     if( FAILED(hr) )
  636.         return DXTRACE_ERR( TEXT("LockIndexBuffer"), hr );
  637.     int iStrip, iQuad;
  638.     int iRow, iCol;
  639.     float iX, iY;
  640.     for( iStrip = 0; iStrip<nNumStrips; iStrip++ )
  641.     {
  642.         WORD nCurRow1 = (iStrip+0)*nMeshHeight;
  643.         WORD nCurRow2 = (iStrip+1)*nMeshHeight;
  644.         for( iQuad = 0; iQuad<nQuadsPerStrip; iQuad++ )
  645.         {
  646.             // first tri 
  647.             *pIndexBuffer++ = nCurRow1;
  648.             *pIndexBuffer++ = nCurRow1 + 1;
  649.             *pIndexBuffer++ = nCurRow2;
  650.             // second tri 
  651.             *pIndexBuffer++ = nCurRow1 + 1;
  652.             *pIndexBuffer++ = nCurRow2 + 1;
  653.             *pIndexBuffer++ = nCurRow2;
  654.             nCurRow1++;
  655.             nCurRow2++;
  656.         }
  657.     }
  658.     hr = pIB->Unlock();
  659.     if( FAILED(hr) )
  660.         return DXTRACE_ERR( TEXT("UnlockIndexBuffer"), hr );
  661.     // Setup the viewport for the ID3DXRenderToSurface.  Make the viewport the
  662.     // same size as the surface that will be the target.
  663.     hr = m_pTexture->GetLevelDesc( 0, &surfDesc );
  664.     vp.Width  = surfDesc.Width;
  665.     vp.Height = surfDesc.Height;
  666.     vp.MinZ   = 0;
  667.     vp.MaxZ   = 1.0f;
  668.     vp.X      = 0;
  669.     vp.Y      = 0;
  670.     // Render to the surface of m_pTexture.  Use the ID3DXRenderToSurface 
  671.     // to render surface, even if the surface isn't a render target.  Some
  672.     // video cards don't support textures as render targets.
  673.     IDirect3DSurface9* pRenderSurface = NULL;
  674.     m_pTexture->GetSurfaceLevel( 0, &pRenderSurface );
  675.     pRenderToSurface->BeginScene( pRenderSurface, &vp );
  676.     g_pd3dDevice->Clear( 0L, NULL, D3DCLEAR_TARGET, 0xFF000000, 1.0f, 0L );
  677.     D3DMATERIAL9 mtrl;
  678.     ZeroMemory( &mtrl, sizeof(D3DMATERIAL9) );
  679.     mtrl.Diffuse.r = mtrl.Ambient.r = 1.0f;
  680.     mtrl.Diffuse.g = mtrl.Ambient.g = 1.0f;
  681.     mtrl.Diffuse.b = mtrl.Ambient.b = 1.0f;
  682.     mtrl.Diffuse.a = mtrl.Ambient.a = 1.0f;
  683.     hr = g_pd3dDevice->SetMaterial( &mtrl );
  684.     g_pd3dDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR );
  685.     g_pd3dDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR );
  686.     hr = g_pd3dDevice->SetFVF( RHW_FVF );
  687.     hr = g_pd3dDevice->SetStreamSource( 0, pVB, 0, sizeof(RHW_VERTEX) );
  688.     hr = g_pd3dDevice->SetIndices( pIB );
  689.     g_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
  690.     g_pd3dDevice->SetRenderState( D3DRS_SRCBLEND,     D3DBLEND_SRCALPHA  );
  691.     g_pd3dDevice->SetRenderState( D3DRS_DESTBLEND,    D3DBLEND_ONE );
  692.     g_pd3dDevice->SetRenderState( D3DRS_TEXTUREFACTOR, 0 );
  693.     g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP,   D3DTOP_SELECTARG1  );
  694.     g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
  695.     g_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP,   D3DTOP_SELECTARG1  );
  696.     g_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
  697.     g_pd3dDevice->SetTextureStageState( 1, D3DTSS_COLOROP,   D3DTOP_BLENDCURRENTALPHA );
  698.     g_pd3dDevice->SetTextureStageState( 1, D3DTSS_COLORARG1, D3DTA_TEXTURE );
  699.     g_pd3dDevice->SetTextureStageState( 1, D3DTSS_COLORARG2, D3DTA_TFACTOR );
  700.     g_pd3dDevice->SetTextureStageState( 1, D3DTSS_ALPHAOP,   D3DTOP_SELECTARG1  );
  701.     g_pd3dDevice->SetTextureStageState( 1, D3DTSS_ALPHAARG1, D3DTA_CURRENT );
  702.     g_pd3dDevice->SetTextureStageState( 2, D3DTSS_COLOROP,   D3DTOP_DISABLE );
  703.     for( i=0; i<m_pLandStyle->dwNumLayers; i++ )
  704.     {
  705.         RHW_VERTEX* pVertexBuffer = NULL;
  706.         hr = pVB->Lock( 0, 0, (void**) &pVertexBuffer, D3DLOCK_DISCARD );
  707.         if( FAILED(hr) )
  708.             return DXTRACE_ERR( TEXT("LockVertexBuffer"), hr );
  709.         float fSizeQuadX = 1.0f;
  710.         float fSizeQuadY = 1.0f;
  711.         hr = m_pTexture->GetLevelDesc( 0, &surfDesc );
  712.         iX = 0.0f;
  713.         for( iCol = 0; iCol<nMeshWidth; iCol++ )
  714.         {
  715.             iY = 0.0f;
  716.             
  717.             for( iRow = 0; iRow<nMeshHeight; iRow++ )
  718.             {
  719.                 // The first texture is the alpha mask.  
  720.                 float tu1 = (float) iRow / (float) (nMeshWidth-1);
  721.                 float tv1 = (float) iCol / (float) (nMeshHeight-1);
  722.                 // The second texture is the source texture, and it's tiled.
  723.                 // Also add a small amount of random variation to the tiling.
  724.                 float tu2 = (float) iRow / (float)  (nMeshWidth-1) * m_pLandStyle->aLayerTile[i] + ((float)(rand() % 100)/100.0f-0.50f)*m_pLandStyle->aLayerRandomness[i];
  725.                 float tv2 = (float) iCol / (float) (nMeshHeight-1) * m_pLandStyle->aLayerTile[i] + ((float)(rand() % 100)/100.0f-0.50f)*m_pLandStyle->aLayerRandomness[i];
  726.                 pVertexBuffer->p   = D3DXVECTOR4( tu1*surfDesc.Width, tv1*surfDesc.Height, 0.0f, 1.0f );
  727.                 pVertexBuffer->tu1 = tu1;
  728.                 pVertexBuffer->tv1 = tv1;
  729.                 pVertexBuffer->tu2 = tu2;
  730.                 pVertexBuffer->tv2 = tv2;
  731.                 pVertexBuffer++;
  732.                 iY += fSizeQuadY;
  733.             }
  734.             iX += fSizeQuadX;
  735.         }
  736.         hr = pVB->Unlock(); 
  737.         if( FAILED(hr) )
  738.             return DXTRACE_ERR( TEXT("UnlockVertexBuffer"), hr );
  739.         g_pd3dDevice->SetStreamSource( 0, pVB, 0, sizeof(RHW_VERTEX) );
  740.         g_pd3dDevice->SetTexture( 0, pAlphaTex[i] );
  741.         g_pd3dDevice->SetTexture( 1, pSrcTex[i] );
  742.         g_pd3dDevice->DrawIndexedPrimitive( D3DPT_TRIANGLELIST, 0, 0, dwNumVerties, 0, dwNumFaces );
  743.     }
  744.     hr = pRenderToSurface->EndScene( D3DX_FILTER_LINEAR );
  745.     SAFE_RELEASE( pRenderSurface );
  746.     g_pd3dDevice->SetTextureStageState( 1, D3DTSS_COLOROP,   D3DTOP_DISABLE );
  747.     SAFE_RELEASE( pIB );
  748.     SAFE_RELEASE( pVB );
  749.     SAFE_RELEASE( pRenderToSurface );
  750.     for( i=0; i<m_pLandStyle->dwNumLayers; i++ )
  751.     {
  752.         SAFE_RELEASE( pSrcTex[i] );
  753.         SAFE_RELEASE( pAlphaTex[i] );
  754.     }
  755.     
  756.     return S_OK;
  757. }
  758. //-----------------------------------------------------------------------------
  759. // Name: 
  760. // Desc: 
  761. //-----------------------------------------------------------------------------
  762. HRESULT CTerrainMesh::CreateTextureFromHeight( int nWidth, int nHeight )
  763. {
  764.     HRESULT hr;
  765.     // Create a D3DFMT_A8R8G8B8 texture.  use D3DPOOL_SCRATCH to create this texture 
  766.     // even if the video card doesn't support it.
  767.     LPDIRECT3DTEXTURE9 pScratchTexture = NULL;
  768.     hr = D3DXCreateTexture( g_pd3dDevice, nWidth*2, nHeight*2, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_SCRATCH, &pScratchTexture );
  769.     if( FAILED(hr) )
  770.         return DXTRACE_ERR( TEXT("D3DXCreateTexture"), hr );
  771.     D3DSURFACE_DESC surfDesc;
  772.     hr = pScratchTexture->GetLevelDesc( 0, &surfDesc );
  773.     if( FAILED(hr) )
  774.         return DXTRACE_ERR( TEXT("GetLevelDesc"), hr );
  775.     assert( surfDesc.Format == D3DFMT_A8R8G8B8 );
  776.     D3DLOCKED_RECT LockedRect;
  777.     hr = pScratchTexture->LockRect( 0, &LockedRect, NULL, 0 );
  778.     if( FAILED(hr) )
  779.         return DXTRACE_ERR( TEXT("LockRect"), hr );
  780.     DWORD* pBits;
  781.     for( DWORD iTexelZ=0; iTexelZ<surfDesc.Height; iTexelZ++ )
  782.     {
  783.         pBits = (DWORD*) ((BYTE*)LockedRect.pBits + LockedRect.Pitch*iTexelZ);
  784.         for( DWORD iTexelX=0; iTexelX<surfDesc.Width; iTexelX++ )
  785.         {
  786.             FLOAT fHeight;
  787.             fHeight = g_pTerrainEngine->GetHeight( iTexelX/2.0f + m_fWorldOffsetX, iTexelZ/2.0f + m_fWorldOffsetZ );
  788.             fHeight /= MAX_HEIGHT_OF_MAP;
  789.             float aClrFactor[10];
  790.             DWORD iColor;
  791.             for( iColor=0; iColor<m_pLandStyle->dwNumLayers; iColor++ )
  792.             {
  793.                 float fHigh, fLow;
  794.                 if( iColor==0 )
  795.                     fLow = -0.25f;
  796.                 else
  797.                     fLow = m_pLandStyle->aLayerHeight[iColor-1];
  798.                 if( iColor==m_pLandStyle->dwNumLayers-1 )
  799.                     fHigh = 1.25f;
  800.                 else
  801.                     fHigh = m_pLandStyle->aLayerHeight[iColor+1];
  802.                 aClrFactor[iColor] = TextureColorFactor( iColor, fHeight );  
  803.             }
  804.             FLOAT fRed   = 0.0f;
  805.             FLOAT fGreen = 0.0f;
  806.             FLOAT fBlue  = 0.0f;
  807.             for( iColor=0; iColor<m_pLandStyle->dwNumLayers; iColor++ )
  808.             {
  809.                 fRed   += aClrFactor[iColor]*(float)RVALUE(m_pLandStyle->aLayerColor[iColor]);
  810.                 fGreen += aClrFactor[iColor]*(float)GVALUE(m_pLandStyle->aLayerColor[iColor]);
  811.                 fBlue  += aClrFactor[iColor]*(float)BVALUE(m_pLandStyle->aLayerColor[iColor]);
  812.             }
  813.             DWORD nRed   = (DWORD) fRed;
  814.             DWORD nGreen = (DWORD) fGreen;
  815.             DWORD nBlue  = (DWORD) fBlue;
  816.             if( nRed > 0xFF )
  817.                 nRed = 0xFF;
  818.             if( nGreen > 0xFF )
  819.                 nGreen = 0xFF;
  820.             if( nBlue > 0xFF )
  821.                 nBlue = 0xFF;
  822.             *pBits = (0xFF << 24) + (nRed << 16) + (nGreen << 8) + (nBlue << 0);
  823.             pBits++;
  824.         }
  825.     }        
  826.     hr = pScratchTexture->UnlockRect( 0 );
  827.     if( FAILED(hr) )
  828.         return DXTRACE_ERR( TEXT("UnlockRect"), hr );   
  829.     // Create a texture w/ a format supported by the video card
  830.     hr = D3DXCreateTexture( g_pd3dDevice, nWidth*2, nHeight*2, 1, 0, m_fmtTexture, D3DPOOL_MANAGED, &m_pTexture );
  831.     if( FAILED(hr) )
  832.         return DXTRACE_ERR( TEXT("D3DXCreateTexture"), hr );
  833.     // Use d3dx to convert from the scratch texture to a card supported texture format 
  834.     IDirect3DSurface9* pSurfaceSrc = NULL;
  835.     IDirect3DSurface9* pSurfaceDest = NULL;
  836.     m_pTexture->GetSurfaceLevel( 0, &pSurfaceDest );
  837.     pScratchTexture->GetSurfaceLevel( 0, &pSurfaceSrc );
  838.     hr = D3DXLoadSurfaceFromSurface( pSurfaceDest, NULL, NULL, pSurfaceSrc, NULL, NULL, D3DX_FILTER_POINT, 0 );
  839.     if( FAILED(hr) )
  840.         return DXTRACE_ERR( TEXT("D3DXLoadSurfaceFromSurface"), hr );
  841.     SAFE_RELEASE( pSurfaceDest );
  842.     SAFE_RELEASE( pSurfaceSrc );
  843.     SAFE_RELEASE( pScratchTexture );
  844.     
  845.     return S_OK;
  846. }
  847. //-----------------------------------------------------------------------------
  848. // Name: 
  849. // Desc: 
  850. //-----------------------------------------------------------------------------
  851. HRESULT CTerrainMesh::FrameMove( const float fElapsedTime )
  852. {
  853.     return S_OK;
  854. }
  855. //-----------------------------------------------------------------------------
  856. // Name: 
  857. // Desc: 
  858. //-----------------------------------------------------------------------------
  859. HRESULT CTerrainMesh::RenderFrame( float fWrapOffsetX, float fWrapOffsetZ, DWORD* pdwNumVerts )
  860. {
  861.     HRESULT hr = S_OK;
  862.     assert( m_pMesh != NULL );
  863.     // Setup a material
  864.     D3DMATERIAL9 mtrl;
  865.     ZeroMemory( &mtrl, sizeof(D3DMATERIAL9) );
  866.     mtrl.Diffuse.r = mtrl.Ambient.r = 1.0f;
  867.     mtrl.Diffuse.g = mtrl.Ambient.g = 1.0f;
  868.     mtrl.Diffuse.b = mtrl.Ambient.b = 1.0f;
  869.     mtrl.Diffuse.a = mtrl.Ambient.a = 1.0f;
  870.     g_pd3dDevice->SetMaterial( &mtrl );
  871.     g_pd3dDevice->SetTexture( 0, m_pTexture );
  872.     g_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
  873.     g_pd3dDevice->SetRenderState( D3DRS_SRCBLEND,     D3DBLEND_SRCALPHA  );
  874.     g_pd3dDevice->SetRenderState( D3DRS_DESTBLEND,    D3DBLEND_INVSRCALPHA );
  875.     g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP,   D3DTOP_MODULATE  );
  876.     g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
  877.     g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
  878.     g_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP,   D3DTOP_SELECTARG1  );
  879.     g_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
  880.     g_pd3dDevice->SetSamplerState( 0, D3DSAMP_MIPFILTER, D3DTEXF_POINT);
  881.     D3DXMatrixTranslation( &m_matWorld, fWrapOffsetX + m_fWorldOffsetX, 0.0f, fWrapOffsetZ + m_fWorldOffsetZ );
  882.     g_pd3dDevice->SetTransform( D3DTS_WORLD, &m_matWorld );
  883.     if( pdwNumVerts )
  884.         *pdwNumVerts = m_pMesh->GetNumFaces();
  885.     if( g_Profile.bRenderGround )
  886.     {
  887.         hr = m_pMesh->DrawSubset( 0 );
  888.         if( FAILED(hr) )
  889.             return DXTRACE_ERR( TEXT("DrawSubset"), hr );
  890.     }
  891.     return S_OK;
  892. }
  893. //-----------------------------------------------------------------------------
  894. // Name: 
  895. // Desc: 
  896. //-----------------------------------------------------------------------------
  897. HRESULT CTerrainMesh::InvalidateDeviceObjects()
  898. {
  899.     SAFE_RELEASE( m_pMesh );
  900.     SAFE_RELEASE( m_pTexture );
  901.     return S_OK;
  902. }
  903. //-----------------------------------------------------------------------------
  904. // Name: 
  905. // Desc: 
  906. //-----------------------------------------------------------------------------
  907. HRESULT CTerrainMesh::DeleteDeviceObjects()
  908. {
  909.     return S_OK;
  910. }
  911. //-----------------------------------------------------------------------------
  912. // Name: 
  913. // Desc: 
  914. //-----------------------------------------------------------------------------
  915. VOID CTerrainMesh::FinalCleanup()
  916. {
  917.     SAFE_DELETE( m_pMap );
  918. }
  919. //-----------------------------------------------------------------------------
  920. // Name: 
  921. // Desc: 
  922. //-----------------------------------------------------------------------------
  923. DWORD CTerrainMesh::GetTexelColor( DWORD iLevel, float x, float z )
  924. {
  925.     HRESULT hr;
  926.     DWORD dwResult = 0;
  927.     D3DSURFACE_DESC surfDesc;
  928.     hr = m_pTexture->GetLevelDesc( iLevel, &surfDesc );
  929.     
  930.     x -= m_fWorldOffsetX;
  931.     z -= m_fWorldOffsetZ;
  932.     DWORD dwTexelX = (DWORD) ( x * (surfDesc.Width  / m_pMap->m_fXSize) );
  933.     DWORD dwTexelZ = (DWORD) ( z * (surfDesc.Height / m_pMap->m_fZSize) );
  934.     D3DLOCKED_RECT LockedRect;
  935.     hr = m_pTexture->LockRect( iLevel, &LockedRect, NULL, 0 );
  936.     if( FAILED(hr) )
  937.         return DXTRACE_ERR( TEXT("LockRect"), hr );
  938.     switch( surfDesc.Format )
  939.     {
  940.         case D3DFMT_A8R8G8B8:
  941.         case D3DFMT_X8R8G8B8:
  942.         {
  943.             DWORD* pBits = (DWORD*) ((BYTE*)LockedRect.pBits + LockedRect.Pitch*dwTexelZ);
  944.             pBits += dwTexelX;
  945.             dwResult = *pBits;
  946.             break;
  947.         }
  948.     }
  949.     hr = m_pTexture->UnlockRect( iLevel );
  950.     if( FAILED(hr) )
  951.         return DXTRACE_ERR( TEXT("UnlockRect"), hr );   
  952.     return dwResult;
  953. }
  954. //-----------------------------------------------------------------------------
  955. // Name: 
  956. // Desc: 
  957. //-----------------------------------------------------------------------------
  958. HRESULT CTerrainMesh::SaveMeshToXFile()
  959. {
  960. /*
  961.     HRESULT hr;
  962.     TCHAR strFileName[MAX_PATH];
  963.     lstrcpy( strFileName, m_pLandStyle->szHeightMap );
  964.     strFileName[lstrlen(strFileName)-4] = 0;
  965.     lstrcat( strFileName, TEXT("-save.x") );
  966.     DWORD* pdwAdjaceny  = NULL;
  967.     pdwAdjaceny = new DWORD[ 3 * m_pMesh->GetNumFaces() ];
  968.     if( pdwAdjaceny == NULL )
  969.         return E_OUTOFMEMORY;
  970.     hr = m_pMesh->GenerateAdjacency( 0.01f, pdwAdjaceny );
  971.     if( FAILED(hr) )
  972.         return DXTRACE_ERR( TEXT("GenerateAdjacency"), hr );
  973.     hr = D3DXSaveMeshToX( strFileName, m_pMesh, pdwAdjaceny, NULL, 0, DXFILEFORMAT_TEXT );
  974.     if( FAILED(hr) )
  975.         return DXTRACE_ERR( TEXT("D3DXSaveMeshToX"), hr );
  976.     
  977.     SAFE_DELETE_ARRAY( pdwAdjaceny );
  978. */  
  979.     return S_OK;
  980. }
  981. //-----------------------------------------------------------------------------
  982. // Name: 
  983. // Desc: 
  984. //-----------------------------------------------------------------------------
  985. HRESULT CTerrainMesh::SaveTextureToFile()
  986. {
  987.     HRESULT hr;
  988.     TCHAR strFileName[MAX_PATH];
  989.     lstrcpy( strFileName, m_pLandStyle->szHeightMap );
  990.     strFileName[lstrlen(strFileName)-4] = 0;
  991.     lstrcat( strFileName, TEXT("-save.bmp") );
  992.     hr = D3DXSaveTextureToFile( strFileName, D3DXIFF_BMP, m_pTexture, NULL );
  993.     if( FAILED(hr) )
  994.         return DXTRACE_ERR( TEXT("D3DXSaveTextureToFile"), hr );
  995.     
  996.     return S_OK;
  997. }