admin 管理员组

文章数量: 1184232

dx9.0地形

  1. 照相机
    这里照相机有
    3种移动方式:
    1.x轴:left/right
    2.y轴:up/down
    3.z轴:forward/backward
    3种旋转方式:
    1.x轴:rotate on right vector
    2.y轴:rotate on up vector
    3.z轴:rotate on look vector
    计算视图矩阵
    1.平移:将摄像机的位置移动到原点

  2. 地形

    1.从raw文件加载高度图readRawFile
    2.生成地形几何数据:
    顶点缓存

    v[index]=TerrainVertex((float)x,(float)_heightmap[index],(float)z,(float)j * uCoordIncrementSize,(float)i * vCoordIncrementSize);

    索引缓存

    indices[baseIndex]= i * _numVertsPerRow + j;
    indices[baseIndex +1]= i * _numVertsPerRow + j +1;
    indices[baseIndex +2]=(i +1)* _numVertsPerRow + j;
    indices[baseIndex +3]=(i +1)* _numVertsPerRow + j;
    indices[baseIndex +4]= i * _numVertsPerRow + j +1;
    indices[baseIndex +5]=(i +1)* _numVertsPerRow + j +1;

    3.根据高度生成纹理

    DWORD* imageData =(DWORD*)lockedRect.pBits;for(int i =0; i < texHeight; i++){for(int j =0; j < texWidth; j++){
    			D3DXCOLOR c;// get height of upper left vertex of quad.float height =(float)getHeightmapEntry(i, j)/ _heightScale;if((height)<42.5f) 		 c = d3d::BEACH_SAND;elseif((height)<85.0f)	 c = d3d::LIGHT_YELLOW_GREEN;elseif((height)<127.5f) c = d3d::PUREGREEN;elseif((height)<170.0f) c = d3d::DARK_YELLOW_GREEN;elseif((height)<212.5f) c = d3d::DARKBROWN;else	                     c = d3d::WHITE;// fill locked data, note we divide the pitch by four because the// pitch is given in bytes and there are 4 bytes per DWORD.
    			imageData[i * lockedRect.Pitch /4+ j]=(D3DCOLOR)c;}}

    4.根据光线和平面法线的照射角度生成明暗属性

    // build two vectors on the quad
    	D3DXVECTOR3 u(_cellSpacing, heightB - heightA,0.0f);
    	D3DXVECTOR3 v(0.0f, heightC - heightA,-_cellSpacing);// find the normal by taking the cross product of two// vectors on the quad.
    	D3DXVECTOR3 n;D3DXVec3Cross(&n,&u,&v);D3DXVec3Normalize(&n,&n);float cosine =D3DXVec3Dot(&n, directionToLight);if(cosine <0.0f)
    		cosine =0.0f;

    5.根据位置判断上下三角形获取位置高度

    //  A   B//  *---*//  | / |//  *---*  //  C   D

    float A = getHeightmapEntry(row, col);
    float B = getHeightmapEntry(row, col + 1);
    float C = getHeightmapEntry(row + 1, col);
    float D = getHeightmapEntry(row + 1, col + 1);

    //
    // Find the triangle we are in:
    //
    // Translate by the transformation that takes the upper-left
    // corner of the cell we are in to the origin.  Recall that our 
    // cellspacing was nomalized to 1.  Thus we have a unit square
    // at the origin of our +x -> 'right' and +z -> 'down' system.
    float dx = x - col;
    float dz = z - row;
    // Note the below compuations of u and v are unneccessary, we really
    // only need the height, but we compute the entire vector to emphasis
    // the books discussion.
    float height = 0.0f;
    if (dz < 1.0f - dx)  // upper triangle ABC
    {
    	float uy = B - A; // A->B
    	float vy = C - A; // A->C
    	// Linearly interpolate on each vector.  The height is the vertex
    	// height the vectors u and v originate from {A}, plus the heights
    	// found by interpolating on each vector u and v.
    	height = A + d3d::Lerp(0.0f, uy, dx) + d3d::Lerp(0.0f, vy, dz);
    }
    else // lower triangle DCB
    {
    	float uy = C - D; // D->C
    	float vy = B - D; // D->B
    	// Linearly interpolate on each vector.  The height is the vertex
    	// height the vectors u and v originate from {D}, plus the heights
    	// found by interpolating on each vector u and v.
    	height = D + d3d::Lerp(0.0f, uy, 1.0f - dx) + d3d::Lerp(0.0f, vy, 1.0f - dz);
    }
    
  3. 原书代码修改部分

这里sprintf_s(_fpsString, 8, “%f”, _fps)的_fps的长度会超过8位,改为stringstream就不用担心这个问题

boolFPSCounter::render(D3DCOLOR color,float timeDelta){if(_font){
		_frameCnt++;
		_timeElapsed += timeDelta;if(_timeElapsed >=1.0f){
			_fps =(float)_frameCnt / _timeElapsed;
			std::stringstream ss;//std::string fpsStr;
			ss << _fps;
			ss >> _fpsString;//strncpy_s(_fpsString, 9, fpsStr.c_str(), 9);//sprintf_s(_fpsString, 8, "%f", _fps);
			_fpsString[8]='\0';// mark end of string
			_timeElapsed =0.0f;
			_frameCnt =0;}
		_font->DrawText(20,20, color, _fpsString);}returntrue;}
  1. 运行效果
#pragmaonce#include<tchar.h>#include<D3D9.h>// Font creation flags#defineD3DFONT_BOLD0x0001#defineD3DFONT_ITALIC0x0002#defineD3DFONT_ZENABLE0x0004// Font rendering flags#defineD3DFONT_CENTERED_X0x0001#defineD3DFONT_CENTERED_Y0x0002#defineD3DFONT_TWOSIDED0x0004#defineD3DFONT_FILTERED0x0008//-----------------------------------------------------------------------------// Name: class CD3DFont// Desc: Texture-based font class for doing text in a 3D scene.//-----------------------------------------------------------------------------classCD3DFont{
    TCHAR   m_strFontName[80];// Font properties
    DWORD   m_dwFontHeight;
    DWORD   m_dwFontFlags;
    LPDIRECT3DDEVICE9       m_pd3dDevice;// A D3DDevice used for rendering
    LPDIRECT3DTEXTURE9      m_pTexture;// The d3d texture for this font
    LPDIRECT3DVERTEXBUFFER9 m_pVB;// VertexBuffer for rendering text
    DWORD   m_dwTexWidth;// Texture dimensions
    DWORD   m_dwTexHeight;
    FLOAT   m_fTextScale;
    FLOAT   m_fTexCoords[128-32][4];
    DWORD   m_dwSpacing;// Character pixel spacing per side// Stateblocks for setting and restoring render states
    LPDIRECT3DSTATEBLOCK9 m_pStateBlockSaved;
    LPDIRECT3DSTATEBLOCK9 m_pStateBlockDrawText;public:// 2D and 3D text drawing functions
    HRESULT DrawText(FLOAT x, FLOAT y, DWORD dwColor,const TCHAR* strText, DWORD dwFlags =0L);
    HRESULT DrawTextScaled(FLOAT x, FLOAT y, FLOAT z,
        FLOAT fXScale, FLOAT fYScale, DWORD dwColor,const TCHAR* strText, DWORD dwFlags =0L);
    HRESULT Render3DText(const TCHAR* strText, DWORD dwFlags =0L);// Function to get extent of text
    HRESULT GetTextExtent(const TCHAR* strText, SIZE* pSize);// Initializing and destroying device-dependent objects
    HRESULT InitDeviceObjects(LPDIRECT3DDEVICE9 pd3dDevice);
    HRESULT RestoreDeviceObjects();
    HRESULT InvalidateDeviceObjects();
    HRESULT DeleteDeviceObjects();// Constructor / destructorCD3DFont(const TCHAR* strFontName, DWORD dwHeight, DWORD dwFlags =0L);~CD3DFont();};

d3dfont.cpp

//-----------------------------------------------------------------------------// File: D3DFont.cpp//// Desc: Texture-based font class//// Copyright (c) 1999-2001 Microsoft Corporation. All rights reserved.//-----------------------------------------------------------------------------#defineSTRICT#include<stdio.h>#include<tchar.h>#include<D3DX9.h>#include"D3DFont.h"#include"D3DUtil.h"#include"DXUtil.h"//-----------------------------------------------------------------------------// Custom vertex types for rendering text//-----------------------------------------------------------------------------#defineMAX_NUM_VERTICES50*6structFONT2DVERTEX{ D3DXVECTOR4 p;   DWORD color;     FLOAT tu, tv;};structFONT3DVERTEX{ D3DXVECTOR3 p;   D3DXVECTOR3 n;   FLOAT tu, tv;};#defineD3DFVF_FONT2DVERTEX(D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1)#defineD3DFVF_FONT3DVERTEX(D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX1)inline FONT2DVERTEX InitFont2DVertex(const D3DXVECTOR4& p, D3DCOLOR color,
    FLOAT tu, FLOAT tv){
    FONT2DVERTEX v;   v.p = p;   v.color = color;   v.tu = tu;   v.tv = tv;return v;}inline FONT3DVERTEX InitFont3DVertex(const D3DXVECTOR3& p,const D3DXVECTOR3& n,
    FLOAT tu, FLOAT tv){
    FONT3DVERTEX v;   v.p = p;   v.n = n;   v.tu = tu;   v.tv = tv;return v;}//-----------------------------------------------------------------------------// Name: CD3DFont()// Desc: Font class constructor//-----------------------------------------------------------------------------CD3DFont::CD3DFont(const TCHAR* strFontName, DWORD dwHeight, DWORD dwFlags){_tcsncpy_s(m_strFontName, strFontName,sizeof(m_strFontName)/sizeof(TCHAR));
    m_strFontName[sizeof(m_strFontName)/sizeof(TCHAR)-1]=_T('\0');
    m_dwFontHeight = dwHeight;
    m_dwFontFlags = dwFlags;
    m_dwSpacing =0;
    m_pd3dDevice =NULL;
    m_pTexture =NULL;
    m_pVB =NULL;
    m_pStateBlockSaved =NULL;
    m_pStateBlockDrawText =NULL;}//-----------------------------------------------------------------------------// Name: ~CD3DFont()// Desc: Font class destructor//-----------------------------------------------------------------------------CD3DFont::~CD3DFont(){InvalidateDeviceObjects();DeleteDeviceObjects();}//-----------------------------------------------------------------------------// Name: InitDeviceObjects()// Desc: Initializes device-dependent objects, including the vertex buffer used//       for rendering text and the texture map which stores the font image.//-----------------------------------------------------------------------------
HRESULT CD3DFont::InitDeviceObjects(LPDIRECT3DDEVICE9 pd3dDevice){
    HRESULT hr;// Keep a local copy of the device
    m_pd3dDevice = pd3dDevice;// Establish the font and texture size
    m_fTextScale =1.0f;// Draw fonts into texture without scaling// Large fonts need larger texturesif(m_dwFontHeight >60)
        m_dwTexWidth = m_dwTexHeight =2048;elseif(m_dwFontHeight >30)
        m_dwTexWidth = m_dwTexHeight =1024;elseif(m_dwFontHeight >15)
        m_dwTexWidth = m_dwTexHeight =512;else
        m_dwTexWidth = m_dwTexHeight =256;// If requested texture is too big, use a smaller texture and smaller font,// and scale up when rendering.
    D3DCAPS9 d3dCaps;
    m_pd3dDevice->GetDeviceCaps(&d3dCaps);if(m_dwTexWidth > d3dCaps.MaxTextureWidth){
        m_fTextScale =(FLOAT)d3dCaps.MaxTextureWidth /(FLOAT)m_dwTexWidth;
        m_dwTexWidth = m_dwTexHeight = d3dCaps.MaxTextureWidth;}// Create a new texture for the font
    hr = m_pd3dDevice->CreateTexture(m_dwTexWidth, m_dwTexHeight,1,0, D3DFMT_A4R4G4B4,
        D3DPOOL_MANAGED,&m_pTexture,NULL);if(FAILED(hr))return hr;// Prepare to create a bitmap
    DWORD* pBitmapBits;
    BITMAPINFO bmi;ZeroMemory(&bmi.bmiHeader,sizeof(BITMAPINFOHEADER));
    bmi.bmiHeader.biSize =sizeof(BITMAPINFOHEADER);
    bmi.bmiHeader.biWidth =(int)m_dwTexWidth;
    bmi.bmiHeader.biHeight =-(int)m_dwTexHeight;
    bmi.bmiHeader.biPlanes =1;
    bmi.bmiHeader.biCompression = BI_RGB;
    bmi.bmiHeader.biBitCount =32;// Create a DC and a bitmap for the font
    HDC     hDC =CreateCompatibleDC(NULL);
    HBITMAP hbmBitmap =CreateDIBSection(hDC,&bmi, DIB_RGB_COLORS,(void**)&pBitmapBits,NULL,0);SetMapMode(hDC, MM_TEXT);// Create a font.  By specifying ANTIALIASED_QUALITY, we might get an// antialiased font, but this is not guaranteed.
    INT nHeight =-MulDiv(m_dwFontHeight,(INT)(GetDeviceCaps(hDC, LOGPIXELSY)* m_fTextScale),72);
    DWORD dwBold =(m_dwFontFlags & D3DFONT_BOLD)? FW_BOLD : FW_NORMAL;
    DWORD dwItalic =(m_dwFontFlags & D3DFONT_ITALIC)? TRUE : FALSE;
    HFONT hFont =CreateFont(nHeight,0,0,0, dwBold, dwItalic,
        FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
        CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY,
        VARIABLE_PITCH, m_strFontName);if(NULL== hFont)return E_FAIL;
    HGDIOBJ hbmOld =SelectObject(hDC, hbmBitmap);
    HGDIOBJ hFontOld =SelectObject(hDC, hFont);// Set text propertiesSetTextColor(hDC,RGB(255,255,255));SetBkColor(hDC,0x00000000);SetTextAlign(hDC, TA_TOP);// Loop through all printable character and output them to the bitmap..// Meanwhile, keep track of the corresponding tex coords for each character.
    DWORD x =0;
    DWORD y =0;
    TCHAR str[2]=_T("x");
    SIZE size;// Calculate the spacing between characters based on line heightGetTextExtentPoint32(hDC,TEXT(" "),1,&size);
    x = m_dwSpacing =(DWORD)ceil(size.cy *0.3f);for(TCHAR c =32; c <127; c++){
        str[0]= c;GetTextExtentPoint32(hDC, str,1,&size);if((DWORD)(x + size.cx + m_dwSpacing)> m_dwTexWidth){
            x = m_dwSpacing;
            y += size.cy +1;}ExtTextOut(hDC, x +0, y +0, ETO_OPAQUE,NULL, str,1,NULL);
        m_fTexCoords[c -32][0]=((FLOAT)(x +0- m_dwSpacing))/ m_dwTexWidth;
        m_fTexCoords[c -32][1]=((FLOAT)(y +0+0))/ m_dwTexHeight;
        m_fTexCoords[c -32][2]=((FLOAT)(x + size.cx + m_dwSpacing))/ m_dwTexWidth;
        m_fTexCoords[c -32][3]=((FLOAT)(y + size.cy +0))/ m_dwTexHeight;
        x += size.cx +(2* m_dwSpacing);}// Lock the surface and write the alpha values for the set pixels
    D3DLOCKED_RECT d3dlr;
    m_pTexture->LockRect(0,&d3dlr,0,0);
    BYTE* pDstRow =(BYTE*)d3dlr.pBits;
    WORD* pDst16;
    BYTE bAlpha;// 4-bit measure of pixel intensityfor(y =0; y < m_dwTexHeight; y++){
        pDst16 =(WORD*)pDstRow;for(x =0; x < m_dwTexWidth; x++){
            bAlpha =(BYTE)((pBitmapBits[m_dwTexWidth * y + x]&0xff)>>4);if(bAlpha >0){*pDst16++=(WORD)((bAlpha <<12)|0x0fff);}else{*pDst16++=0x0000;}}
        pDstRow += d3dlr.Pitch;}// Done updating texture, so clean up used objects
    m_pTexture->UnlockRect(0);SelectObject(hDC, hbmOld);SelectObject(hDC, hFontOld);DeleteObject(hbmBitmap);DeleteObject(hFont);DeleteDC(hDC);return S_OK;}//-----------------------------------------------------------------------------// Name: RestoreDeviceObjects()// Desc://-----------------------------------------------------------------------------
HRESULT CD3DFont::RestoreDeviceObjects(){
    HRESULT hr;// Create vertex buffer for the lettersint vertexSize =max(sizeof(FONT2DVERTEX),sizeof(FONT3DVERTEX));if(FAILED(hr = m_pd3dDevice->CreateVertexBuffer(MAX_NUM_VERTICES * vertexSize,
        D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC,0,
        D3DPOOL_DEFAULT,&m_pVB,NULL))){return hr;}// Create the state blocks for rendering textfor(UINT which =0; which <2; which++){
        m_pd3dDevice->BeginStateBlock();
        m_pd3dDevice->SetTexture(0, m_pTexture);if(D3DFONT_ZENABLE & m_dwFontFlags)
            m_pd3dDevice->SetRenderState(D3DRS_ZENABLE, TRUE);else
            m_pd3dDevice->SetRenderState(D3DRS_ZENABLE, FALSE);
        m_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
        m_pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
        m_pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
        m_pd3dDevice->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE);
        m_pd3dDevice->SetRenderState(D3DRS_ALPHAREF,0x08);
        m_pd3dDevice->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL);
        m_pd3dDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
        m_pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);
        m_pd3dDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE);
        m_pd3dDevice->SetRenderState(D3DRS_CLIPPING, TRUE);
        m_pd3dDevice->SetRenderState(D3DRS_CLIPPLANEENABLE, FALSE);
        m_pd3dDevice->SetRenderState(D3DRS_VERTEXBLEND, D3DVBF_DISABLE);
        m_pd3dDevice->SetRenderState(D3DRS_INDEXEDVERTEXBLENDENABLE, FALSE);
        m_pd3dDevice->SetRenderState(D3DRS_FOGENABLE, FALSE);
        m_pd3dDevice->SetRenderState(D3DRS_COLORWRITEENABLE,
            D3DCOLORWRITEENABLE_RED | D3DCOLORWRITEENABLE_GREEN |
            D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_ALPHA);
        m_pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
        m_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
        m_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
        m_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
        m_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
        m_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
        m_pd3dDevice->SetTextureStageState(0, D3DTSS_TEXCOORDINDEX,0);
        m_pd3dDevice->SetTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE);
        m_pd3dDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
        m_pd3dDevice->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
        m_pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);
        m_pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
        m_pd3dDevice->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_NONE);if(which ==0)
            m_pd3dDevice->EndStateBlock(&m_pStateBlockSaved);else
            m_pd3dDevice->EndStateBlock(&m_pStateBlockDrawText);}return S_OK;}//-----------------------------------------------------------------------------// Name: InvalidateDeviceObjects()// Desc: Destroys all device-dependent objects//-----------------------------------------------------------------------------
HRESULT CD3DFont::InvalidateDeviceObjects(){SAFE_RELEASE(m_pVB);SAFE_RELEASE(m_pStateBlockSaved);SAFE_RELEASE(m_pStateBlockDrawText);return S_OK;}//-----------------------------------------------------------------------------// Name: DeleteDeviceObjects()// Desc: Destroys all device-dependent objects//-----------------------------------------------------------------------------
HRESULT CD3DFont::DeleteDeviceObjects(){SAFE_RELEASE(m_pTexture);
    m_pd3dDevice =NULL;return S_OK;}//-----------------------------------------------------------------------------// Name: GetTextExtent()// Desc: Get the dimensions of a text string//-----------------------------------------------------------------------------
HRESULT CD3DFont::GetTextExtent(const TCHAR* strText, SIZE* pSize){if(NULL== strText ||NULL== pSize)return E_FAIL;
    FLOAT fRowWidth =0.0f;
    FLOAT fRowHeight =(m_fTexCoords[0][3]- m_fTexCoords[0][1])* m_dwTexHeight;
    FLOAT fWidth =0.0f;
    FLOAT fHeight = fRowHeight;while(*strText){
        TCHAR c =*strText++;if(c ==_T('\n')){
            fRowWidth =0.0f;
            fHeight += fRowHeight;}if((c -32)<0||(c -32)>=128-32)continue;
        FLOAT tx1 = m_fTexCoords[c -32][0];
        FLOAT tx2 = m_fTexCoords[c -32][2];
        fRowWidth +=(tx2 - tx1)* m_dwTexWidth -2* m_dwSpacing;if(fRowWidth > fWidth)
            fWidth = fRowWidth;}
    pSize->cx =(int)fWidth;
    pSize->cy =(int)fHeight;return S_OK;}//-----------------------------------------------------------------------------// Name: DrawTextScaled()// Desc: Draws scaled 2D text.  Note that x and y are in viewport coordinates//       (ranging from -1 to +1).  fXScale and fYScale are the size fraction //       relative to the entire viewport.  For example, a fXScale of 0.25 is//       1/8th of the screen width.  This allows you to output text at a fixed//       fraction of the viewport, even if the screen or window size changes.//-----------------------------------------------------------------------------
HRESULT CD3DFont::DrawTextScaled(FLOAT x, FLOAT y, FLOAT z,
    FLOAT fXScale, FLOAT fYScale, DWORD dwColor,const TCHAR* strText, DWORD dwFlags){if(m_pd3dDevice ==NULL)return E_FAIL;// Set up renderstate
    m_pStateBlockSaved->Capture();
    m_pStateBlockDrawText->Apply();
    m_pd3dDevice->SetFVF(D3DFVF_FONT2DVERTEX);
    m_pd3dDevice->SetPixelShader(NULL);
    m_pd3dDevice->SetStreamSource(0, m_pVB,0,sizeof(FONT2DVERTEX));// Set filter statesif(dwFlags & D3DFONT_FILTERED){
        m_pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
        m_pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);}
    D3DVIEWPORT9 vp;
    m_pd3dDevice->GetViewport(&vp);
    FLOAT fLineHeight =(m_fTexCoords[0][3]- m_fTexCoords[0][1])* m_dwTexHeight;// Center the text block in the viewportif(dwFlags & D3DFONT_CENTERED_X){const TCHAR* strTextTmp = strText;float xFinal =0.0f;while(*strTextTmp){
            TCHAR c =*strTextTmp++;if(c ==_T('\n'))break;// Isn't supported.  if((c -32)<0||(c -32)>=128-32)continue;
            FLOAT tx1 = m_fTexCoords[c -32][0];
            FLOAT tx2 = m_fTexCoords[c -32][2];
            FLOAT w =(tx2 - tx1)* m_dwTexWidth;
            w *=(fXScale * vp.Height)/ fLineHeight;
            xFinal += w -(2* m_dwSpacing)*(fXScale * vp.Height)/ fLineHeight;}
        x =-xFinal / vp.Width;}if(dwFlags & D3DFONT_CENTERED_Y){
        y =-fLineHeight / vp.Height;}
    FLOAT sx =(x +1.0f)* vp.Width /2;
    FLOAT sy =(y +1.0f)* vp.Height /2;
    FLOAT sz = z;
    FLOAT rhw =1.0f;// Adjust for character spacing
    sx -= m_dwSpacing *(fXScale * vp.Height)/ fLineHeight;
    FLOAT fStartX = sx;// Fill vertex buffer
    FONT2DVERTEX* pVertices;
    DWORD         dwNumTriangles =0L;
    m_pVB->Lock(0,0,(void**)&pVertices, D3DLOCK_DISCARD);while(*strText){
        TCHAR c =*strText++;if(c ==_T('\n')){
            sx = fStartX;
            sy += fYScale * vp.Height;}if((c -32)<0||(c -32)>=128-32)continue;
        FLOAT tx1 = m_fTexCoords[c -32][0];
        FLOAT ty1 = m_fTexCoords[c -32][1];
        FLOAT tx2 = m_fTexCoords[c -32][2];
        FLOAT ty2 = m_fTexCoords[c -32][3];
        FLOAT w =(tx2 - tx1)* m_dwTexWidth;
        FLOAT h =(ty2 - ty1)* m_dwTexHeight;
        w *=(fXScale * vp.Height)/ fLineHeight;
        h *=(fYScale * vp.Height)/ fLineHeight;if(c !=_T(' ')){*pVertices++=InitFont2DVertex(D3DXVECTOR4(sx +0-0.5f, sy + h -0.5f, sz, rhw), dwColor, tx1, ty2);*pVertices++=InitFont2DVertex(D3DXVECTOR4(sx +0-0.5f, sy +0-0.5f, sz, rhw), dwColor, tx1, ty1);*pVertices++=InitFont2DVertex(D3DXVECTOR4(sx + w -0.5f, sy + h -0.5f, sz, rhw), dwColor, tx2, ty2);*pVertices++=InitFont2DVertex(D3DXVECTOR4(sx + w -0.5f, sy +0-0.5f, sz, rhw), dwColor, tx2, ty1);*pVertices++=InitFont2DVertex(D3DXVECTOR4(sx + w -0.5f, sy + h -0.5f, sz, rhw), dwColor, tx2, ty2);*pVertices++=InitFont2DVertex(D3DXVECTOR4(sx +0-0.5f, sy +0-0.5f, sz, rhw), dwColor, tx1, ty1);
            dwNumTriangles +=2;if(dwNumTriangles *3>(MAX_NUM_VERTICES -6)){// Unlock, render, and relock the vertex buffer
                m_pVB->Unlock();
                m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST,0, dwNumTriangles);
                m_pVB->Lock(0,0,(void**)&pVertices, D3DLOCK_DISCARD);
                dwNumTriangles =0L;}}
        sx += w -(2* m_dwSpacing)*(fXScale * vp.Height)/ fLineHeight;}// Unlock and render the vertex buffer
    m_pVB->Unlock();if(dwNumTriangles >0)
        m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST,0, dwNumTriangles);// Restore the modified renderstates
    m_pStateBlockSaved->Apply();return S_OK;}//-----------------------------------------------------------------------------// Name: DrawText()// Desc: Draws 2D text. Note that sx and sy are in pixels//-----------------------------------------------------------------------------
HRESULT CD3DFont::DrawText(FLOAT sx, FLOAT sy, DWORD dwColor,const TCHAR* strText, DWORD dwFlags){if(m_pd3dDevice ==NULL)return E_FAIL;// Setup renderstate
    m_pStateBlockSaved->Capture();
    m_pStateBlockDrawText->Apply();
    m_pd3dDevice->SetFVF(D3DFVF_FONT2DVERTEX);
    m_pd3dDevice->SetPixelShader(NULL);
    m_pd3dDevice->SetStreamSource(0, m_pVB,0,sizeof(FONT2DVERTEX));// Set filter statesif(dwFlags & D3DFONT_FILTERED){
        m_pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
        m_pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);}// Center the text block in the viewportif(dwFlags & D3DFONT_CENTERED_X){
        D3DVIEWPORT9 vp;
        m_pd3dDevice->GetViewport(&vp);const TCHAR* strTextTmp = strText;float xFinal =0.0f;while(*strTextTmp){
            TCHAR c =*strTextTmp++;if(c ==_T('\n'))break;// Isn't supported.  if((c -32)<0||(c -32)>=128-32)continue;
            FLOAT tx1 = m_fTexCoords[c -32][0];
            FLOAT tx2 = m_fTexCoords[c -32][2];
            FLOAT w =(tx2 - tx1)* m_dwTexWidth / m_fTextScale;
            xFinal += w -(2* m_dwSpacing);}
        sx =(vp.Width - xFinal)/2.0f;}if(dwFlags & D3DFONT_CENTERED_Y){
        D3DVIEWPORT9 vp;
        m_pd3dDevice->GetViewport(&vp);float fLineHeight =((m_fTexCoords[0][3]- m_fTexCoords[0][1])* m_dwTexHeight);
        sy =(vp.Height - fLineHeight)/2;}// Adjust for character spacing
    sx -= m_dwSpacing;
    FLOAT fStartX = sx;// Fill vertex buffer
    FONT2DVERTEX* pVertices =NULL;
    DWORD         dwNumTriangles =0;
    m_pVB->Lock(0,0,(void**)&pVertices, D3DLOCK_DISCARD);while(*strText){
        TCHAR c =*strText++;if(c ==_T('\n')){
            sx = fStartX;
            sy +=(m_fTexCoords[0][3]- m_fTexCoords[0][1])* m_dwTexHeight;}if((c -32)<0||(c -32)>=128-32)continue;
        FLOAT tx1 = m_fTexCoords[c -32][0];
        FLOAT ty1 = m_fTexCoords[c -32][1];
        FLOAT tx2 = m_fTexCoords[c -32][2];
        FLOAT ty2 = m_fTexCoords[c -32][3];
        FLOAT w =(tx2 - tx1)* m_dwTexWidth / m_fTextScale;
        FLOAT h =(ty2 - ty1)* m_dwTexHeight / m_fTextScale;if(c !=_T(' ')){*pVertices++=InitFont2DVertex(D3DXVECTOR4(sx +0-0.5f, sy + h -0.5f,0.9f,1.0f), dwColor, tx1, ty2);*pVertices++=InitFont2DVertex(D3DXVECTOR4(sx +0-0.5f, sy +0-0.5f,0.9f,1.0f), dwColor, tx1, ty1);*pVertices++=InitFont2DVertex(D3DXVECTOR4(sx + w -0.5f, sy + h -0.5f,0.9f,1.0f), dwColor, tx2, ty2);*pVertices++=InitFont2DVertex(D3DXVECTOR4(sx + w -0.5f, sy +0-0.5f,0.9f,1.0f), dwColor, tx2, ty1);*pVertices++=InitFont2DVertex(D3DXVECTOR4(sx + w -0.5f, sy + h -0.5f,0.9f,1.0f), dwColor, tx2, ty2);*pVertices++=InitFont2DVertex(D3DXVECTOR4(sx +0-0.5f, sy +0-0.5f,0.9f,1.0f), dwColor, tx1, ty1);
            dwNumTriangles +=2;if(dwNumTriangles *3>(MAX_NUM_VERTICES -6)){// Unlock, render, and relock the vertex buffer
                m_pVB->Unlock();
                m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST,0, dwNumTriangles);
                pVertices =NULL;
                m_pVB->Lock(0,0,(void**)&pVertices, D3DLOCK_DISCARD);
                dwNumTriangles =0L;}}
        sx += w -(2* m_dwSpacing);}// Unlock and render the vertex buffer
    m_pVB->Unlock();if(dwNumTriangles >0)
        m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST,0, dwNumTriangles);// Restore the modified renderstates
    m_pStateBlockSaved->Apply();return S_OK;}//-----------------------------------------------------------------------------// Name: Render3DText()// Desc: Renders 3D text//-----------------------------------------------------------------------------
HRESULT CD3DFont::Render3DText(const TCHAR* strText, DWORD dwFlags){if(m_pd3dDevice ==NULL)return E_FAIL;// Setup renderstate
    m_pStateBlockSaved->Capture();
    m_pStateBlockDrawText->Apply();
    m_pd3dDevice->SetFVF(D3DFVF_FONT3DVERTEX);
    m_pd3dDevice->SetPixelShader(NULL);
    m_pd3dDevice->SetStreamSource(0, m_pVB,0,sizeof(FONT3DVERTEX));// Set filter statesif(dwFlags & D3DFONT_FILTERED){
        m_pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
        m_pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);}// Position for each text element
    FLOAT x =0.0f;
    FLOAT y =0.0f;// Center the text block at the origin (not the viewport)if(dwFlags & D3DFONT_CENTERED_X){
        SIZE sz;GetTextExtent(strText,&sz);
        x =-(((FLOAT)sz.cx)/10.0f)/2.0f;}if(dwFlags & D3DFONT_CENTERED_Y){
        SIZE sz;GetTextExtent(strText,&sz);
        y =-(((FLOAT)sz.cy)/10.0f)/2.0f;}// Turn off culling for two-sided textif(dwFlags & D3DFONT_TWOSIDED)
        m_pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);// Adjust for character spacing
    x -= m_dwSpacing /10.0f;
    FLOAT fStartX = x;
    TCHAR c;// Fill vertex buffer
    FONT3DVERTEX* pVertices;
    DWORD         dwNumTriangles =0L;
    m_pVB->Lock(0,0,(void**)&pVertices, D3DLOCK_DISCARD);while((c =*strText++)!=0){if(c =='\n'){
            x = fStartX;
            y -=(m_fTexCoords[0][3]- m_fTexCoords[0][1])* m_dwTexHeight /10.0f;}if((c -32)<0||(c -32)>=128-32)continue;
        FLOAT tx1 = m_fTexCoords[c -32][0];
        FLOAT ty1 = m_fTexCoords[c -32][1];
        FLOAT tx2 = m_fTexCoords[c -32][2];
        FLOAT ty2 = m_fTexCoords[c -32][3];
        FLOAT w =(tx2 - tx1)* m_dwTexWidth /(10.0f* m_fTextScale);
        FLOAT h =(ty2 - ty1)* m_dwTexHeight /(10.0f* m_fTextScale);if(c !=_T(' ')){*pVertices++=InitFont3DVertex(D3DXVECTOR3(x +0, y +0,0),D3DXVECTOR3(0,0,-1), tx1, ty2);*pVertices++=InitFont3DVertex(D3DXVECTOR3(x +0, y + h,0),D3DXVECTOR3(0,0,-1), tx1, ty1);*pVertices++=InitFont3DVertex(D3DXVECTOR3(x + w, y +0,0),D3DXVECTOR3(0,0,-1), tx2, ty2);*pVertices++=InitFont3DVertex(D3DXVECTOR3(x + w, y + h,0),D3DXVECTOR3(0,0,-1), tx2, ty1);*pVertices++=InitFont3DVertex(D3DXVECTOR3(x + w, y +0,0),D3DXVECTOR3(0,0,-1), tx2, ty2);*pVertices++=InitFont3DVertex(D3DXVECTOR3(x +0, y + h,0),D3DXVECTOR3(0,0,-1), tx1, ty1);
            dwNumTriangles +=2;if(dwNumTriangles *3>(MAX_NUM_VERTICES -6)){// Unlock, render, and relock the vertex buffer
                m_pVB->Unlock();
                m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST,0, dwNumTriangles);
                m_pVB->Lock(0,0,(void**)&pVertices, D3DLOCK_DISCARD);
                dwNumTriangles =0L;}}
        x += w -(2* m_dwSpacing)/10.0f;}// Unlock and render the vertex buffer
    m_pVB->Unlock();if(dwNumTriangles >0)
        m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST,0, dwNumTriangles);// Restore the modified renderstates
    m_pStateBlockSaved->Apply();return S_OK;}

d3dutil.h

#pragmaonce#include<D3D9.h>#include<D3DX9Math.h>//-----------------------------------------------------------------------------// Name: D3DUtil_InitMaterial()// Desc: Initializes a D3DMATERIAL9 structure, setting the diffuse and ambient//       colors. It does not set emissive or specular colors.//-----------------------------------------------------------------------------
VOID D3DUtil_InitMaterial(D3DMATERIAL9& mtrl, FLOAT r =0.0f, FLOAT g =0.0f,
    FLOAT b =0.0f, FLOAT a =1.0f);//-----------------------------------------------------------------------------// Name: D3DUtil_InitLight()// Desc: Initializes a D3DLIGHT structure, setting the light position. The//       diffuse color is set to white, specular and ambient left as black.//-----------------------------------------------------------------------------
VOID D3DUtil_InitLight(D3DLIGHT9& light, D3DLIGHTTYPE ltType,
    FLOAT x =0.0f, FLOAT y =0.0f, FLOAT z =0.0f);//-----------------------------------------------------------------------------// Name: D3DUtil_CreateTexture()// Desc: Helper function to create a texture. It checks the root path first,//       then tries the DXSDK media path (as specified in the system registry).//-----------------------------------------------------------------------------
HRESULT D3DUtil_CreateTexture(LPDIRECT3DDEVICE9 pd3dDevice, TCHAR* strTexture,
    LPDIRECT3DTEXTURE9* ppTexture,
    D3DFORMAT d3dFormat = D3DFMT_UNKNOWN);//-----------------------------------------------------------------------------// Name: D3DUtil_GetCubeMapViewMatrix()// Desc: Returns a view matrix for rendering to a face of a cubemap.//-----------------------------------------------------------------------------
D3DXMATRIX D3DUtil_GetCubeMapViewMatrix(DWORD dwFace);//-----------------------------------------------------------------------------// Name: D3DUtil_GetRotationFromCursor()// Desc: Returns a quaternion for the rotation implied by the window's cursor//       position.//-----------------------------------------------------------------------------
D3DXQUATERNION D3DUtil_GetRotationFromCursor(HWND hWnd,
    FLOAT fTrackBallRadius =1.0f);//-----------------------------------------------------------------------------// Name: D3DUtil_SetDeviceCursor// Desc: Builds and sets a cursor for the D3D device based on hCursor.//-----------------------------------------------------------------------------
HRESULT D3DUtil_SetDeviceCursor(LPDIRECT3DDEVICE9 pd3dDevice, HCURSOR hCursor,
    BOOL bAddWatermark);//-----------------------------------------------------------------------------// Name: D3DUtil_D3DFormatToString// Desc: Returns the string for the given D3DFORMAT.//       bWithPrefix determines whether the string should include the "D3DFMT_"//-----------------------------------------------------------------------------
TCHAR*D3DUtil_D3DFormatToString(D3DFORMAT format,bool bWithPrefix =true);//-----------------------------------------------------------------------------// Name: class CD3DArcBall// Desc://-----------------------------------------------------------------------------classCD3DArcBall{
    INT            m_iWidth;// ArcBall's window width
    INT            m_iHeight;// ArcBall's window height
    FLOAT          m_fRadius;// ArcBall's radius in screen coords
    FLOAT          m_fRadiusTranslation;// ArcBall's radius for translating the target
    D3DXQUATERNION m_qDown;// Quaternion before button down
    D3DXQUATERNION m_qNow;// Composite quaternion for current drag
    D3DXMATRIXA16  m_matRotation;// Matrix for arcball's orientation
    D3DXMATRIXA16  m_matRotationDelta;// Matrix for arcball's orientation
    D3DXMATRIXA16  m_matTranslation;// Matrix for arcball's position
    D3DXMATRIXA16  m_matTranslationDelta;// Matrix for arcball's position
    BOOL           m_bDrag;// Whether user is dragging arcball
    BOOL           m_bRightHanded;// Whether to use RH coordinate system
    D3DXVECTOR3 ScreenToVector(int sx,int sy);public:
    LRESULT     HandleMouseMessages(HWND, UINT, WPARAM, LPARAM);
    D3DXMATRIX*GetRotationMatrix(){return&m_matRotation;}
    D3DXMATRIX*GetRotationDeltaMatrix(){return&m_matRotationDelta;}
    D3DXMATRIX*GetTranslationMatrix(){return&m_matTranslation;}
    D3DXMATRIX*GetTranslationDeltaMatrix(){return&m_matTranslationDelta;}
    BOOL        IsBeingDragged(){return m_bDrag;}
    VOID        SetRadius(FLOAT fRadius);
    VOID        SetWindow(INT w, INT h, FLOAT r =0.9);
    VOID        SetRightHanded(BOOL bRightHanded){ m_bRightHanded = bRightHanded;}CD3DArcBall();
    VOID        Init();};//-----------------------------------------------------------------------------// Name: class CD3DCamera// Desc://-----------------------------------------------------------------------------classCD3DCamera{
    D3DXVECTOR3 m_vEyePt;// Attributes for view matrix
    D3DXVECTOR3 m_vLookatPt;
    D3DXVECTOR3 m_vUpVec;
    D3DXVECTOR3 m_vView;
    D3DXVECTOR3 m_vCross;
    D3DXMATRIXA16  m_matView;
    D3DXMATRIXA16  m_matBillboard;// Special matrix for billboarding effects
    FLOAT       m_fFOV;// Attributes for projection matrix
    FLOAT       m_fAspect;
    FLOAT       m_fNearPlane;
    FLOAT       m_fFarPlane;
    D3DXMATRIXA16  m_matProj;public:// Access functions
    D3DXVECTOR3 GetEyePt(){return m_vEyePt;}
    D3DXVECTOR3 GetLookatPt(){return m_vLookatPt;}
    D3DXVECTOR3 GetUpVec(){return m_vUpVec;}
    D3DXVECTOR3 GetViewDir(){return m_vView;}
    D3DXVECTOR3 GetCross(){return m_vCross;}
    FLOAT       GetFOV(){return m_fFOV;}
    FLOAT       GetAspect(){return m_fAspect;}
    FLOAT       GetNearPlane(){return m_fNearPlane;}
    FLOAT       GetFarPlane(){return m_fFarPlane;}
    D3DXMATRIX  GetViewMatrix(){return m_matView;}
    D3DXMATRIX  GetBillboardMatrix(){return m_matBillboard;}
    D3DXMATRIX  GetProjMatrix(){return m_matProj;}
    VOID SetViewParams(D3DXVECTOR3& vEyePt, D3DXVECTOR3& vLookatPt,
        D3DXVECTOR3& vUpVec);
    VOID SetProjParams(FLOAT fFOV, FLOAT fAspect, FLOAT fNearPlane,
        FLOAT fFarPlane);CD3DCamera();};

d3dutil.cpp

#defineSTRICT#include<Windows.h>#include<WindowsX.h>#include<tchar.h>#include<stdio.h>#include"D3DUtil.h"#include"DXUtil.h"#include"D3DX9.h"//-----------------------------------------------------------------------------// Name: D3DUtil_InitMaterial()// Desc: Initializes a D3DMATERIAL9 structure, setting the diffuse and ambient//       colors. It does not set emissive or specular colors.//-----------------------------------------------------------------------------
VOID D3DUtil_InitMaterial(D3DMATERIAL9& mtrl, FLOAT r, FLOAT g, FLOAT b,
    FLOAT a){ZeroMemory(&mtrl,sizeof(D3DMATERIAL9));
    mtrl.Diffuse.r = mtrl.Ambient.r = r;
    mtrl.Diffuse.g = mtrl.Ambient.g = g;
    mtrl.Diffuse.b = mtrl.Ambient.b = b;
    mtrl.Diffuse.a = mtrl.Ambient.a = a;}//-----------------------------------------------------------------------------// Name: D3DUtil_InitLight()// Desc: Initializes a D3DLIGHT structure, setting the light position. The//       diffuse color is set to white; specular and ambient are left as black.//-----------------------------------------------------------------------------
VOID D3DUtil_InitLight(D3DLIGHT9& light, D3DLIGHTTYPE ltType,
    FLOAT x, FLOAT y, FLOAT z){
    D3DXVECTOR3 vecLightDirUnnormalized(x, y, z);ZeroMemory(&light,sizeof(D3DLIGHT9));
    light.Type = ltType;
    light.Diffuse.r =1.0f;
    light.Diffuse.g =1.0f;
    light.Diffuse.b =1.0f;D3DXVec3Normalize((D3DXVECTOR3*)&light.Direction,&vecLightDirUnnormalized);
    light.Position.x = x;
    light.Position.y = y;
    light.Position.z = z;
    light.Range =1000.0f;}//-----------------------------------------------------------------------------// Name: D3DUtil_CreateTexture()// Desc: Helper function to create a texture. It checks the root path first,//       then tries the DXSDK media path (as specified in the system registry).//-----------------------------------------------------------------------------
HRESULT D3DUtil_CreateTexture(LPDIRECT3DDEVICE9 pd3dDevice, TCHAR* strTexture,
    LPDIRECT3DTEXTURE9* ppTexture, D3DFORMAT d3dFormat){
    HRESULT hr;
    TCHAR strPath[MAX_PATH];// Get the path to the textureif(FAILED(hr =DXUtil_FindMediaFileCb(strPath,sizeof(strPath), strTexture)))return hr;// Create the texture using D3DXreturnD3DXCreateTextureFromFileEx(pd3dDevice, strPath,
        D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT,0, d3dFormat,
        D3DPOOL_MANAGED, D3DX_FILTER_TRIANGLE | D3DX_FILTER_MIRROR,
        D3DX_FILTER_TRIANGLE | D3DX_FILTER_MIRROR,0,NULL,NULL, ppTexture);}//-----------------------------------------------------------------------------// Name: D3DUtil_GetCubeMapViewMatrix()// Desc: Returns a view matrix for rendering to a face of a cubemap.//-----------------------------------------------------------------------------
D3DXMATRIX D3DUtil_GetCubeMapViewMatrix(DWORD dwFace){
    D3DXVECTOR3 vEyePt =D3DXVECTOR3(0.0f,0.0f,0.0f);
    D3DXVECTOR3 vLookDir;
    D3DXVECTOR3 vUpDir;switch(dwFace){case D3DCUBEMAP_FACE_POSITIVE_X:
        vLookDir =D3DXVECTOR3(1.0f,0.0f,0.0f);
        vUpDir =D3DXVECTOR3(0.0f,1.0f,0.0f);break;case D3DCUBEMAP_FACE_NEGATIVE_X:
        vLookDir =D3DXVECTOR3(-1.0f,0.0f,0.0f);
        vUpDir =D3DXVECTOR3(0.0f,1.0f,0.0f);break;case D3DCUBEMAP_FACE_POSITIVE_Y:
        vLookDir =D3DXVECTOR3(0.0f,1.0f,0.0f);
        vUpDir =D3DXVECTOR3(0.0f,0.0f,-1.0f);break;case D3DCUBEMAP_FACE_NEGATIVE_Y:
        vLookDir =D3DXVECTOR3(0.0f,-1.0f,0.0f);
        vUpDir =D3DXVECTOR3(0.0f,0.0f,1.0f);break;case D3DCUBEMAP_FACE_POSITIVE_Z:
        vLookDir =D3DXVECTOR3(0.0f,0.0f,1.0f);
        vUpDir =D3DXVECTOR3(0.0f,1.0f,0.0f);break;case D3DCUBEMAP_FACE_NEGATIVE_Z:
        vLookDir =D3DXVECTOR3(0.0f,0.0f,-1.0f);
        vUpDir =D3DXVECTOR3(0.0f,1.0f,0.0f);break;}// Set the view transform for this cubemap surface
    D3DXMATRIXA16 matView;D3DXMatrixLookAtLH(&matView,&vEyePt,&vLookDir,&vUpDir);return matView;}//-----------------------------------------------------------------------------// Name: D3DUtil_GetRotationFromCursor()// Desc: Returns a quaternion for the rotation implied by the window's cursor//       position.//-----------------------------------------------------------------------------
D3DXQUATERNION D3DUtil_GetRotationFromCursor(HWND hWnd,
    FLOAT fTrackBallRadius){
    POINT pt;
    RECT  rc;GetCursorPos(&pt);GetClientRect(hWnd,&rc);ScreenToClient(hWnd,&pt);
    FLOAT sx =(((2.0f* pt.x)/(rc.right - rc.left))-1);
    FLOAT sy =(((2.0f* pt.y)/(rc.bottom - rc.top))-1);
    FLOAT sz;if(sx ==0.0f&& sy ==0.0f)returnD3DXQUATERNION(0.0f,0.0f,0.0f,1.0f);
    FLOAT d2 =sqrtf(sx * sx + sy * sy);if(d2 < fTrackBallRadius *0.70710678118654752440)// Inside sphere
        sz =sqrtf(fTrackBallRadius * fTrackBallRadius - d2 * d2);else// On hyperbola
        sz =(fTrackBallRadius * fTrackBallRadius)/(2.0f* d2);// Get two points on trackball's sphere
    D3DXVECTOR3 p1(sx, sy, sz);
    D3DXVECTOR3 p2(0.0f,0.0f, fTrackBallRadius);// Get axis of rotation, which is cross product of p1 and p2
    D3DXVECTOR3 vAxis;D3DXVec3Cross(&vAxis,&p1,&p2);// Calculate angle for the rotation about that axis
    D3DXVECTOR3 vecDiff = p2 - p1;
    FLOAT t =D3DXVec3Length(&vecDiff)/(2.0f* fTrackBallRadius);if(t >+1.0f) t =+1.0f;if(t <-1.0f) t =-1.0f;
    FLOAT fAngle =2.0f*asinf(t);// Convert axis to quaternion
    D3DXQUATERNION quat;D3DXQuaternionRotationAxis(&quat,&vAxis, fAngle);return quat;}//-----------------------------------------------------------------------------// Name: D3DUtil_SetDeviceCursor// Desc: Gives the D3D device a cursor with image and hotspot from hCursor.//-----------------------------------------------------------------------------
HRESULT D3DUtil_SetDeviceCursor(LPDIRECT3DDEVICE9 pd3dDevice, HCURSOR hCursor,
    BOOL bAddWatermark){
    HRESULT hr = E_FAIL;
    ICONINFO iconinfo;
    BOOL bBWCursor;
    LPDIRECT3DSURFACE9 pCursorSurface =NULL;
    HDC hdcColor =NULL;
    HDC hdcMask =NULL;
    HDC hdcScreen =NULL;
    BITMAP bm;
    DWORD dwWidth;
    DWORD dwHeightSrc;
    DWORD dwHeightDest;
    COLORREF crColor;
    COLORREF crMask;
    UINT x;
    UINT y;
    BITMAPINFO bmi;
    COLORREF* pcrArrayColor =NULL;
    COLORREF* pcrArrayMask =NULL;
    DWORD* pBitmap;
    HGDIOBJ hgdiobjOld;ZeroMemory(&iconinfo,sizeof(iconinfo));if(!GetIconInfo(hCursor,&iconinfo))goto End;if(0==GetObject((HGDIOBJ)iconinfo.hbmMask,sizeof(BITMAP),(LPVOID)&bm))goto End;
    dwWidth = bm.bmWidth;
    dwHeightSrc = bm.bmHeight;if(iconinfo.hbmColor ==NULL){
        bBWCursor = TRUE;
        dwHeightDest = dwHeightSrc /2;}else{
        bBWCursor = FALSE;
        dwHeightDest = dwHeightSrc;}// Create a surface for the fullscreen cursorif(FAILED(hr = pd3dDevice->CreateOffscreenPlainSurface(dwWidth, dwHeightDest,
        D3DFMT_A8R8G8B8, D3DPOOL_SCRATCH,&pCursorSurface,NULL))){goto End;}
    pcrArrayMask =new DWORD[dwWidth * dwHeightSrc];ZeroMemory(&bmi,sizeof(bmi));
    bmi.bmiHeader.biSize =sizeof(bmi.bmiHeader);
    bmi.bmiHeader.biWidth = dwWidth;
    bmi.bmiHeader.biHeight = dwHeightSrc;
    bmi.bmiHeader.biPlanes =1;
    bmi.bmiHeader.biBitCount =32;
    bmi.bmiHeader.biCompression = BI_RGB;
    hdcScreen =GetDC(NULL);
    hdcMask =CreateCompatibleDC(hdcScreen);if(hdcMask ==NULL){
        hr = E_FAIL;goto End;}
    hgdiobjOld =SelectObject(hdcMask, iconinfo.hbmMask);GetDIBits(hdcMask, iconinfo.hbmMask,0, dwHeightSrc,
        pcrArrayMask,&bmi, DIB_RGB_COLORS);SelectObject(hdcMask, hgdiobjOld);if(!bBWCursor){
        pcrArrayColor =new DWORD[dwWidth * dwHeightDest];
        hdcColor =CreateCompatibleDC(hdcScreen);if(hdcColor ==NULL){
            hr = E_FAIL;goto End;}SelectObject(hdcColor, iconinfo.hbmColor);GetDIBits(hdcColor, iconinfo.hbmColor,0, dwHeightDest,
            pcrArrayColor,&bmi, DIB_RGB_COLORS);}// Transfer cursor image into the surface
    D3DLOCKED_RECT lr;
    pCursorSurface->LockRect(&lr,NULL,0);
    pBitmap =(DWORD*)lr.pBits;for(y =0; y < dwHeightDest; y++){for(x =0; x < dwWidth; x++){if(bBWCursor){
                crColor = pcrArrayMask[dwWidth *(dwHeightDest -1- y)+ x];
                crMask = pcrArrayMask[dwWidth *(dwHeightSrc -1- y)+ x];}else{
                crColor = pcrArrayColor[dwWidth *(dwHeightDest -1- y)+ x];
                crMask = pcrArrayMask[dwWidth *(dwHeightDest -1- y)+ x];}if(crMask ==0)
                pBitmap[dwWidth * y + x]=0xff000000| crColor;else
                pBitmap[dwWidth * y + x]=0x00000000;// It may be helpful to make the D3D cursor look slightly // different from the Windows cursor so you can distinguish // between the two when developing/testing code.  When// bAddWatermark is TRUE, the following code adds some// small grey "D3D" characters to the upper-left corner of// the D3D cursor image.if(bAddWatermark && x <12&& y <5){// 11.. 11.. 11.. .... CCC0// 1.1. ..1. 1.1. .... A2A0// 1.1. .1.. 1.1. .... A4A0// 1.1. ..1. 1.1. .... A2A0// 11.. 11.. 11.. .... CCC0const WORD wMask[5]={0xccc0,0xa2a0,0xa4a0,0xa2a0,0xccc0};if(wMask[y]&(1<<(15- x))){
                    pBitmap[dwWidth * y + x]|=0xff808080;}}}}
    pCursorSurface->UnlockRect();// Set the device cursorif(FAILED(hr = pd3dDevice->SetCursorProperties(iconinfo.xHotspot,
        iconinfo.yHotspot, pCursorSurface))){goto End;}
    hr = S_OK;
End:if(iconinfo.hbmMask !=NULL)DeleteObject(iconinfo.hbmMask);if(iconinfo.hbmColor !=NULL)DeleteObject(iconinfo.hbmColor);if(hdcScreen !=NULL)ReleaseDC(NULL, hdcScreen);if(hdcColor !=NULL)DeleteDC(hdcColor);if(hdcMask !=NULL)DeleteDC(hdcMask);SAFE_DELETE_ARRAY(pcrArrayColor);SAFE_DELETE_ARRAY(pcrArrayMask);SAFE_RELEASE(pCursorSurface);return hr;}//-----------------------------------------------------------------------------// Name: D3DFormatToString// Desc: Returns the string for the given D3DFORMAT.//-----------------------------------------------------------------------------
TCHAR*D3DUtil_D3DFormatToString(D3DFORMAT format,bool bWithPrefix){
    TCHAR* pstr =NULL;switch(format){case D3DFMT_UNKNOWN:         pstr =(TCHAR*)TEXT("D3DFMT_UNKNOWN");break;case D3DFMT_R8G8B8:          pstr =(TCHAR*)TEXT("D3DFMT_R8G8B8");break;case D3DFMT_A8R8G8B8:        pstr =(TCHAR*)TEXT("D3DFMT_A8R8G8B8");break;case D3DFMT_X8R8G8B8:        pstr =(TCHAR*)TEXT("D3DFMT_X8R8G8B8");break;case D3DFMT_R5G6B5:          pstr =(TCHAR*)TEXT("D3DFMT_R5G6B5");break;case D3DFMT_X1R5G5B5:        pstr =(TCHAR*)TEXT("D3DFMT_X1R5G5B5");break;case D3DFMT_A1R5G5B5:        pstr =(TCHAR*)TEXT("D3DFMT_A1R5G5B5");break;case D3DFMT_A4R4G4B4:        pstr =(TCHAR*)TEXT("D3DFMT_A4R4G4B4");break;case D3DFMT_R3G3B2:          pstr =(TCHAR*)TEXT("D3DFMT_R3G3B2");break;case D3DFMT_A8:              pstr =(TCHAR*)TEXT("D3DFMT_A8");break;case D3DFMT_A8R3G3B2:        pstr =(TCHAR*)TEXT("D3DFMT_A8R3G3B2");break;case D3DFMT_X4R4G4B4:        pstr =(TCHAR*)TEXT("D3DFMT_X4R4G4B4");break;case D3DFMT_A2B10G10R10:     pstr =(TCHAR*)TEXT("D3DFMT_A2B10G10R10");break;case D3DFMT_A8B8G8R8:        pstr =(TCHAR*)TEXT("D3DFMT_A8B8G8R8");break;case D3DFMT_X8B8G8R8:        pstr =(TCHAR*)TEXT("D3DFMT_X8B8G8R8");break;case D3DFMT_G16R16:          pstr =(TCHAR*)TEXT("D3DFMT_G16R16");break;case D3DFMT_A2R10G10B10:     pstr =(TCHAR*)TEXT("D3DFMT_A2R10G10B10");break;case D3DFMT_A16B16G16R16:    pstr =(TCHAR*)TEXT("D3DFMT_A16B16G16R16");break;case D3DFMT_A8P8:            pstr =(TCHAR*)TEXT("D3DFMT_A8P8");break;case D3DFMT_P8:              pstr =(TCHAR*)TEXT("D3DFMT_P8");break;case D3DFMT_L8:              pstr =(TCHAR*)TEXT("D3DFMT_L8");break;case D3DFMT_A8L8:            pstr =(TCHAR*)TEXT("D3DFMT_A8L8");break;case D3DFMT_A4L4:            pstr =(TCHAR*)TEXT("D3DFMT_A4L4");break;case D3DFMT_V8U8:            pstr =(TCHAR*)TEXT("D3DFMT_V8U8");break;case D3DFMT_L6V5U5:          pstr =(TCHAR*)TEXT("D3DFMT_L6V5U5");break;case D3DFMT_X8L8V8U8:        pstr =(TCHAR*)TEXT("D3DFMT_X8L8V8U8");break;case D3DFMT_Q8W8V8U8:        pstr =(TCHAR*)TEXT("D3DFMT_Q8W8V8U8");break;case D3DFMT_V16U16:          pstr =(TCHAR*)TEXT("D3DFMT_V16U16");break;case D3DFMT_A2W10V10U10:     pstr =(TCHAR*)TEXT("D3DFMT_A2W10V10U10");break;case D3DFMT_UYVY:            pstr =(TCHAR*)TEXT("D3DFMT_UYVY");break;case D3DFMT_YUY2:            pstr =(TCHAR*)TEXT("D3DFMT_YUY2");break;case D3DFMT_DXT1:            pstr =(TCHAR*)TEXT("D3DFMT_DXT1");break;case D3DFMT_DXT2:            pstr =(TCHAR*)TEXT("D3DFMT_DXT2");break;case D3DFMT_DXT3:            pstr =(TCHAR*)TEXT("D3DFMT_DXT3");break;case D3DFMT_DXT4:            pstr =(TCHAR*)TEXT("D3DFMT_DXT4");break;case D3DFMT_DXT5:            pstr =(TCHAR*)TEXT("D3DFMT_DXT5");break;case D3DFMT_D16_LOCKABLE:    pstr =(TCHAR*)TEXT("D3DFMT_D16_LOCKABLE");break;case D3DFMT_D32:             pstr =(TCHAR*)TEXT("D3DFMT_D32");break;case D3DFMT_D15S1:           pstr =(TCHAR*)TEXT("D3DFMT_D15S1");break;case D3DFMT_D24S8:           pstr =(TCHAR*)TEXT("D3DFMT_D24S8");break;case D3DFMT_D24X8:           pstr =(TCHAR*)TEXT("D3DFMT_D24X8");break;case D3DFMT_D24X4S4:         pstr =(TCHAR*)TEXT("D3DFMT_D24X4S4");break;case D3DFMT_D16:             pstr =(TCHAR*)TEXT("D3DFMT_D16");break;case D3DFMT_L16:             pstr =(TCHAR*)TEXT("D3DFMT_L16");break;case D3DFMT_VERTEXDATA:      pstr =(TCHAR*)TEXT("D3DFMT_VERTEXDATA");break;case D3DFMT_INDEX16:         pstr =(TCHAR*)TEXT("D3DFMT_INDEX16");break;case D3DFMT_INDEX32:         pstr =(TCHAR*)TEXT("D3DFMT_INDEX32");break;case D3DFMT_Q16W16V16U16:    pstr =(TCHAR*)TEXT("D3DFMT_Q16W16V16U16");break;case D3DFMT_MULTI2_ARGB8:    pstr =(TCHAR*)TEXT("D3DFMT_MULTI2_ARGB8");break;case D3DFMT_R16F:            pstr =(TCHAR*)TEXT("D3DFMT_R16F");break;case D3DFMT_G16R16F:         pstr =(TCHAR*)TEXT("D3DFMT_G16R16F");break;case D3DFMT_A16B16G16R16F:   pstr =(TCHAR*)TEXT("D3DFMT_A16B16G16R16F");break;case D3DFMT_R32F:            pstr =(TCHAR*)TEXT("D3DFMT_R32F");break;case D3DFMT_G32R32F:         pstr =(TCHAR*)TEXT("D3DFMT_G32R32F");break;case D3DFMT_A32B32G32R32F:   pstr =(TCHAR*)TEXT("D3DFMT_A32B32G32R32F");break;case D3DFMT_CxV8U8:          pstr =(TCHAR*)TEXT("D3DFMT_CxV8U8");break;default:                     pstr =(TCHAR*)TEXT("Unknown format");break;}if(bWithPrefix ||_tcsstr(pstr,TEXT("D3DFMT_"))==NULL)return pstr;elsereturn pstr +lstrlen(TEXT("D3DFMT_"));}//-----------------------------------------------------------------------------// Name: D3DXQuaternionUnitAxisToUnitAxis2// Desc: Axis to axis quaternion double angle (no normalization)//       Takes two points on unit sphere an angle THETA apart, returns//       quaternion that represents a rotation around cross product by 2*THETA.//-----------------------------------------------------------------------------inline D3DXQUATERNION* WINAPI D3DXQuaternionUnitAxisToUnitAxis2(D3DXQUATERNION* pOut,const D3DXVECTOR3* pvFrom,const D3DXVECTOR3* pvTo){
    D3DXVECTOR3 vAxis;D3DXVec3Cross(&vAxis, pvFrom, pvTo);// proportional to sin(theta)
    pOut->x = vAxis.x;
    pOut->y = vAxis.y;
    pOut->z = vAxis.z;
    pOut->w =D3DXVec3Dot(pvFrom, pvTo);return pOut;}//-----------------------------------------------------------------------------// Name: D3DXQuaternionAxisToAxis// Desc: Axis to axis quaternion //       Takes two points on unit sphere an angle THETA apart, returns//       quaternion that represents a rotation around cross product by theta.//-----------------------------------------------------------------------------inline D3DXQUATERNION* WINAPI D3DXQuaternionAxisToAxis(D3DXQUATERNION* pOut,const D3DXVECTOR3* pvFrom,const D3DXVECTOR3* pvTo){
    D3DXVECTOR3 vA, vB;D3DXVec3Normalize(&vA, pvFrom);D3DXVec3Normalize(&vB, pvTo);
    D3DXVECTOR3 vHalf(vA + vB);D3DXVec3Normalize(&vHalf,&vHalf);returnD3DXQuaternionUnitAxisToUnitAxis2(pOut,&vA,&vHalf);}//-----------------------------------------------------------------------------// Name:// Desc://-----------------------------------------------------------------------------CD3DArcBall::CD3DArcBall(){Init();}//-----------------------------------------------------------------------------// Name:// Desc://-----------------------------------------------------------------------------voidCD3DArcBall::Init(){D3DXQuaternionIdentity(&m_qDown);D3DXQuaternionIdentity(&m_qNow);D3DXMatrixIdentity(&m_matRotation);D3DXMatrixIdentity(&m_matRotationDelta);D3DXMatrixIdentity(&m_matTranslation);D3DXMatrixIdentity(&m_matTranslationDelta);
    m_bDrag = FALSE;
    m_fRadiusTranslation =1.0f;
    m_bRightHanded = FALSE;}//-----------------------------------------------------------------------------// Name:// Desc://-----------------------------------------------------------------------------
VOID CD3DArcBall::SetWindow(int iWidth,int iHeight,float fRadius){// Set ArcBall info
    m_iWidth = iWidth;
    m_iHeight = iHeight;
    m_fRadius = fRadius;}//-----------------------------------------------------------------------------// Name:// Desc://-----------------------------------------------------------------------------
D3DXVECTOR3 CD3DArcBall::ScreenToVector(int sx,int sy){// Scale to screen
    FLOAT x =-(sx - m_iWidth /2)/(m_fRadius * m_iWidth /2);
    FLOAT y =(sy - m_iHeight /2)/(m_fRadius * m_iHeight /2);if(m_bRightHanded){
        x =-x;
        y =-y;}
    FLOAT z =0.0f;
    FLOAT mag = x * x + y * y;if(mag >1.0f){
        FLOAT scale =1.0f/sqrtf(mag);
        x *= scale;
        y *= scale;}else
        z =sqrtf(1.0f- mag);// Return vectorreturnD3DXVECTOR3(x, y, z);}//-----------------------------------------------------------------------------// Name:// Desc://-----------------------------------------------------------------------------
VOID CD3DArcBall::SetRadius(FLOAT fRadius){
    m_fRadiusTranslation = fRadius;}//-----------------------------------------------------------------------------// Name:// Desc://-----------------------------------------------------------------------------
LRESULT CD3DArcBall::HandleMouseMessages(HWND hWnd, UINT uMsg, WPARAM wParam,
    LPARAM lParam){UNREFERENCED_PARAMETER(hWnd);staticint         iCurMouseX;// Saved mouse positionstaticint         iCurMouseY;static D3DXVECTOR3 s_vDown;// Button down vector// Current mouse positionint iMouseX =GET_X_LPARAM(lParam);int iMouseY =GET_Y_LPARAM(lParam);switch(uMsg){case WM_RBUTTONDOWN:case WM_MBUTTONDOWN:// Store off the position of the cursor when the button is pressed
        iCurMouseX = iMouseX;
        iCurMouseY = iMouseY;return TRUE;case WM_LBUTTONDOWN:// Start drag mode
        m_bDrag = TRUE;
        s_vDown =ScreenToVector(iMouseX, iMouseY);
        m_qDown = m_qNow;return TRUE;case WM_LBUTTONUP:// End drag mode
        m_bDrag = FALSE;return TRUE;case WM_MOUSEMOVE:// Drag objectif(MK_LBUTTON & wParam){if(m_bDrag){// recompute m_qNow
                D3DXVECTOR3 vCur =ScreenToVector(iMouseX, iMouseY);
                D3DXQUATERNION qAxisToAxis;D3DXQuaternionAxisToAxis(&qAxisToAxis,&s_vDown,&vCur);
                m_qNow = m_qDown;
                m_qNow *= qAxisToAxis;D3DXMatrixRotationQuaternion(&m_matRotationDelta,&qAxisToAxis);}elseD3DXMatrixIdentity(&m_matRotationDelta);D3DXMatrixRotationQuaternion(&m_matRotation,&m_qNow);
            m_bDrag = TRUE;}elseif((MK_RBUTTON & wParam)||(MK_MBUTTON & wParam)){// Normalize based on size of window and bounding sphere radius
            FLOAT fDeltaX =(iCurMouseX - iMouseX)* m_fRadiusTranslation / m_iWidth;
            FLOAT fDeltaY =(iCurMouseY - iMouseY)* m_fRadiusTranslation / m_iHeight;if(wParam & MK_RBUTTON){D3DXMatrixTranslation(&m_matTranslationDelta,-2* fDeltaX,2* fDeltaY,0.0f);D3DXMatrixMultiply(&m_matTranslation,&m_matTranslation,&m_matTranslationDelta);}else// wParam & MK_MBUTTON{D3DXMatrixTranslation(&m_matTranslationDelta,0.0f,0.0f,5* fDeltaY);D3DXMatrixMultiply(&m_matTranslation,&m_matTranslation,&m_matTranslationDelta);}// Store mouse coordinate
            iCurMouseX = iMouseX;
            iCurMouseY = iMouseY;}return TRUE;}return FALSE;}//-----------------------------------------------------------------------------// Name:// Desc://-----------------------------------------------------------------------------CD3DCamera::CD3DCamera(){// Set attributes for the view matrix
    D3DXVECTOR3 vEyePt(0.0f,0.0f,0.0f);
    D3DXVECTOR3 vLookatPt(0.0f,0.0f,1.0f);
    D3DXVECTOR3 vUpVec(0.0f,1.0f,0.0f);SetViewParams(vEyePt, vLookatPt, vUpVec);// Set attributes for the projection matrixSetProjParams(D3DX_PI /4,1.0f,1.0f,1000.0f);}//-----------------------------------------------------------------------------// Name:// Desc://-----------------------------------------------------------------------------
VOID CD3DCamera::SetViewParams(D3DXVECTOR3& vEyePt, D3DXVECTOR3& vLookatPt,
    D3DXVECTOR3& vUpVec){// Set attributes for the view matrix
    m_vEyePt = vEyePt;
    m_vLookatPt = vLookatPt;
    m_vUpVec = vUpVec;
    D3DXVECTOR3 vDir = m_vLookatPt - m_vEyePt;D3DXVec3Normalize(&m_vView,&vDir);D3DXVec3Cross(&m_vCross,&m_vView,&m_vUpVec);D3DXMatrixLookAtLH(&m_matView,&m_vEyePt,&m_vLookatPt,&m_vUpVec);D3DXMatrixInverse(&m_matBillboard,NULL,&m_matView);
    m_matBillboard._41 =0.0f;
    m_matBillboard._42 =0.0f;
    m_matBillboard._43 =0.0f;}//-----------------------------------------------------------------------------// Name:// Desc://-----------------------------------------------------------------------------
VOID CD3DCamera::SetProjParams(FLOAT fFOV, FLOAT fAspect, FLOAT fNearPlane,
    FLOAT fFarPlane){// Set attributes for the projection matrix
    m_fFOV = fFOV;
    m_fAspect = fAspect;
    m_fNearPlane = fNearPlane;
    m_fFarPlane = fFarPlane;D3DXMatrixPerspectiveFovLH(&m_matProj, fFOV, fAspect, fNearPlane, fFarPlane);}

dxutil.h

#pragmaonce//-----------------------------------------------------------------------------// Miscellaneous helper functions//-----------------------------------------------------------------------------#defineSAFE_DELETE(p){if(p){delete(p);(p)=NULL;}}#defineSAFE_DELETE_ARRAY(p){if(p){delete[](p);(p)=NULL;}}#defineSAFE_RELEASE(p){if(p){(p)->Release();(p)=NULL;}}#ifndefUNDER_CE//-----------------------------------------------------------------------------// Name: DXUtil_GetDXSDKMediaPath() and DXUtil_FindMediaFile() // Desc: Returns the DirectX SDK path, as stored in the system registry//       during the SDK install.//-----------------------------------------------------------------------------
HRESULT DXUtil_GetDXSDKMediaPathCch(TCHAR* strDest,int cchDest);
HRESULT DXUtil_GetDXSDKMediaPathCb(TCHAR* szDest,int cbDest);
HRESULT DXUtil_FindMediaFileCch(TCHAR* strDestPath,int cchDest, TCHAR* strFilename);
HRESULT DXUtil_FindMediaFileCb(TCHAR* szDestPath,int cbDest, TCHAR* strFilename);#endif// !UNDER_CE//-----------------------------------------------------------------------------// Name: DXUtil_Read*RegKey() and DXUtil_Write*RegKey()// Desc: Helper functions to read/write a string registry key //-----------------------------------------------------------------------------
HRESULT DXUtil_WriteStringRegKey(HKEY hKey, TCHAR* strRegName, TCHAR* strValue);
HRESULT DXUtil_WriteIntRegKey(HKEY hKey, TCHAR* strRegName, DWORD dwValue);
HRESULT DXUtil_WriteGuidRegKey(HKEY hKey, TCHAR* strRegName, GUID guidValue);
HRESULT DXUtil_WriteBoolRegKey(HKEY hKey, TCHAR* strRegName, BOOL bValue);
HRESULT DXUtil_ReadStringRegKeyCch(HKEY hKey, TCHAR* strRegName, TCHAR* strDest, DWORD cchDest, TCHAR* strDefault);
HRESULT DXUtil_ReadStringRegKeyCb(HKEY hKey, TCHAR* strRegName, TCHAR* strDest, DWORD cbDest, TCHAR* strDefault);
HRESULT DXUtil_ReadIntRegKey(HKEY hKey, TCHAR* strRegName, DWORD* pdwValue, DWORD dwDefault);
HRESULT DXUtil_ReadGuidRegKey(HKEY hKey, TCHAR* strRegName, GUID* pGuidValue, GUID& guidDefault);
HRESULT DXUtil_ReadBoolRegKey(HKEY hKey, TCHAR* strRegName, BOOL* pbValue, BOOL bDefault);//-----------------------------------------------------------------------------// Name: DXUtil_Timer()// Desc: Performs timer opertations. Use the following commands://          TIMER_RESET           - to reset the timer//          TIMER_START           - to start the timer//          TIMER_STOP            - to stop (or pause) the timer//          TIMER_ADVANCE         - to advance the timer by 0.1 seconds//          TIMER_GETABSOLUTETIME - to get the absolute system time//          TIMER_GETAPPTIME      - to get the current time//          TIMER_GETELAPSEDTIME  - to get the time that elapsed between //                                  TIMER_GETELAPSEDTIME calls//-----------------------------------------------------------------------------enumTIMER_COMMAND{
    TIMER_RESET, TIMER_START, TIMER_STOP, TIMER_ADVANCE,
    TIMER_GETABSOLUTETIME, TIMER_GETAPPTIME, TIMER_GETELAPSEDTIME
};
FLOAT __stdcall DXUtil_Timer(TIMER_COMMAND command);//-----------------------------------------------------------------------------// UNICODE support for converting between CHAR, TCHAR, and WCHAR strings//-----------------------------------------------------------------------------
HRESULT DXUtil_ConvertAnsiStringToWideCch(WCHAR* wstrDestination,const CHAR* strSource,int cchDestChar);
HRESULT DXUtil_ConvertWideStringToAnsiCch(CHAR* strDestination,const WCHAR* wstrSource,int cchDestChar);
HRESULT DXUtil_ConvertGenericStringToAnsiCch(CHAR* strDestination,const TCHAR* tstrSource,int cchDestChar);
HRESULT DXUtil_ConvertGenericStringToWideCch(WCHAR* wstrDestination,const TCHAR* tstrSource,int cchDestChar);
HRESULT DXUtil_ConvertAnsiStringToGenericCch(TCHAR* tstrDestination,const CHAR* strSource,int cchDestChar);
HRESULT DXUtil_ConvertWideStringToGenericCch(TCHAR* tstrDestination,const WCHAR* wstrSource,int cchDestChar);
HRESULT DXUtil_ConvertAnsiStringToWideCb(WCHAR* wstrDestination,const CHAR* strSource,int cbDestChar);
HRESULT DXUtil_ConvertWideStringToAnsiCb(CHAR* strDestination,const WCHAR* wstrSource,int cbDestChar);
HRESULT DXUtil_ConvertGenericStringToAnsiCb(CHAR* strDestination,const TCHAR* tstrSource,int cbDestChar);
HRESULT DXUtil_ConvertGenericStringToWideCb(WCHAR* wstrDestination,const TCHAR* tstrSource,int cbDestChar);
HRESULT DXUtil_ConvertAnsiStringToGenericCb(TCHAR* tstrDestination,const CHAR* strSource,int cbDestChar);
HRESULT DXUtil_ConvertWideStringToGenericCb(TCHAR* tstrDestination,const WCHAR* wstrSource,int cbDestChar);//-----------------------------------------------------------------------------// Readme functions//-----------------------------------------------------------------------------
VOID DXUtil_LaunchReadme(HWND hWnd, TCHAR* strLoc =NULL);//-----------------------------------------------------------------------------// GUID to String converting //-----------------------------------------------------------------------------
HRESULT DXUtil_ConvertGUIDToStringCch(const GUID* pGuidSrc, TCHAR* strDest,int cchDestChar);
HRESULT DXUtil_ConvertGUIDToStringCb(const GUID* pGuidSrc, TCHAR* strDest,int cbDestChar);
HRESULT DXUtil_ConvertStringToGUID(const TCHAR* strIn, GUID* pGuidOut);//-----------------------------------------------------------------------------// Debug printing support// See dxerr9.h for more debug printing support//-----------------------------------------------------------------------------
VOID    DXUtil_Trace(TCHAR* strMsg,...);#ifdefined(DEBUG)|defined(_DEBUG)#defineDXTRACEDXUtil_Trace#else#defineDXTRACEsizeof#endif//-----------------------------------------------------------------------------// Name: ArrayListType// Desc: Indicates how data should be stored in a CArrayList//-----------------------------------------------------------------------------enumArrayListType{
    AL_VALUE,// entry data is copied into the list
    AL_REFERENCE,// entry pointers are copied into the list};//-----------------------------------------------------------------------------// Name: CArrayList// Desc: A growable array//-----------------------------------------------------------------------------classCArrayList{protected:
    ArrayListType m_ArrayListType;void* m_pData;
    UINT m_BytesPerEntry;
    UINT m_NumEntries;
    UINT m_NumEntriesAllocated;public:CArrayList(ArrayListType Type, UINT BytesPerEntry =0);~CArrayList(void);
    HRESULT Add(void* pEntry);voidRemove(UINT Entry);void*GetPtr(UINT Entry);
    UINT Count(void){return m_NumEntries;}boolContains(void* pEntryData);voidClear(void){ m_NumEntries =0;}};//-----------------------------------------------------------------------------// WinCE build support//-----------------------------------------------------------------------------#ifdefUNDER_CE#defineCheckDlgButton(hdialog, id, state)::SendMessage(::GetDlgItem(hdialog, id), BM_SETCHECK, state,0)#defineIsDlgButtonChecked(hdialog, id)::SendMessage(::GetDlgItem(hdialog, id), BM_GETCHECK,0L,0L)#defineGETTIMESTAMPGetTickCount#define_TWINCE(x)_T(x)
__inline intGetScrollPos(HWND hWnd,int nBar){
    SCROLLINFO si;memset(&si,0,sizeof(si));
    si.cbSize =sizeof(si);
    si.fMask = SIF_POS;if(!GetScrollInfo(hWnd, nBar,&si)){return0;}else{return si.nPos;}}#else// !UNDER_CE#defineGETTIMESTAMPtimeGetTime#define_TWINCE(x) x#endif// UNDER_CE

dxutil.cpp

//-----------------------------------------------------------------------------// File: DXUtil.cpp//// Desc: Shortcut macros and functions for using DX objects//// Copyright (c) Microsoft Corporation. All rights reserved//-----------------------------------------------------------------------------#ifndefSTRICT#defineSTRICT#endif// !STRICT#include<windows.h>#include<mmsystem.h>#include<tchar.h>#include<stdio.h>#include<stdarg.h>#include"DXUtil.h"#ifdefUNICODEtypedefHINSTANCE(WINAPI* LPShellExecute)(HWND hwnd, LPCWSTR lpOperation, LPCWSTR lpFile, LPCWSTR lpParameters, LPCWSTR lpDirectory, INT nShowCmd);#elsetypedefHINSTANCE(WINAPI* LPShellExecute)(HWND hwnd, LPCSTR lpOperation, LPCSTR lpFile, LPCSTR lpParameters, LPCSTR lpDirectory, INT nShowCmd);#endif#ifndefUNDER_CE//-----------------------------------------------------------------------------// Name: DXUtil_GetDXSDKMediaPathCch()// Desc: Returns the DirectX SDK media path//       cchDest is the size in TCHARs of strDest.  Be careful not to //       pass in sizeof(strDest) on UNICODE builds.//-----------------------------------------------------------------------------
HRESULT DXUtil_GetDXSDKMediaPathCch(TCHAR* strDest,int cchDest){if(strDest ==NULL|| cchDest <1)return E_INVALIDARG;lstrcpy(strDest,TEXT(""));// Open the appropriate registry key
    HKEY  hKey;
    LONG lResult =RegOpenKeyEx(HKEY_LOCAL_MACHINE,_T("Software\\Microsoft\\DirectX SDK"),0, KEY_READ,&hKey);if(ERROR_SUCCESS != lResult)return E_FAIL;
    DWORD dwType;
    DWORD dwSize = cchDest *sizeof(TCHAR);
    lResult =RegQueryValueEx(hKey,_T("DX9SDK Samples Path"),NULL,&dwType,(BYTE*)strDest,&dwSize);
    strDest[cchDest -1]=0;// RegQueryValueEx doesn't NULL term if buffer too smallRegCloseKey(hKey);if(ERROR_SUCCESS != lResult)return E_FAIL;const TCHAR* strMedia =_T("\\Media\\");if(lstrlen(strDest)+lstrlen(strMedia)< cchDest)_tcscat_s(strDest, cchDest, strMedia);elsereturn E_INVALIDARG;return S_OK;}#endif// !UNDER_CE#ifndefUNDER_CE//-----------------------------------------------------------------------------// Name: DXUtil_FindMediaFileCch()// Desc: Returns a valid path to a DXSDK media file//       cchDest is the size in TCHARs of strDestPath.  Be careful not to //       pass in sizeof(strDest) on UNICODE builds.//-----------------------------------------------------------------------------
HRESULT DXUtil_FindMediaFileCch(TCHAR* strDestPath,int cchDest, TCHAR* strFilename){
    HRESULT hr;
    HANDLE file;
    TCHAR* strShortNameTmp =NULL;
    TCHAR strShortName[MAX_PATH];int cchPath;if(NULL== strFilename ||NULL== strDestPath || cchDest <1)return E_INVALIDARG;lstrcpy(strDestPath,TEXT(""));lstrcpy(strShortName,TEXT(""));// Build full path name from strFileName (strShortName will be just the leaf filename)
    cchPath =GetFullPathName(strFilename, cchDest, strDestPath,&strShortNameTmp);if((cchPath ==0)||(cchDest <= cchPath))return E_FAIL;if(strShortNameTmp)lstrcpyn(strShortName, strShortNameTmp, MAX_PATH);// first try to find the filename given a full path
    file =CreateFile(strDestPath, GENERIC_READ, FILE_SHARE_READ,NULL,
        OPEN_EXISTING,0,NULL);if(INVALID_HANDLE_VALUE != file){CloseHandle(file);return S_OK;}// next try to find the filename in the current working directory (path stripped)
    file =CreateFile(strShortName, GENERIC_READ, FILE_SHARE_READ,NULL,
        OPEN_EXISTING,0,NULL);if(INVALID_HANDLE_VALUE != file){_tcsncpy_s(strDestPath, cchDest, strShortName, cchDest);
        strDestPath[cchDest -1]=0;// _tcsncpy doesn't NULL term if it runs out of spaceCloseHandle(file);return S_OK;}// last, check if the file exists in the media directoryif(FAILED(hr =DXUtil_GetDXSDKMediaPathCch(strDestPath, cchDest)))return hr;if(lstrlen(strDestPath)+lstrlen(strShortName)< cchDest)lstrcat(strDestPath, strShortName);elsereturn E_INVALIDARG;
    file =CreateFile(strDestPath, GENERIC_READ, FILE_SHARE_READ,NULL,
        OPEN_EXISTING,0,NULL);if(INVALID_HANDLE_VALUE != file){CloseHandle(file);return S_OK;}// On failure, just return the file as the path_tcsncpy_s(strDestPath, cchDest, strFilename, cchDest);
    strDestPath[cchDest -1]=0;// _tcsncpy doesn't NULL term if it runs out of spacereturnHRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);}#endif// !UNDER_CE//-----------------------------------------------------------------------------// Name: DXUtil_ReadStringRegKeyCch()// Desc: Helper function to read a registry key string//       cchDest is the size in TCHARs of strDest.  Be careful not to //       pass in sizeof(strDest) on UNICODE builds.//-----------------------------------------------------------------------------
HRESULT DXUtil_ReadStringRegKeyCch(HKEY hKey, TCHAR* strRegName, TCHAR* strDest,
    DWORD cchDest, TCHAR* strDefault){
    DWORD dwType;
    DWORD cbDest = cchDest *sizeof(TCHAR);if(ERROR_SUCCESS !=RegQueryValueEx(hKey, strRegName,0,&dwType,(BYTE*)strDest,&cbDest)){_tcsncpy_s(strDest, cchDest, strDefault, cchDest);
        strDest[cchDest -1]=0;if(dwType != REG_SZ)return E_FAIL;return S_OK;}return E_FAIL;}//-----------------------------------------------------------------------------// Name: DXUtil_WriteStringRegKey()// Desc: Helper function to write a registry key string//-----------------------------------------------------------------------------
HRESULT DXUtil_WriteStringRegKey(HKEY hKey, TCHAR* strRegName,
    TCHAR* strValue){if(NULL== strValue)return E_INVALIDARG;
    DWORD cbValue =((DWORD)_tcslen(strValue)+1)*sizeof(TCHAR);if(ERROR_SUCCESS !=RegSetValueEx(hKey, strRegName,0, REG_SZ,(BYTE*)strValue, cbValue))return E_FAIL;return S_OK;}//-----------------------------------------------------------------------------// Name: DXUtil_ReadIntRegKey()// Desc: Helper function to read a registry key int//-----------------------------------------------------------------------------
HRESULT DXUtil_ReadIntRegKey(HKEY hKey, TCHAR* strRegName, DWORD* pdwDest,
    DWORD dwDefault){
    DWORD dwType;
    DWORD dwLength =sizeof(DWORD);if(ERROR_SUCCESS !=RegQueryValueEx(hKey, strRegName,0,&dwType,(BYTE*)pdwDest,&dwLength)){*pdwDest = dwDefault;if(dwType != REG_DWORD)return E_FAIL;return S_OK;}return E_FAIL;}//-----------------------------------------------------------------------------// Name: DXUtil_WriteIntRegKey()// Desc: Helper function to write a registry key int//-----------------------------------------------------------------------------
HRESULT DXUtil_WriteIntRegKey(HKEY hKey, TCHAR* strRegName, DWORD dwValue){if(ERROR_SUCCESS !=RegSetValueEx(hKey, strRegName,0, REG_DWORD,(BYTE*)&dwValue,sizeof(DWORD)))return E_FAIL;return S_OK;}//-----------------------------------------------------------------------------// Name: DXUtil_ReadBoolRegKey()// Desc: Helper function to read a registry key BOOL//-----------------------------------------------------------------------------
HRESULT DXUtil_ReadBoolRegKey(HKEY hKey, TCHAR* strRegName, BOOL* pbDest,
    BOOL bDefault){
    DWORD dwType;
    DWORD dwLength =sizeof(BOOL);if(ERROR_SUCCESS !=RegQueryValueEx(hKey, strRegName,0,&dwType,(BYTE*)pbDest,&dwLength)){*pbDest = bDefault;if(dwType != REG_DWORD)return E_FAIL;return S_OK;}return E_FAIL;}//-----------------------------------------------------------------------------// Name: DXUtil_WriteBoolRegKey()// Desc: Helper function to write a registry key BOOL//-----------------------------------------------------------------------------
HRESULT DXUtil_WriteBoolRegKey(HKEY hKey, TCHAR* strRegName, BOOL bValue){if(ERROR_SUCCESS !=RegSetValueEx(hKey, strRegName,0, REG_DWORD,(BYTE*)&bValue,sizeof(BOOL)))return E_FAIL;return S_OK;}//-----------------------------------------------------------------------------// Name: DXUtil_ReadGuidRegKey()// Desc: Helper function to read a registry key guid//-----------------------------------------------------------------------------
HRESULT DXUtil_ReadGuidRegKey(HKEY hKey, TCHAR* strRegName, GUID* pGuidDest,
    GUID& guidDefault){
    DWORD dwType;
    DWORD dwLength =sizeof(GUID);if(ERROR_SUCCESS !=RegQueryValueEx(hKey, strRegName,0,&dwType,(LPBYTE)pGuidDest,&dwLength)){*pGuidDest = guidDefault;if(dwType != REG_BINARY)return E_FAIL;return S_OK;}return E_FAIL;}//-----------------------------------------------------------------------------// Name: DXUtil_WriteGuidRegKey()// Desc: Helper function to write a registry key guid//-----------------------------------------------------------------------------
HRESULT DXUtil_WriteGuidRegKey(HKEY hKey, TCHAR* strRegName, GUID guidValue){if(ERROR_SUCCESS !=RegSetValueEx(hKey, strRegName,0, REG_BINARY,(BYTE*)&guidValue,sizeof(GUID)))return E_FAIL;return S_OK;}//-----------------------------------------------------------------------------// Name: DXUtil_Timer()// Desc: Performs timer opertations. Use the following commands://          TIMER_RESET           - to reset the timer//          TIMER_START           - to start the timer//          TIMER_STOP            - to stop (or pause) the timer//          TIMER_ADVANCE         - to advance the timer by 0.1 seconds//          TIMER_GETABSOLUTETIME - to get the absolute system time//          TIMER_GETAPPTIME      - to get the current time//          TIMER_GETELAPSEDTIME  - to get the time that elapsed between //                                  TIMER_GETELAPSEDTIME calls//-----------------------------------------------------------------------------
FLOAT __stdcall DXUtil_Timer(TIMER_COMMAND command){static BOOL     m_bTimerInitialized = FALSE;static BOOL     m_bUsingQPF = FALSE;static BOOL     m_bTimerStopped = TRUE;static LONGLONG m_llQPFTicksPerSec =0;// Initialize the timerif(FALSE == m_bTimerInitialized){
        m_bTimerInitialized = TRUE;// Use QueryPerformanceFrequency() to get frequency of timer.  If QPF is// not supported, we will timeGetTime() which returns milliseconds.
        LARGE_INTEGER qwTicksPerSec;
        m_bUsingQPF =QueryPerformanceFrequency(&qwTicksPerSec);if(m_bUsingQPF)
            m_llQPFTicksPerSec = qwTicksPerSec.QuadPart;}if(m_bUsingQPF){static LONGLONG m_llStopTime =0;static LONGLONG m_llLastElapsedTime =0;static LONGLONG m_llBaseTime =0;double fTime;double fElapsedTime;
        LARGE_INTEGER qwTime;// Get either the current time or the stop time, depending// on whether we're stopped and what command was sentif(m_llStopTime !=0&& command != TIMER_START && command != TIMER_GETABSOLUTETIME)
            qwTime.QuadPart = m_llStopTime;elseQueryPerformanceCounter(&qwTime);// Return the elapsed timeif(command == TIMER_GETELAPSEDTIME){
            fElapsedTime =(double)(qwTime.QuadPart - m_llLastElapsedTime)/(double)m_llQPFTicksPerSec;
            m_llLastElapsedTime = qwTime.QuadPart;return(FLOAT)fElapsedTime;}// Return the current timeif(command == TIMER_GETAPPTIME){double fAppTime =(double)(qwTime.QuadPart - m_llBaseTime)/(double)m_llQPFTicksPerSec;return(FLOAT)fAppTime;}// Reset the timerif(command == TIMER_RESET){
            m_llBaseTime = qwTime.QuadPart;
            m_llLastElapsedTime = qwTime.QuadPart;
            m_llStopTime =0;
            m_bTimerStopped = FALSE;return0.0f;}// Start the timerif(command == TIMER_START){if(m_bTimerStopped)
                m_llBaseTime += qwTime.QuadPart - m_llStopTime;
            m_llStopTime =0;
            m_llLastElapsedTime = qwTime.QuadPart;
            m_bTimerStopped = FALSE;return0.0f;}// Stop the timerif(command == TIMER_STOP){if(!m_bTimerStopped){
                m_llStopTime = qwTime.QuadPart;
                m_llLastElapsedTime = qwTime.QuadPart;
                m_bTimerStopped = TRUE;}return0.0f;}// Advance the timer by 1/10th secondif(command == TIMER_ADVANCE){
            m_llStopTime += m_llQPFTicksPerSec /10;return0.0f;}if(command == TIMER_GETABSOLUTETIME){
            fTime = qwTime.QuadPart /(double)m_llQPFTicksPerSec;return(FLOAT)fTime;}return-1.0f;// Invalid command specified}else{// Get the time using timeGetTime()staticdouble m_fLastElapsedTime =0.0;staticdouble m_fBaseTime =0.0;staticdouble m_fStopTime =0.0;double fTime;double fElapsedTime;// Get either the current time or the stop time, depending// on whether we're stopped and what command was sentif(m_fStopTime !=0.0&& command != TIMER_START && command != TIMER_GETABSOLUTETIME)
            fTime = m_fStopTime;else
            fTime =GETTIMESTAMP()*0.001;// Return the elapsed timeif(command == TIMER_GETELAPSEDTIME){
            fElapsedTime =(double)(fTime - m_fLastElapsedTime);
            m_fLastElapsedTime = fTime;return(FLOAT)fElapsedTime;}// Return the current timeif(command == TIMER_GETAPPTIME){return(FLOAT)(fTime - m_fBaseTime);}// Reset the timerif(command == TIMER_RESET){
            m_fBaseTime = fTime;
            m_fLastElapsedTime = fTime;
            m_fStopTime =0;
            m_bTimerStopped = FALSE;return0.0f;}// Start the timerif(command == TIMER_START){if(m_bTimerStopped)
                m_fBaseTime += fTime - m_fStopTime;
            m_fStopTime =0.0f;
            m_fLastElapsedTime = fTime;
            m_bTimerStopped = FALSE;return0.0f;}// Stop the timerif(command == TIMER_STOP){if(!m_bTimerStopped){
                m_fStopTime = fTime;
                m_fLastElapsedTime = fTime;
                m_bTimerStopped = TRUE;}return0.0f;}// Advance the timer by 1/10th secondif(command == TIMER_ADVANCE){
            m_fStopTime +=0.1f;return0.0f;}if(command == TIMER_GETABSOLUTETIME){return(FLOAT)fTime;}return-1.0f;// Invalid command specified}}//-----------------------------------------------------------------------------// Name: DXUtil_ConvertAnsiStringToWideCch()// Desc: This is a UNICODE conversion utility to convert a CHAR string into a//       WCHAR string. //       cchDestChar is the size in TCHARs of wstrDestination.  Be careful not to //       pass in sizeof(strDest) //-----------------------------------------------------------------------------
HRESULT DXUtil_ConvertAnsiStringToWideCch(WCHAR* wstrDestination,const CHAR* strSource,int cchDestChar){if(wstrDestination ==NULL|| strSource ==NULL|| cchDestChar <1)return E_INVALIDARG;int nResult =MultiByteToWideChar(CP_ACP,0, strSource,-1,
        wstrDestination, cchDestChar);
    wstrDestination[cchDestChar -1]=0;if(nResult ==0)return E_FAIL;return S_OK;}//-----------------------------------------------------------------------------// Name: DXUtil_ConvertWideStringToAnsi()// Desc: This is a UNICODE conversion utility to convert a WCHAR string into a//       CHAR string. //       cchDestChar is the size in TCHARs of strDestination//-----------------------------------------------------------------------------
HRESULT DXUtil_ConvertWideStringToAnsiCch(CHAR* strDestination,const WCHAR* wstrSource,int cchDestChar){if(strDestination ==NULL|| wstrSource ==NULL|| cchDestChar <1)return E_INVALIDARG;int nResult =WideCharToMultiByte(CP_ACP,0, wstrSource,-1, strDestination,
        cchDestChar *sizeof(CHAR),NULL,NULL);
    strDestination[cchDestChar -1]=0;if(nResult ==0)return E_FAIL;return S_OK;}//-----------------------------------------------------------------------------// Name: DXUtil_ConvertGenericStringToAnsi()// Desc: This is a UNICODE conversion utility to convert a TCHAR string into a//       CHAR string. //       cchDestChar is the size in TCHARs of strDestination//-----------------------------------------------------------------------------
HRESULT DXUtil_ConvertGenericStringToAnsiCch(CHAR* strDestination,const TCHAR* tstrSource,int cchDestChar){if(strDestination ==NULL|| tstrSource ==NULL|| cchDestChar <1)return E_INVALIDARG;#ifdef_UNICODEreturnDXUtil_ConvertWideStringToAnsiCch(strDestination, tstrSource, cchDestChar);#elsestrncpy_s(strDestination, cchDestChar, tstrSource, cchDestChar);
    strDestination[cchDestChar -1]='\0';return S_OK;#endif}//-----------------------------------------------------------------------------// Name: DXUtil_ConvertGenericStringToWide()// Desc: This is a UNICODE conversion utility to convert a TCHAR string into a//       WCHAR string. //       cchDestChar is the size in TCHARs of wstrDestination.  Be careful not to //       pass in sizeof(strDest) //-----------------------------------------------------------------------------
HRESULT DXUtil_ConvertGenericStringToWideCch(WCHAR* wstrDestination,const TCHAR* tstrSource,int cchDestChar){if(wstrDestination ==NULL|| tstrSource ==NULL|| cchDestChar <1)return E_INVALIDARG;#ifdef_UNICODEwcsncpy(wstrDestination, tstrSource, cchDestChar);
    wstrDestination[cchDestChar -1]= L'\0';return S_OK;#elsereturnDXUtil_ConvertAnsiStringToWideCch(wstrDestination, tstrSource, cchDestChar);#endif}//-----------------------------------------------------------------------------// Name: DXUtil_ConvertAnsiStringToGeneric()// Desc: This is a UNICODE conversion utility to convert a CHAR string into a//       TCHAR string. //       cchDestChar is the size in TCHARs of tstrDestination.  Be careful not to //       pass in sizeof(strDest) on UNICODE builds//-----------------------------------------------------------------------------
HRESULT DXUtil_ConvertAnsiStringToGenericCch(TCHAR* tstrDestination,const CHAR* strSource,int cchDestChar){if(tstrDestination ==NULL|| strSource ==NULL|| cchDestChar <1)return E_INVALIDARG;#ifdef_UNICODEreturnDXUtil_ConvertAnsiStringToWideCch(tstrDestination, strSource, cchDestChar);#elsestrncpy_s(tstrDestination, cchDestChar, strSource, cchDestChar);
    tstrDestination[cchDestChar -1]='\0';return S_OK;#endif}//-----------------------------------------------------------------------------// Name: DXUtil_ConvertAnsiStringToGeneric()// Desc: This is a UNICODE conversion utility to convert a WCHAR string into a//       TCHAR string. //       cchDestChar is the size in TCHARs of tstrDestination.  Be careful not to //       pass in sizeof(strDest) on UNICODE builds//-----------------------------------------------------------------------------
HRESULT DXUtil_ConvertWideStringToGenericCch(TCHAR* tstrDestination,const WCHAR* wstrSource,int cchDestChar){if(tstrDestination ==NULL|| wstrSource ==NULL|| cchDestChar <1)return E_INVALIDARG;#ifdef_UNICODEwcsncpy(tstrDestination, wstrSource, cchDestChar);
    tstrDestination[cchDestChar -1]= L'\0';return S_OK;#elsereturnDXUtil_ConvertWideStringToAnsiCch(tstrDestination, wstrSource, cchDestChar);#endif}//-----------------------------------------------------------------------------// Name: DXUtil_LaunchReadme()// Desc: Finds and opens the readme.txt for this sample//-----------------------------------------------------------------------------
VOID DXUtil_LaunchReadme(HWND hWnd, TCHAR* strLoc){#ifdefUNDER_CE// This is not available on PocketPCMessageBox(hWnd,TEXT("For operating instructions, please open the ")TEXT("readme.txt file included with the project."),TEXT("DirectX SDK Sample"), MB_ICONWARNING | MB_OK);return;#elsebool bSuccess =false;bool bFound =false;
    TCHAR strReadmePath[1024];
    TCHAR strExeName[MAX_PATH];
    TCHAR strExePath[MAX_PATH];
    TCHAR strSamplePath[MAX_PATH];
    TCHAR* strLastSlash =NULL;lstrcpy(strReadmePath,TEXT(""));lstrcpy(strExePath,TEXT(""));lstrcpy(strExeName,TEXT(""));lstrcpy(strSamplePath,TEXT(""));// If the user provided a location for the readme, check there first.if(strLoc){
        HKEY  hKey;
        LONG lResult =RegOpenKeyEx(HKEY_LOCAL_MACHINE,_T("Software\\Microsoft\\DirectX SDK"),0, KEY_READ,&hKey);if(ERROR_SUCCESS == lResult){
            DWORD dwType;
            DWORD dwSize = MAX_PATH *sizeof(TCHAR);
            lResult =RegQueryValueEx(hKey,_T("DX9SDK Samples Path"),NULL,&dwType,(BYTE*)strSamplePath,&dwSize);
            strSamplePath[MAX_PATH -1]=0;// RegQueryValueEx doesn't NULL term if buffer too smallif(ERROR_SUCCESS == lResult){_sntprintf_s(strReadmePath,1023,TEXT("%s\\C++\\%s\\readme.txt"),
                    strSamplePath, strLoc);
                strReadmePath[1023]=0;if(GetFileAttributes(strReadmePath)!=0xFFFFFFFF)
                    bFound = TRUE;}}RegCloseKey(hKey);}// Get the exe name, and exe pathGetModuleFileName(NULL, strExePath, MAX_PATH);
    strExePath[MAX_PATH -1]=0;
    strLastSlash =_tcsrchr(strExePath,TEXT('\\'));if(strLastSlash){_tcsncpy_s(strExeName,&strLastSlash[1], MAX_PATH);
        strExeName[MAX_PATH -1]=0;// Chop the exe name from the exe path*strLastSlash =0;// Chop the .exe from the exe name
        strLastSlash =_tcsrchr(strExeName,TEXT('.'));if(strLastSlash)*strLastSlash =0;}if(!bFound){// Search in "%EXE_DIR%\..\%EXE_NAME%".  This matchs the DirectX SDK layout_tcscpy_s(strReadmePath, strExePath);
        strLastSlash =_tcsrchr(strReadmePath,TEXT('\\'));if(strLastSlash)*strLastSlash =0;lstrcat(strReadmePath,TEXT("\\"));lstrcat(strReadmePath, strExeName);lstrcat(strReadmePath,TEXT("\\readme.txt"));if(GetFileAttributes(strReadmePath)!=0xFFFFFFFF)
            bFound = TRUE;}if(!bFound){// Search in "%EXE_DIR%\"_tcscpy_s(strReadmePath, strExePath);lstrcat(strReadmePath,TEXT("\\readme.txt"));if(GetFileAttributes(strReadmePath)!=0xFFFFFFFF)
            bFound = TRUE;}if(!bFound){// Search in "%EXE_DIR%\.."_tcscpy_s(strReadmePath, strExePath);
        strLastSlash =_tcsrchr(strReadmePath,TEXT('\\'));if(strLastSlash)*strLastSlash =0;lstrcat(strReadmePath,TEXT("\\readme.txt"));if(GetFileAttributes(strReadmePath)!=0xFFFFFFFF)
            bFound = TRUE;}if(!bFound){// Search in "%EXE_DIR%\..\.."_tcscpy_s(strReadmePath, strExePath);
        strLastSlash =_tcsrchr(strReadmePath,TEXT('\\'));if(strLastSlash)*strLastSlash =0;
        strLastSlash =_tcsrchr(strReadmePath,TEXT('\\'));if(strLastSlash)*strLastSlash =0;lstrcat(strReadmePath,TEXT("\\readme.txt"));if(GetFileAttributes(strReadmePath)!=0xFFFFFFFF)
            bFound = TRUE;}if(bFound){// GetProcAddress for ShellExecute, so we don't have to include shell32.lib // in every project that uses dxutil.cpp
        LPShellExecute pShellExecute =NULL;
        HINSTANCE hInstShell32 =LoadLibrary(TEXT("shell32.dll"));if(hInstShell32 !=NULL){#ifdefUNICODE
            pShellExecute =(LPShellExecute)GetProcAddress(hInstShell32,_TWINCE("ShellExecuteW"));#else
            pShellExecute =(LPShellExecute)GetProcAddress(hInstShell32,_TWINCE("ShellExecuteA"));#endifif(pShellExecute !=NULL){if(pShellExecute(hWnd,TEXT("open"), strReadmePath,NULL,NULL, SW_SHOW)>(HINSTANCE)32)
                    bSuccess =true;}FreeLibrary(hInstShell32);}}if(!bSuccess){// Tell the user that the readme couldn't be openedMessageBox(hWnd,TEXT("Could not find readme.txt"),TEXT("DirectX SDK Sample"), MB_ICONWARNING | MB_OK);}#endif// UNDER_CE}//-----------------------------------------------------------------------------// Name: DXUtil_Trace()// Desc: Outputs to the debug stream a formatted string with a variable-//       argument list.//-----------------------------------------------------------------------------
VOID DXUtil_Trace(TCHAR* strMsg,...){#ifdefined(DEBUG)|defined(_DEBUG)
    TCHAR strBuffer[512];
    va_list args;va_start(args, strMsg);_vsntprintf_s(strBuffer,512, strMsg, args);va_end(args);OutputDebugString(strBuffer);#elseUNREFERENCED_PARAMETER(strMsg);#endif}//-----------------------------------------------------------------------------// Name: DXUtil_ConvertStringToGUID()// Desc: Converts a string to a GUID//-----------------------------------------------------------------------------
HRESULT DXUtil_ConvertStringToGUID(const TCHAR* strSrc, GUID* pGuidDest){
    UINT aiTmp[10];if(_stscanf_s(strSrc,TEXT("{%8X-%4X-%4X-%2X%2X-%2X%2X%2X%2X%2X%2X}"),&pGuidDest->Data1,&aiTmp[0],&aiTmp[1],&aiTmp[2],&aiTmp[3],&aiTmp[4],&aiTmp[5],&aiTmp[6],&aiTmp[7],&aiTmp[8],&aiTmp[9])!=11){ZeroMemory(pGuidDest,sizeof(GUID));return E_FAIL;}else{
        pGuidDest->Data2 =(USHORT)aiTmp[0];
        pGuidDest->Data3 =(USHORT)aiTmp[1];
        pGuidDest->Data4[0]=(BYTE)aiTmp[2];
        pGuidDest->Data4[1]=(BYTE)aiTmp[3];
        pGuidDest->Data4[2]=(BYTE)aiTmp[4];
        pGuidDest->Data4[3]=(BYTE)aiTmp[5];
        pGuidDest->Data4[4]=(BYTE)aiTmp[6];
        pGuidDest->Data4[5]=(BYTE)aiTmp[7];
        pGuidDest->Data4[6]=(BYTE)aiTmp[8];
        pGuidDest->Data4[7]=(BYTE)aiTmp[9];return S_OK;}}//-----------------------------------------------------------------------------// Name: DXUtil_ConvertGUIDToStringCch()// Desc: Converts a GUID to a string //       cchDestChar is the size in TCHARs of strDest.  Be careful not to //       pass in sizeof(strDest) on UNICODE builds//-----------------------------------------------------------------------------
HRESULT DXUtil_ConvertGUIDToStringCch(const GUID* pGuidSrc, TCHAR* strDest,int cchDestChar){int nResult =_sntprintf_s(strDest, cchDestChar, cchDestChar,TEXT("{%0.8X-%0.4X-%0.4X-%0.2X%0.2X-%0.2X%0.2X%0.2X%0.2X%0.2X%0.2X}"),
        pGuidSrc->Data1, pGuidSrc->Data2, pGuidSrc->Data3,
        pGuidSrc->Data4[0], pGuidSrc->Data4[1],
        pGuidSrc->Data4[2], pGuidSrc->Data4[3],
        pGuidSrc->Data4[4], pGuidSrc->Data4[5],
        pGuidSrc->Data4[6], pGuidSrc->Data4[7]);if(nResult <0)return E_FAIL;return S_OK;}//-----------------------------------------------------------------------------// Name: CArrayList constructor// Desc: //-----------------------------------------------------------------------------CArrayList::CArrayList(ArrayListType Type, UINT BytesPerEntry){if(Type == AL_REFERENCE)
        BytesPerEntry =sizeof(void*);
    m_ArrayListType = Type;
    m_pData =NULL;
    m_BytesPerEntry = BytesPerEntry;
    m_NumEntries =0;
    m_NumEntriesAllocated =0;}//-----------------------------------------------------------------------------// Name: CArrayList destructor// Desc: //-----------------------------------------------------------------------------CArrayList::~CArrayList(void){if(m_pData !=NULL)delete[] m_pData;}//-----------------------------------------------------------------------------// Name: CArrayList::Add// Desc: Adds pEntry to the list.//-----------------------------------------------------------------------------
HRESULT CArrayList::Add(void* pEntry){if(m_BytesPerEntry ==0)return E_FAIL;if(m_pData ==NULL|| m_NumEntries +1> m_NumEntriesAllocated){void* pDataNew;
        UINT NumEntriesAllocatedNew;if(m_NumEntriesAllocated ==0)
            NumEntriesAllocatedNew =16;else
            NumEntriesAllocatedNew = m_NumEntriesAllocated *2;
        pDataNew =new BYTE[NumEntriesAllocatedNew * m_BytesPerEntry];if(pDataNew ==NULL)return E_OUTOFMEMORY;if(m_pData !=NULL){CopyMemory(pDataNew, m_pData, m_NumEntries * m_BytesPerEntry);delete[] m_pData;}
        m_pData = pDataNew;
        m_NumEntriesAllocated = NumEntriesAllocatedNew;}if(m_ArrayListType == AL_VALUE)CopyMemory((BYTE*)m_pData +(m_NumEntries * m_BytesPerEntry), pEntry, m_BytesPerEntry);else*(((void**)m_pData)+ m_NumEntries)= pEntry;
    m_NumEntries++;return S_OK;}//-----------------------------------------------------------------------------// Name: CArrayList::Remove// Desc: Remove the item at Entry in the list, and collapse the array. //-----------------------------------------------------------------------------voidCArrayList::Remove(UINT Entry){// Decrement count
    m_NumEntries--;// Find the entry address
    BYTE* pData =(BYTE*)m_pData +(Entry * m_BytesPerEntry);// Collapse the arrayMoveMemory(pData, pData + m_BytesPerEntry,(m_NumEntries - Entry)* m_BytesPerEntry);}//-----------------------------------------------------------------------------// Name: CArrayList::GetPtr// Desc: Returns a pointer to the Entry'th entry in the list.//-----------------------------------------------------------------------------void*CArrayList::GetPtr(UINT Entry){if(m_ArrayListType == AL_VALUE)return(BYTE*)m_pData +(Entry * m_BytesPerEntry);elsereturn*(((void**)m_pData)+ Entry);}//-----------------------------------------------------------------------------// Name: CArrayList::Contains// Desc: Returns whether the list contains an entry identical to the //       specified entry data.//-----------------------------------------------------------------------------boolCArrayList::Contains(void* pEntryData){for(UINT iEntry =0; iEntry < m_NumEntries; iEntry++){if(m_ArrayListType == AL_VALUE){if(memcmp(GetPtr(iEntry), pEntryData, m_BytesPerEntry)==0)returntrue;}else{if(GetPtr(iEntry)== pEntryData)returntrue;}}returnfalse;}//-----------------------------------------------------------------------------// Name: BYTE helper functions// Desc: cchDestChar is the size in BYTEs of strDest.  Be careful not to //       pass use sizeof() if the strDest is a string pointer.  //       eg.//       TCHAR* sz = new TCHAR[100]; // sizeof(sz)  == 4//       TCHAR sz2[100];             // sizeof(sz2) == 200//-----------------------------------------------------------------------------
HRESULT DXUtil_ConvertAnsiStringToWideCb(WCHAR* wstrDestination,const CHAR* strSource,int cbDestChar){returnDXUtil_ConvertAnsiStringToWideCch(wstrDestination, strSource, cbDestChar /sizeof(WCHAR));}
HRESULT DXUtil_ConvertWideStringToAnsiCb(CHAR* strDestination,const WCHAR* wstrSource,int cbDestChar){returnDXUtil_ConvertWideStringToAnsiCch(strDestination, wstrSource, cbDestChar /sizeof(CHAR));}
HRESULT DXUtil_ConvertGenericStringToAnsiCb(CHAR* strDestination,const TCHAR* tstrSource,int cbDestChar){returnDXUtil_ConvertGenericStringToAnsiCch(strDestination, tstrSource, cbDestChar /sizeof(CHAR));}
HRESULT DXUtil_ConvertGenericStringToWideCb(WCHAR* wstrDestination,const TCHAR* tstrSource,int cbDestChar){returnDXUtil_ConvertGenericStringToWideCch(wstrDestination, tstrSource, cbDestChar /sizeof(WCHAR));}
HRESULT DXUtil_ConvertAnsiStringToGenericCb(TCHAR* tstrDestination,const CHAR* strSource,int cbDestChar){returnDXUtil_ConvertAnsiStringToGenericCch(tstrDestination, strSource, cbDestChar /sizeof(TCHAR));}
HRESULT DXUtil_ConvertWideStringToGenericCb(TCHAR* tstrDestination,const WCHAR* wstrSource,int cbDestChar){returnDXUtil_ConvertWideStringToGenericCch(tstrDestination, wstrSource, cbDestChar /sizeof(TCHAR));}
HRESULT DXUtil_ReadStringRegKeyCb(HKEY hKey, TCHAR* strRegName, TCHAR* strDest, DWORD cbDest, TCHAR* strDefault){returnDXUtil_ReadStringRegKeyCch(hKey, strRegName, strDest, cbDest /sizeof(TCHAR), strDefault);}
HRESULT DXUtil_ConvertGUIDToStringCb(const GUID* pGuidSrc, TCHAR* strDest,int cbDestChar){returnDXUtil_ConvertGUIDToStringCch(pGuidSrc, strDest, cbDestChar /sizeof(TCHAR));}#ifndefUNDER_CE
HRESULT DXUtil_GetDXSDKMediaPathCb(TCHAR* szDest,int cbDest){returnDXUtil_GetDXSDKMediaPathCch(szDest, cbDest /sizeof(TCHAR));}
HRESULT DXUtil_FindMediaFileCb(TCHAR* szDestPath,int cbDest, TCHAR* strFilename){returnDXUtil_FindMediaFileCch(szDestPath, cbDest /sizeof(TCHAR), strFilename);}#endif// !UNDER_CE

fps.h

#pragmaonce#include"d3dfont.h"#include<sstream>classFPSCounter{public:FPSCounter(IDirect3DDevice9* device);~FPSCounter();boolrender(D3DCOLOR color,float timeDelta);private:
	IDirect3DDevice9* _device;
	CD3DFont* _font;
	DWORD     _frameCnt;float     _timeElapsed;float     _fps;char      _fpsString[9];};

fps.cpp

#include"fps.h"#include<cstdio>FPSCounter::FPSCounter(IDirect3DDevice9* device){
	_device = device;
	_font =newCD3DFont("Times New Roman",24,0);
	_font->InitDeviceObjects(_device);
	_font->RestoreDeviceObjects();
	_frameCnt =0;
	_timeElapsed =0.0f;
	_fps =0.0f;}FPSCounter::~FPSCounter(){if(_font){
		_font->InvalidateDeviceObjects();
		_font->DeleteDeviceObjects();delete _font;}}boolFPSCounter::render(D3DCOLOR color,float timeDelta){if(_font){
		_frameCnt++;
		_timeElapsed += timeDelta;if(_timeElapsed >=1.0f){
			_fps =(float)_frameCnt / _timeElapsed;
			std::stringstream ss;//std::string fpsStr;
			ss << _fps;
			ss >> _fpsString;//strncpy_s(_fpsString, 9, fpsStr.c_str(), 9);//sprintf_s(_fpsString, 8, "%f", _fps);
			_fpsString[8]='\0';// mark end of string
			_timeElapsed =0.0f;
			_frameCnt =0;}
		_font->DrawText(20,20, color, _fpsString);}returntrue;}

terrain.h

#pragmaonce#include"d3dUtility.h"#include<string>#include<vector>classTerrain{public:Terrain(
		IDirect3DDevice9* device,
		std::string heightmapFileName,int numVertsPerRow,int numVertsPerCol,int cellSpacing,// space between cellsfloat heightScale);~Terrain();intgetHeightmapEntry(int row,int col);voidsetHeightmapEntry(int row,int col,int value);floatgetHeight(float x,float z);boolloadTexture(std::string fileName);boolgenTexture(D3DXVECTOR3* directionToLight);booldraw(D3DXMATRIX* world,bool drawTris);private:
	IDirect3DDevice9* _device;
	IDirect3DTexture9* _tex;
	IDirect3DVertexBuffer9* _vb;
	IDirect3DIndexBuffer9* _ib;int _numVertsPerRow;int _numVertsPerCol;int _cellSpacing;int _numCellsPerRow;int _numCellsPerCol;int _width;int _depth;int _numVertices;int _numTriangles;float _heightScale;
	std::vector<int> _heightmap;// helper methodsboolreadRawFile(std::string fileName);boolcomputeVertices();boolcomputeIndices();boollightTerrain(D3DXVECTOR3* directionToLight);floatcomputeShade(int cellRow,int cellCol, D3DXVECTOR3* directionToLight);structTerrainVertex{TerrainVertex(){}TerrainVertex(float x,float y,float z,float u,float v){
			_x = x; _y = y; _z = z; _u = u; _v = v;}float _x, _y, _z;float _u, _v;staticconst DWORD FVF;};};

terrain.cpp

#include"terrain.h"#include<fstream>#include<cmath>const DWORD Terrain::TerrainVertex::FVF = D3DFVF_XYZ | D3DFVF_TEX1;Terrain::Terrain(IDirect3DDevice9* device,
	std::string heightmapFileName,int numVertsPerRow,int numVertsPerCol,int cellSpacing,float heightScale){
	_device = device;
	_numVertsPerRow = numVertsPerRow;
	_numVertsPerCol = numVertsPerCol;
	_cellSpacing = cellSpacing;
	_numCellsPerRow = _numVertsPerRow -1;
	_numCellsPerCol = _numVertsPerCol -1;
	_width = _numCellsPerRow * _cellSpacing;
	_depth = _numCellsPerCol * _cellSpacing;
	_numVertices = _numVertsPerRow * _numVertsPerCol;
	_numTriangles = _numCellsPerRow * _numCellsPerCol *2;
	_heightScale = heightScale;// load heightmapif(!readRawFile(heightmapFileName)){::MessageBox(0,"readRawFile - FAILED",0,0);::PostQuitMessage(0);}// scale heightsfor(int i =0; i < _heightmap.size(); i++)
		_heightmap[i]*= heightScale;// compute the verticesif(!computeVertices()){::MessageBox(0,"computeVertices - FAILED",0,0);::PostQuitMessage(0);}// compute the indicesif(!computeIndices()){::MessageBox(0,"computeIndices - FAILED",0,0);::PostQuitMessage(0);}}Terrain::~Terrain(){
	d3d::Release<IDirect3DVertexBuffer9*>(_vb);
	d3d::Release<IDirect3DIndexBuffer9*>(_ib);
	d3d::Release<IDirect3DTexture9*>(_tex);}intTerrain::getHeightmapEntry(int row,int col){return _heightmap[row * _numVertsPerRow + col];}voidTerrain::setHeightmapEntry(int row,int col,int value){
	_heightmap[row * _numVertsPerRow + col]= value;}boolTerrain::computeVertices(){
	HRESULT hr =0;
	hr = _device->CreateVertexBuffer(
		_numVertices *sizeof(TerrainVertex),
		D3DUSAGE_WRITEONLY,
		TerrainVertex::FVF,
		D3DPOOL_MANAGED,&_vb,0);if(FAILED(hr))returnfalse;// coordinates to start generating vertices atint startX =-_width /2;int startZ = _depth /2;// coordinates to end generating vertices atint endX = _width /2;int endZ =-_depth /2;// compute the increment size of the texture coordinates// from one vertex to the next.float uCoordIncrementSize =1.0f/(float)_numCellsPerRow;float vCoordIncrementSize =1.0f/(float)_numCellsPerCol;
	TerrainVertex* v =0;
	_vb->Lock(0,0,(void**)&v,0);int i =0;for(int z = startZ; z >= endZ; z -= _cellSpacing){int j =0;for(int x = startX; x <= endX; x += _cellSpacing){// compute the correct index into the vertex buffer and heightmap// based on where we are in the nested loop.int index = i * _numVertsPerRow + j;
			v[index]=TerrainVertex((float)x,(float)_heightmap[index],(float)z,(float)j * uCoordIncrementSize,(float)i * vCoordIncrementSize);
			j++;// next column}
		i++;// next row}
	_vb->Unlock();returntrue;}boolTerrain::computeIndices(){
	HRESULT hr =0;
	hr = _device->CreateIndexBuffer(
		_numTriangles *3*sizeof(WORD),// 3 indices per triangle
		D3DUSAGE_WRITEONLY,
		D3DFMT_INDEX16,
		D3DPOOL_MANAGED,&_ib,0);if(FAILED(hr))returnfalse;
	WORD* indices =0;
	_ib->Lock(0,0,(void**)&indices,0);// index to start of a group of 6 indices that describe the// two triangles that make up a quadint baseIndex =0;// loop through and compute the triangles of each quadfor(int i =0; i < _numCellsPerCol; i++){for(int j =0; j < _numCellsPerRow; j++){
			indices[baseIndex]= i * _numVertsPerRow + j;
			indices[baseIndex +1]= i * _numVertsPerRow + j +1;
			indices[baseIndex +2]=(i +1)* _numVertsPerRow + j;
			indices[baseIndex +3]=(i +1)* _numVertsPerRow + j;
			indices[baseIndex +4]= i * _numVertsPerRow + j +1;
			indices[baseIndex +5]=(i +1)* _numVertsPerRow + j +1;// next quad
			baseIndex +=6;}}
	_ib->Unlock();returntrue;}boolTerrain::loadTexture(std::string fileName){
	HRESULT hr =0;
	hr =D3DXCreateTextureFromFile(
		_device,
		fileName.c_str(),&_tex);if(FAILED(hr))returnfalse;returntrue;}boolTerrain::genTexture(D3DXVECTOR3* directionToLight){// Method fills the top surface of a texture procedurally.  Then// lights the top surface.  Finally, it fills the other mipmap// surfaces based on the top surface data using D3DXFilterTexture.
	HRESULT hr =0;// texel for each quad cellint texWidth = _numCellsPerRow;int texHeight = _numCellsPerCol;// create an empty texture
	hr =D3DXCreateTexture(
		_device,
		texWidth, texHeight,0,// create a complete mipmap chain0,// usage
		D3DFMT_X8R8G8B8,// 32 bit XRGB format
		D3DPOOL_MANAGED,&_tex);if(FAILED(hr))returnfalse;
	D3DSURFACE_DESC textureDesc;
	_tex->GetLevelDesc(0/*level*/,&textureDesc);// make sure we got the requested format because our code // that fills the texture is hard coded to a 32 bit pixel depth.if(textureDesc.Format != D3DFMT_X8R8G8B8)returnfalse;
	D3DLOCKED_RECT lockedRect;
	_tex->LockRect(0/*lock top surface*/,&lockedRect,0/* lock entire tex*/,0/*flags*/);
	DWORD* imageData =(DWORD*)lockedRect.pBits;for(int i =0; i < texHeight; i++){for(int j =0; j < texWidth; j++){
			D3DXCOLOR c;// get height of upper left vertex of quad.float height =(float)getHeightmapEntry(i, j)/ _heightScale;if((height)<42.5f) 		 c = d3d::BEACH_SAND;elseif((height)<85.0f)	 c = d3d::LIGHT_YELLOW_GREEN;elseif((height)<127.5f) c = d3d::PUREGREEN;elseif((height)<170.0f) c = d3d::DARK_YELLOW_GREEN;elseif((height)<212.5f) c = d3d::DARKBROWN;else	                     c = d3d::WHITE;// fill locked data, note we divide the pitch by four because the// pitch is given in bytes and there are 4 bytes per DWORD.
			imageData[i * lockedRect.Pitch /4+ j]=(D3DCOLOR)c;}}
	_tex->UnlockRect(0);if(!lightTerrain(directionToLight)){::MessageBox(0,"lightTerrain() - FAILED",0,0);returnfalse;}
	hr =D3DXFilterTexture(
		_tex,0,// default palette0,// use top level as source level
		D3DX_DEFAULT);// default filterif(FAILED(hr)){::MessageBox(0,"D3DXFilterTexture() - FAILED",0,0);returnfalse;}returntrue;}boolTerrain::lightTerrain(D3DXVECTOR3* directionToLight){
	HRESULT hr =0;
	D3DSURFACE_DESC textureDesc;
	_tex->GetLevelDesc(0/*level*/,&textureDesc);// make sure we got the requested format because our code that fills the// texture is hard coded to a 32 bit pixel depth.if(textureDesc.Format != D3DFMT_X8R8G8B8)returnfalse;
	D3DLOCKED_RECT lockedRect;
	_tex->LockRect(0,// lock top surface level in mipmap chain&lockedRect,// pointer to receive locked data0,// lock entire texture image0);// no lock flags specified
	DWORD* imageData =(DWORD*)lockedRect.pBits;for(int i =0; i < textureDesc.Height; i++){for(int j =0; j < textureDesc.Width; j++){// index into texture, note we use the pitch and divide by // four since the pitch is given in bytes and there are // 4 bytes per DWORD.int index = i * lockedRect.Pitch /4+ j;// get current color of quad
			D3DXCOLOR c(imageData[index]);// shade current quad
			c *=computeShade(i, j, directionToLight);;// save shaded color
			imageData[index]=(D3DCOLOR)c;}}
	_tex->UnlockRect(0);returntrue;}floatTerrain::computeShade(int cellRow,int cellCol, D3DXVECTOR3* directionToLight){// get heights of three vertices on the quadfloat heightA =getHeightmapEntry(cellRow, cellCol);float heightB =getHeightmapEntry(cellRow, cellCol +1);float heightC =getHeightmapEntry(cellRow +1, cellCol);// build two vectors on the quad
	D3DXVECTOR3 u(_cellSpacing, heightB - heightA,0.0f);
	D3DXVECTOR3 v(0.0f, heightC - heightA,-_cellSpacing);// find the normal by taking the cross product of two// vectors on the quad.
	D3DXVECTOR3 n;D3DXVec3Cross(&n,&u,&v);D3DXVec3Normalize(&n,&n);float cosine =D3DXVec3Dot(&n, directionToLight);if(cosine <0.0f)
		cosine =0.0f;return cosine;}boolTerrain::readRawFile(std::string fileName){// Restriction: RAW file dimensions must be >= to the// dimensions of the terrain.  That is a 128x128 RAW file// can only be used with a terrain constructed with at most// 128x128 vertices.// A height for each vertex
	std::vector<BYTE>in(_numVertices);
	std::ifstream inFile(fileName.c_str(), std::ios_base::binary);/*if (inFile.is_open())
		return false;*/
	inFile.read((char*)&in[0],// buffer
		in.size());// number of bytes to read into buffer
	inFile.close();// copy BYTE vector to int vector
	_heightmap.resize(_numVertices);for(int i =0; i < in.size(); i++)
		_heightmap[i]= in[i];returntrue;}floatTerrain::getHeight(float x,float z){// Translate on xz-plane by the transformation that takes// the terrain START point to the origin.
	x =((float)_width /2.0f)+ x;
	z =((float)_depth /2.0f)- z;// Scale down by the transformation that makes the // cellspacing equal to one.  This is given by // 1 / cellspacing since; cellspacing * 1 / cellspacing = 1.
	x /=(float)_cellSpacing;
	z /=(float)_cellSpacing;// From now on, we will interpret our positive z-axis as// going in the 'down' direction, rather than the 'up' direction.// This allows to extract the row and column simply by 'flooring'// x and z:float col =::floorf(x);float row =::floorf(z);// get the heights of the quad we're in:// //  A   B//  *---*//  | / |//  *---*  //  C   Dfloat A =getHeightmapEntry(row, col);float B =getHeightmapEntry(row, col +1);float C =getHeightmapEntry(row +1, col);float D =getHeightmapEntry(row +1, col +1);//// Find the triangle we are in://// Translate by the transformation that takes the upper-left// corner of the cell we are in to the origin.  Recall that our // cellspacing was nomalized to 1.  Thus we have a unit square// at the origin of our +x -> 'right' and +z -> 'down' system.float dx = x - col;float dz = z - row;// Note the below compuations of u and v are unneccessary, we really// only need the height, but we compute the entire vector to emphasis// the books discussion.float height =0.0f;if(dz <1.0f- dx)// upper triangle ABC{float uy = B - A;// A->Bfloat vy = C - A;// A->C// Linearly interpolate on each vector.  The height is the vertex// height the vectors u and v originate from {A}, plus the heights// found by interpolating on each vector u and v.
		height = A + d3d::Lerp(0.0f, uy, dx)+ d3d::Lerp(0.0f, vy, dz);}else// lower triangle DCB{float uy = C - D;// D->Cfloat vy = B - D;// D->B// Linearly interpolate on each vector.  The height is the vertex// height the vectors u and v originate from {D}, plus the heights// found by interpolating on each vector u and v.
		height = D + d3d::Lerp(0.0f, uy,1.0f- dx)+ d3d::Lerp(0.0f, vy,1.0f- dz);}return height;}boolTerrain::draw(D3DXMATRIX* world,bool drawTris){
	HRESULT hr =0;if(_device){
		_device->SetTransform(D3DTS_WORLD, world);
		_device->SetStreamSource(0, _vb,0,sizeof(TerrainVertex));
		_device->SetFVF(TerrainVertex::FVF);
		_device->SetIndices(_ib);
		_device->SetTexture(0, _tex);// turn off lighting since we're lighting it ourselves
		_device->SetRenderState(D3DRS_LIGHTING,false);
		hr = _device->DrawIndexedPrimitive(
			D3DPT_TRIANGLELIST,0,0,
			_numVertices,0,
			_numTriangles);
		_device->SetRenderState(D3DRS_LIGHTING,true);if(drawTris){
			_device->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);
			hr = _device->DrawIndexedPrimitive(
				D3DPT_TRIANGLELIST,0,0,
				_numVertices,0,
				_numTriangles);
			_device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);}if(FAILED(hr))returnfalse;}returntrue;}

camera.h

#pragmaonce#include<d3dx9.h>classCamera{public:enumCameraType{ LANDOBJECT, AIRCRAFT };Camera();Camera(CameraType cameraType);~Camera();voidstrafe(float units);//left/rightvoidfly(float units);//up/downvoidwalk(float units);//forward/backwardvoidpitch(float angle);//rotate on right vectorvoidyaw(float angle);//rotate on up vectorvoidroll(float angle);//rotate on look vectorvoidgetViewMatrix(D3DXMATRIX* V);voidsetCameraType(CameraType cameraType);voidgetPosition(D3DXVECTOR3* pos);voidsetPosition(D3DXVECTOR3* pos);voidgetRight(D3DXVECTOR3* right);voidgetUp(D3DXVECTOR3* up);voidgetLook(D3DXVECTOR3* look);private:
	CameraType _cameraType;
	D3DXVECTOR3 _right;
	D3DXVECTOR3 _up;
	D3DXVECTOR3 _look;
	D3DXVECTOR3 _pos;};

camera.cpp

#include"camera.h"Camera::Camera(){
	_cameraType = LANDOBJECT;
	_pos =D3DXVECTOR3(0.0f,0.0f,0.0f);
	_right =D3DXVECTOR3(1.0f,0.0f,0.0f);
	_up =D3DXVECTOR3(0.0f,1.0f,0.0f);
	_look =D3DXVECTOR3(0.0f,0.0f,1.0f);}Camera::Camera(CameraType cameraType){
	_cameraType = cameraType;
	_pos =D3DXVECTOR3(0.0f,0.0f,0.0f);
	_right =D3DXVECTOR3(1.0f,0.0f,0.0f);
	_up =D3DXVECTOR3(0.0f,1.0f,0.0f);
	_look =D3DXVECTOR3(0.0f,0.0f,1.0f);}Camera::~Camera(){}voidCamera::getPosition(D3DXVECTOR3* pos){*pos = _pos;}voidCamera::setPosition(D3DXVECTOR3* pos){
	_pos =*pos;}voidCamera::getRight(D3DXVECTOR3* right){*right = _right;}voidCamera::getUp(D3DXVECTOR3* up){*up = _up;}voidCamera::getLook(D3DXVECTOR3* look){*look = _look;}voidCamera::walk(float units){if(_cameraType == LANDOBJECT)
		_pos +=D3DXVECTOR3(_look.x,0.0f, _look.z)* units;if(_cameraType == AIRCRAFT)
		_pos += _look * units;}voidCamera::strafe(float units){if(_cameraType == LANDOBJECT)
		_pos +=D3DXVECTOR3(_right.x,0.0f, _right.z)* units;if(_cameraType == AIRCRAFT)
		_pos += _right * units;}voidCamera::fly(float units){if(_cameraType == LANDOBJECT)
		_pos.y += units;if(_cameraType == AIRCRAFT)
		_pos += _up * units;}voidCamera::pitch(float angle){
	D3DXMATRIX T;D3DXMatrixRotationAxis(&T,&_right, angle);D3DXVec3TransformCoord(&_up,&_up,&T);D3DXVec3TransformCoord(&_look,&_look,&T);}voidCamera::yaw(float angle){
	D3DXMATRIX T;if(_cameraType == LANDOBJECT)D3DXMatrixRotationY(&T, angle);if(_cameraType == AIRCRAFT)D3DXMatrixRotationAxis(&T,&_up, angle);D3DXVec3TransformCoord(&_right,&_right,&T);D3DXVec3TransformCoord(&_look,&_look,&T);}voidCamera::roll(float angle){if(_cameraType == AIRCRAFT){
		D3DXMATRIX T;D3DXMatrixRotationAxis(&T,&_look, angle);D3DXVec3TransformCoord(&_up,&_up,&T);D3DXVec3TransformCoord(&_right,&_right,&T);}}voidCamera::getViewMatrix(D3DXMATRIX* V){//保持相机轴彼此正交D3DXVec3Normalize(&_look,&_look);D3DXVec3Cross(&_up,&_look,&_right);D3DXVec3Normalize(&_up,&_up);D3DXVec3Cross(&_right,&_up,&_look);D3DXVec3Normalize(&_right,&_right);//构建视图矩阵float x =-D3DXVec3Dot(&_right,&_pos);float y =-D3DXVec3Dot(&_up,&_pos);float z =-D3DXVec3Dot(&_look,&_pos);//视图矩阵=平移矩阵*旋转矩阵(*V)(0,0)= _right.x;(*V)(0,1)= _up.x;(*V)(0,2)= _look.x;(*V)(0,3)=0.0f;(*V)(1,0)= _right.y;(*V)(1,1)= _up.y;(*V)(1,2)= _look.y;(*V)(1,3)=0.0f;(*V)(2,0)= _right.z;(*V)(2,1)= _up.z;(*V)(2,2)= _look.z;(*V)(2,3)=0.0f;(*V)(3,0)= x;(*V)(3,1)= y;(*V)(3,2)= z;(*V)(3,3)=1.0f;}voidCamera::setCameraType(CameraType cameraType){
	_cameraType = cameraType;}

d3dutil.h

#pragmaonce#include<d3d9.h>#include<d3dx9math.h>namespace d3d
{boolInitD3D(HINSTANCE hInstance,int width,int height,bool windowed, D3DDEVTYPE deviceType, IDirect3DDevice9** device);intEnterMsgLoop(bool(*ptr_display)(float timeDelta));
	LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);template<classT>voidRelease(T t){if(t){
			t->Release();
			t =nullptr;}}template<classT>voidDelete(T t){if(t){delete t;
			t =nullptr;}}const D3DXCOLOR WHITE(D3DCOLOR_XRGB(255,255,255));const D3DXCOLOR BLACK(D3DCOLOR_XRGB(0,0,0));const D3DXCOLOR RED(D3DCOLOR_XRGB(255,0,0));const D3DXCOLOR GREEN(D3DCOLOR_XRGB(0,255,0));const D3DXCOLOR BLUE(D3DCOLOR_XRGB(0,0,255));const D3DXCOLOR YELLOW(D3DCOLOR_XRGB(255,255,0));const D3DXCOLOR CYAN(D3DCOLOR_XRGB(0,255,255));const D3DXCOLOR MAGENTA(D3DCOLOR_XRGB(255,0,255));const D3DXCOLOR BEACH_SAND(D3DCOLOR_XRGB(255,249,157));const D3DXCOLOR DESERT_SAND(D3DCOLOR_XRGB(250,205,135));const D3DXCOLOR LIGHTGREEN(D3DCOLOR_XRGB(60,184,120));const D3DXCOLOR  PUREGREEN(D3DCOLOR_XRGB(0,166,81));const D3DXCOLOR  DARKGREEN(D3DCOLOR_XRGB(0,114,54));const D3DXCOLOR LIGHT_YELLOW_GREEN(D3DCOLOR_XRGB(124,197,118));const D3DXCOLOR  PURE_YELLOW_GREEN(D3DCOLOR_XRGB(57,181,74));const D3DXCOLOR  DARK_YELLOW_GREEN(D3DCOLOR_XRGB(25,123,48));const D3DXCOLOR LIGHTBROWN(D3DCOLOR_XRGB(198,156,109));const D3DXCOLOR DARKBROWN(D3DCOLOR_XRGB(115,100,87));//材质
	D3DMATERIAL9 InitMtrl(D3DXCOLOR a, D3DXCOLOR d, D3DXCOLOR s, D3DXCOLOR e,float p);const D3DMATERIAL9 WHITE_MTRL =InitMtrl(WHITE, WHITE, WHITE, BLACK,8.0f);const D3DMATERIAL9 RED_MTRL =InitMtrl(RED, RED, RED, BLACK,8.0f);const D3DMATERIAL9 GREEN_MTRL =InitMtrl(GREEN, GREEN, GREEN, BLACK,8.0f);const D3DMATERIAL9 BLUE_MTRL =InitMtrl(BLUE, BLUE, BLUE, BLACK,8.0f);const D3DMATERIAL9 YELLOW_MTRL =InitMtrl(YELLOW, YELLOW, YELLOW, BLACK,8.0f);//光源
	D3DLIGHT9 InitDirectionalLight(D3DXVECTOR3* direction, D3DXCOLOR* color);//D3DLIGHT9 InitPointLight(D3DXVECTOR3* position, D3DXCOLOR* color);//D3DLIGHT9 InitSpotLight(D3DXVECTOR3* position, D3DXVECTOR3* direction, D3DXCOLOR* color);// Function references "desert.bmp" internally.  This file must// be in the working directory.boolDrawBasicScene(
		IDirect3DDevice9* device,// Pass in 0 for cleanup.float scale);// uniform scale structVertex{Vertex(){}Vertex(float x,float y,float z,float nx,float ny,float nz,float u,float v){
			_x = x;  _y = y;  _z = z;
			_nx = nx; _ny = ny; _nz = nz;
			_u = u;  _v = v;}float _x, _y, _z;float _nx, _ny, _nz;float _u, _v;staticconst DWORD FVF;};//// Randomness//// Desc: Return random float in [lowBound, highBound] interval.floatGetRandomFloat(float lowBound,float highBound);// Desc: Returns a random vector in the bounds specified by min and max.voidGetRandomVector(
		D3DXVECTOR3* out,
		D3DXVECTOR3* min,
		D3DXVECTOR3* max);//// Conversion//
	DWORD FtoDw(float f);//// Interpolation//floatLerp(float a,float b,float t);}

d3dutil.cpp

#include"d3dUtility.h"// vertex formatsconst DWORD d3d::Vertex::FVF = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1;bool d3d::InitD3D(HINSTANCE hInstance,int width,int height,bool windowed, D3DDEVTYPE deviceType, IDirect3DDevice9** device){//注册wndclass
	WNDCLASS wndclass;
	wndclass.style = CS_VREDRAW | CS_HREDRAW;
	wndclass.lpfnWndProc = WndProc;
	wndclass.cbClsExtra =0;
	wndclass.cbWndExtra =0;
	wndclass.hInstance = hInstance;
	wndclass.hIcon =LoadIcon(nullptr, IDI_APPLICATION);
	wndclass.hCursor =LoadCursor(nullptr, IDC_ARROW);
	wndclass.hbrBackground =(HBRUSH)GetStockObject(WHITE_BRUSH);
	wndclass.lpszMenuName =nullptr;
	wndclass.lpszClassName =TEXT("d3d");if(!RegisterClass(&wndclass)){MessageBox(nullptr,TEXT("RegisterClass() - FAILED"),TEXT("ERROR"), MB_ICONERROR);returnfalse;}//创建窗口
	HWND hwnd =CreateWindow(TEXT("d3d"),TEXT("d3d window"),
		WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, width, height,nullptr,nullptr, hInstance,nullptr);//设备列举和创建IDirect3DDevice9对象
	IDirect3D9* d3d9 =Direct3DCreate9(D3D_SDK_VERSION);//检测硬件顶点处理
	D3DCAPS9 caps;
	d3d9->GetDeviceCaps(D3DADAPTER_DEFAULT, deviceType,&caps);int vp =0;if(caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT)
		vp = D3DCREATE_HARDWARE_VERTEXPROCESSING;//支持硬件顶点处理else
		vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING;//不支持
	D3DDISPLAYMODE d3ddm;if(FAILED(d3d9->GetAdapterDisplayMode(D3DADAPTER_DEFAULT,&d3ddm)))returnfalse;//填充D3DPRESENT_PARAMETERS结构
	D3DPRESENT_PARAMETERS d3dpp;
	d3dpp.BackBufferWidth = width;
	d3dpp.BackBufferHeight = height;//d3dpp.BackBufferFormat = D3DFMT_A8B8G8R8;//像素格式
	d3dpp.BackBufferFormat = d3ddm.Format;
	d3dpp.BackBufferCount =1;
	d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
	d3dpp.MultiSampleQuality =0;
	d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
	d3dpp.hDeviceWindow = hwnd;
	d3dpp.Windowed = windowed;//full screen
	d3dpp.EnableAutoDepthStencil =true;
	d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;//depth format
	d3dpp.Flags =0;
	d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
	d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;//创建IDirect3DDevice9对象
	HRESULT hr = d3d9->CreateDevice(D3DADAPTER_DEFAULT, deviceType, hwnd, vp,&d3dpp, device);if(FAILED(hr)){MessageBox(nullptr,TEXT("CraeteDevice() - FAILED"),TEXT("ERROR"), MB_ICONERROR);returnfalse;}
	d3d9->Release();returntrue;}int d3d::EnterMsgLoop(bool(*ptr_display)(float timeDelta)){
	MSG msg;memset(&msg,0,sizeof(msg));staticfloat lastTime =(float)timeGetTime();while(true){if(PeekMessage(&msg,nullptr,0,0, PM_REMOVE)){if(msg.message == WM_QUIT)break;TranslateMessage(&msg);DispatchMessage(&msg);}else{float currTime =(float)timeGetTime();float timeDelta =(currTime - lastTime)*0.001f;ptr_display(timeDelta);
			lastTime = currTime;}}return msg.wParam;}
LRESULT CALLBACK d3d::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam){switch(msg){case WM_DESTROY:PostQuitMessage(0);break;case WM_KEYDOWN:if(wParam == VK_ESCAPE)DestroyWindow(hwnd);break;}returnDefWindowProc(hwnd, msg, wParam, lParam);}
D3DMATERIAL9 d3d::InitMtrl(D3DXCOLOR a, D3DXCOLOR d, D3DXCOLOR s, D3DXCOLOR e,float p){
	D3DMATERIAL9 mtrl;
	mtrl.Ambient = a;//环境光
	mtrl.Diffuse = d;//漫反射
	mtrl.Specular = s;//镜面反射
	mtrl.Emissive = e;//表面添加颜色
	mtrl.Power = p;//镜面高光return mtrl;}
D3DLIGHT9 d3d::InitDirectionalLight(D3DXVECTOR3* direction, D3DXCOLOR* color){
	D3DLIGHT9 light;ZeroMemory(&light,sizeof(light));
	light.Type = D3DLIGHT_DIRECTIONAL;
	light.Diffuse =*color;
	light.Ambient =*color *0.3f;
	light.Specular =*color *0.6f;
	light.Direction =*direction;return light;}bool d3d::DrawBasicScene(IDirect3DDevice9* device,float scale){static IDirect3DVertexBuffer9* floor =nullptr;static IDirect3DTexture9* tex =nullptr;static ID3DXMesh* pillar =nullptr;
	HRESULT hr =0;if(device ==nullptr){if(floor && tex && pillar){
			d3d::Release<IDirect3DVertexBuffer9*>(floor);
			d3d::Release<IDirect3DTexture9*>(tex);
			d3d::Release<ID3DXMesh*>(pillar);}}elseif(!floor &&!tex &&!pillar){
		device->CreateVertexBuffer(6*sizeof(d3d::Vertex),0,
			d3d::Vertex::FVF,
			D3DPOOL_MANAGED,&floor,0);
		Vertex* v =0;
		floor->Lock(0,0,(void**)&v,0);
		v[0]=Vertex(-20.0f,-2.5f,-20.0f,0.0f,1.0f,0.0f,0.0f,1.0f);
		v[1]=Vertex(-20.0f,-2.5f,20.0f,0.0f,1.0f,0.0f,0.0f,0.0f);
		v[2]=Vertex(20.0f,-2.5f,20.0f,0.0f,1.0f,0.0f,1.0f,0.0f);
		v[3]=Vertex(-20.0f,-2.5f,-20.0f,0.0f,1.0f,0.0f,0.0f,1.0f);
		v[4]=Vertex(20.0f,-2.5f,20.0f,0.0f,1.0f,0.0f,1.0f,0.0f);
		v[5]=Vertex(20.0f,-2.5f,-20.0f,0.0f,1.0f,0.0f,1.0f,1.0f);
		floor->Unlock();//使用左手坐标系创建包含缸的网格D3DXCreateCylinder(device,0.5f,0.5f,5.0f,20,20,&pillar,nullptr);D3DXCreateTextureFromFile(device,TEXT("desert.bmp"),&tex);}else{//设置过滤器
		device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
		device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
		device->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_POINT);//设置光源
		D3DXVECTOR3 dir(0.707f,-0.707f,0.707f);
		D3DXCOLOR col(1.0f,1.0f,1.0f,1.0f);
		D3DLIGHT9 light = d3d::InitDirectionalLight(&dir,&col);
		device->SetLight(0,&light);
		device->LightEnable(0,true);
		device->SetRenderState(D3DRS_NORMALIZENORMALS,true);
		device->SetRenderState(D3DRS_SPECULARENABLE,true);//渲染
		D3DXMATRIX T, R, P, S;//生成沿x、y、z轴缩放的矩阵D3DXMatrixScaling(&S, scale, scale, scale);//用于旋转圆柱体以与世界y轴平行D3DXMatrixRotationX(&R,-D3DX_PI *0.5f);//draw floorD3DXMatrixIdentity(&T);
		T = T * S;
		device->SetTransform(D3DTS_WORLD,&T);
		device->SetMaterial(&d3d::WHITE_MTRL);
		device->SetTexture(0, tex);
		device->SetStreamSource(0, floor,0,sizeof(Vertex));
		device->SetFVF(Vertex::FVF);
		device->DrawPrimitive(D3DPT_TRIANGLELIST,0,2);//draw pillars
		device->SetMaterial(&d3d::BLUE_MTRL);
		device->SetTexture(0,0);for(int i =0; i <5; i++){D3DXMatrixTranslation(&T,-5.0f,0.0f,-15.0f+(i *7.5f));
			P = R * T * S;
			device->SetTransform(D3DTS_WORLD,&P);
			pillar->DrawSubset(0);D3DXMatrixTranslation(&T,5.0f,0.0f,-15.0f+(i *7.5f));
			P = R * T * S;
			device->SetTransform(D3DTS_WORLD,&P);
			pillar->DrawSubset(0);}}returntrue;}float d3d::GetRandomFloat(float lowBound,float highBound){if(lowBound >= highBound)// bad inputreturn lowBound;// get random float in [0, 1] intervalfloat f =(rand()%10000)*0.0001f;// return float in [lowBound, highBound] interval. return(f *(highBound - lowBound))+ lowBound;}void d3d::GetRandomVector(
	D3DXVECTOR3* out,
	D3DXVECTOR3* min,
	D3DXVECTOR3* max){
	out->x =GetRandomFloat(min->x, max->x);
	out->y =GetRandomFloat(min->y, max->y);
	out->z =GetRandomFloat(min->z, max->z);}
DWORD d3d::FtoDw(float f){return*((DWORD*)&f);}float d3d::Lerp(float a,float b,float t){return a -(a * t)+(b * t);}

terrainDriver.cpp

#include"d3dUtility.h"#include"terrain.h"#include"camera.h"#include"fps.h"#pragmacomment(lib,"d3d9.lib")#pragmacomment(lib,"d3dx9.lib")#pragmacomment(lib,"winmm.lib")#defineKEY_DOWN(vk_code)(GetAsyncKeyState(vk_code)&0x8000?1:0)//// Globals//
IDirect3DDevice9* device =0;constint Width =640;constint Height =480;
Terrain* TheTerrain =0;
Camera   TheCamera(Camera::LANDOBJECT);
FPSCounter* FPS =0;//// Framework Functions//boolsetup(){//// Create the terrain.//
	D3DXVECTOR3 lightDirection(0.0f,1.0f,0.0f);
	TheTerrain =newTerrain(device,"coastMountain64.raw",64,64,10,0.5f);
	TheTerrain->genTexture(&lightDirection);//// Create the font.//
	FPS =newFPSCounter(device);//// Set texture filters.//
	device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
	device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
	device->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);//// Set projection matrix.//
	D3DXMATRIX proj;D3DXMatrixPerspectiveFovLH(&proj,
		D3DX_PI *0.25f,// 45 - degree(float)Width /(float)Height,1.0f,1000.0f);
	device->SetTransform(D3DTS_PROJECTION,&proj);returntrue;}voidcleanup(){
	d3d::Delete<Terrain*>(TheTerrain);
	d3d::Delete<FPSCounter*>(FPS);}booldisplay(float timeDelta){//// Update the scene://if(device){if(KEY_DOWN(VK_UP))
			TheCamera.walk(100.0f* timeDelta);if(KEY_DOWN(VK_DOWN))
			TheCamera.walk(-100.0f* timeDelta);if(KEY_DOWN(VK_LEFT))
			TheCamera.yaw(-1.0f* timeDelta);if(KEY_DOWN(VK_RIGHT))
			TheCamera.yaw(1.0f* timeDelta);if(KEY_DOWN('N'))
			TheCamera.strafe(-100.0f* timeDelta);if(KEY_DOWN('M'))
			TheCamera.strafe(100.0f* timeDelta);if(KEY_DOWN('W'))
			TheCamera.pitch(1.0f* timeDelta);if(KEY_DOWN('S'))
			TheCamera.pitch(-1.0f* timeDelta);
		D3DXVECTOR3 pos;
		TheCamera.getPosition(&pos);float height = TheTerrain->getHeight(pos.x, pos.z);
		pos.y = height +5.0f;// add height because we're standing up
		TheCamera.setPosition(&pos);
		D3DXMATRIX V;
		TheCamera.getViewMatrix(&V);
		device->SetTransform(D3DTS_VIEW,&V);//// Draw the scene://
		device->Clear(0,0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,0xff000000,1.0f,0);
		device->BeginScene();
		D3DXMATRIX I;D3DXMatrixIdentity(&I);if(TheTerrain)
			TheTerrain->draw(&I,false);if(FPS)
			FPS->render(0xffffffff, timeDelta);
		device->EndScene();
		device->Present(0,0,0,0);}returntrue;}//// WinMain//int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine,int iCmdShow){if(!d3d::InitD3D(hInstance, Width, Height,true, D3DDEVTYPE_HAL,&device)){MessageBox(nullptr,TEXT("InitD3D() - FAILED"),TEXT("ERROR"), MB_ICONERROR);return0;}if(!setup()){MessageBox(nullptr,TEXT("setup() - FAILED"),TEXT("ERROR"), MB_ICONERROR);return0;}
	d3d::EnterMsgLoop(display);cleanup();
	device->Release();return1;}

本文标签: 系统 编程 地形