dx9.0地形

2023-10-21 21:10
文章标签 地形 dx9.0

本文主要是介绍dx9.0地形,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

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.旋转:将摄像机的方向向量(x、y、z)与世界坐标系的轴对齐
    在这里插入图片描述
    合并视图矩阵=平移矩阵*旋转矩阵

    在这里插入图片描述

  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;else if ((height) < 85.0f)	 c = d3d::LIGHT_YELLOW_GREEN;else if ((height) < 127.5f) c = d3d::PUREGREEN;else if ((height) < 170.0f) c = d3d::DARK_YELLOW_GREEN;else if ((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 quadD3DXVECTOR3 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->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);
    }
    
  3. 原书代码修改部分

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

bool FPSCounter::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);}return true;
}
  1. 运行效果
    在这里插入图片描述
    在这里插入图片描述
    5.原书代码
    d3dfont.h
#pragma once
#include <tchar.h>
#include <D3D9.h>// Font creation flags
#define D3DFONT_BOLD        0x0001
#define D3DFONT_ITALIC      0x0002
#define D3DFONT_ZENABLE     0x0004// Font rendering flags
#define D3DFONT_CENTERED_X  0x0001
#define D3DFONT_CENTERED_Y  0x0002
#define D3DFONT_TWOSIDED    0x0004
#define D3DFONT_FILTERED    0x0008//-----------------------------------------------------------------------------
// Name: class CD3DFont
// Desc: Texture-based font class for doing text in a 3D scene.
//-----------------------------------------------------------------------------
class CD3DFont
{TCHAR   m_strFontName[80];            // Font propertiesDWORD   m_dwFontHeight;DWORD   m_dwFontFlags;LPDIRECT3DDEVICE9       m_pd3dDevice; // A D3DDevice used for renderingLPDIRECT3DTEXTURE9      m_pTexture;   // The d3d texture for this fontLPDIRECT3DVERTEXBUFFER9 m_pVB;        // VertexBuffer for rendering textDWORD   m_dwTexWidth;                 // Texture dimensionsDWORD   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 statesLPDIRECT3DSTATEBLOCK9 m_pStateBlockSaved;LPDIRECT3DSTATEBLOCK9 m_pStateBlockDrawText;public:// 2D and 3D text drawing functionsHRESULT 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 textHRESULT GetTextExtent(const TCHAR* strText, SIZE* pSize);// Initializing and destroying device-dependent objectsHRESULT 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.
//-----------------------------------------------------------------------------
#define STRICT
#include <stdio.h>
#include <tchar.h>
#include <D3DX9.h>
#include "D3DFont.h"
#include "D3DUtil.h"
#include "DXUtil.h"//-----------------------------------------------------------------------------
// Custom vertex types for rendering text
//-----------------------------------------------------------------------------
#define MAX_NUM_VERTICES 50*6struct FONT2DVERTEX { D3DXVECTOR4 p;   DWORD color;     FLOAT tu, tv; };
struct FONT3DVERTEX { D3DXVECTOR3 p;   D3DXVECTOR3 n;   FLOAT tu, tv; };#define D3DFVF_FONT2DVERTEX (D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1)
#define D3DFVF_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 devicem_pd3dDevice = pd3dDevice;// Establish the font and texture sizem_fTextScale = 1.0f; // Draw fonts into texture without scaling// Large fonts need larger texturesif (m_dwFontHeight > 60)m_dwTexWidth = m_dwTexHeight = 2048;else if (m_dwFontHeight > 30)m_dwTexWidth = m_dwTexHeight = 1024;else if (m_dwFontHeight > 15)m_dwTexWidth = m_dwTexHeight = 512;elsem_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 fonthr = 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 bitmapDWORD* 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 fontHDC     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 pixelsD3DLOCKED_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 objectsm_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);elsem_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);elsem_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 renderstatem_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 spacingsx -= m_dwSpacing * (fXScale * vp.Height) / fLineHeight;FLOAT fStartX = sx;// Fill vertex bufferFONT2DVERTEX* 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 bufferm_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 bufferm_pVB->Unlock();if (dwNumTriangles > 0)m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, dwNumTriangles);// Restore the modified renderstatesm_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 renderstatem_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 spacingsx -= m_dwSpacing;FLOAT fStartX = sx;// Fill vertex bufferFONT2DVERTEX* 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 bufferm_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 bufferm_pVB->Unlock();if (dwNumTriangles > 0)m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, dwNumTriangles);// Restore the modified renderstatesm_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 renderstatem_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 elementFLOAT 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 spacingx -= m_dwSpacing / 10.0f;FLOAT fStartX = x;TCHAR c;// Fill vertex bufferFONT3DVERTEX* 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 bufferm_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 bufferm_pVB->Unlock();if (dwNumTriangles > 0)m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, dwNumTriangles);// Restore the modified renderstatesm_pStateBlockSaved->Apply();return S_OK;
}

d3dutil.h

#pragma once
#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:
//-----------------------------------------------------------------------------
class CD3DArcBall
{INT            m_iWidth;   // ArcBall's window widthINT            m_iHeight;  // ArcBall's window heightFLOAT          m_fRadius;  // ArcBall's radius in screen coordsFLOAT          m_fRadiusTranslation; // ArcBall's radius for translating the targetD3DXQUATERNION m_qDown;               // Quaternion before button downD3DXQUATERNION m_qNow;                // Composite quaternion for current dragD3DXMATRIXA16  m_matRotation;         // Matrix for arcball's orientationD3DXMATRIXA16  m_matRotationDelta;    // Matrix for arcball's orientationD3DXMATRIXA16  m_matTranslation;      // Matrix for arcball's positionD3DXMATRIXA16  m_matTranslationDelta; // Matrix for arcball's positionBOOL           m_bDrag;               // Whether user is dragging arcballBOOL           m_bRightHanded;        // Whether to use RH coordinate systemD3DXVECTOR3 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:
//-----------------------------------------------------------------------------
class CD3DCamera
{D3DXVECTOR3 m_vEyePt;       // Attributes for view matrixD3DXVECTOR3 m_vLookatPt;D3DXVECTOR3 m_vUpVec;D3DXVECTOR3 m_vView;D3DXVECTOR3 m_vCross;D3DXMATRIXA16  m_matView;D3DXMATRIXA16  m_matBillboard; // Special matrix for billboarding effectsFLOAT       m_fFOV;         // Attributes for projection matrixFLOAT       m_fAspect;FLOAT       m_fNearPlane;FLOAT       m_fFarPlane;D3DXMATRIXA16  m_matProj;public:// Access functionsD3DXVECTOR3 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

#define STRICT
#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 D3DXreturn D3DXCreateTextureFromFileEx(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 surfaceD3DXMATRIXA16 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)return D3DXQUATERNION(0.0f, 0.0f, 0.0f, 1.0f);FLOAT d2 = sqrtf(sx * sx + sy * sy);if (d2 < fTrackBallRadius * 0.70710678118654752440) // Inside spheresz = sqrtf(fTrackBallRadius * fTrackBallRadius - d2 * d2);else                                                 // On hyperbolasz = (fTrackBallRadius * fTrackBallRadius) / (2.0f * d2);// Get two points on trackball's sphereD3DXVECTOR3 p1(sx, sy, sz);D3DXVECTOR3 p2(0.0f, 0.0f, fTrackBallRadius);// Get axis of rotation, which is cross product of p1 and p2D3DXVECTOR3 vAxis;D3DXVec3Cross(&vAxis, &p1, &p2);// Calculate angle for the rotation about that axisD3DXVECTOR3 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 quaternionD3DXQUATERNION 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 surfaceD3DLOCKED_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;elsepBitmap[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);return D3DXQuaternionUnitAxisToUnitAxis2(pOut, &vA, &vHalf);
}//-----------------------------------------------------------------------------
// Name:
// Desc:
//-----------------------------------------------------------------------------
CD3DArcBall::CD3DArcBall()
{Init();
}//-----------------------------------------------------------------------------
// Name:
// Desc:
//-----------------------------------------------------------------------------
void CD3DArcBall::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 infom_iWidth = iWidth;m_iHeight = iHeight;m_fRadius = fRadius;
}//-----------------------------------------------------------------------------
// Name:
// Desc:
//-----------------------------------------------------------------------------
D3DXVECTOR3 CD3DArcBall::ScreenToVector(int sx, int sy)
{// Scale to screenFLOAT 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;}elsez = sqrtf(1.0f - mag);// Return vectorreturn D3DXVECTOR3(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);static int         iCurMouseX;      // Saved mouse positionstatic int         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 pressediCurMouseX = iMouseX;iCurMouseY = iMouseY;return TRUE;case WM_LBUTTONDOWN:// Start drag modem_bDrag = TRUE;s_vDown = ScreenToVector(iMouseX, iMouseY);m_qDown = m_qNow;return TRUE;case WM_LBUTTONUP:// End drag modem_bDrag = FALSE;return TRUE;case WM_MOUSEMOVE:// Drag objectif (MK_LBUTTON & wParam){if (m_bDrag){// recompute m_qNowD3DXVECTOR3 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;}else if ((MK_RBUTTON & wParam) || (MK_MBUTTON & wParam)){// Normalize based on size of window and bounding sphere radiusFLOAT 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 coordinateiCurMouseX = iMouseX;iCurMouseY = iMouseY;}return TRUE;}return FALSE;
}//-----------------------------------------------------------------------------
// Name:
// Desc:
//-----------------------------------------------------------------------------
CD3DCamera::CD3DCamera()
{// Set attributes for the view matrixD3DXVECTOR3 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 matrixm_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 matrixm_fFOV = fFOV;m_fAspect = fAspect;m_fNearPlane = fNearPlane;m_fFarPlane = fFarPlane;D3DXMatrixPerspectiveFovLH(&m_matProj, fFOV, fAspect, fNearPlane, fFarPlane);
}

dxutil.h

#pragma once
//-----------------------------------------------------------------------------
// Miscellaneous helper functions
//-----------------------------------------------------------------------------
#define SAFE_DELETE(p)       { if(p) { delete (p);     (p)=NULL; } }
#define SAFE_DELETE_ARRAY(p) { if(p) { delete[] (p);   (p)=NULL; } }
#define SAFE_RELEASE(p)      { if(p) { (p)->Release(); (p)=NULL; } }#ifndef UNDER_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
//-----------------------------------------------------------------------------
enum TIMER_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, ...);#if defined(DEBUG) | defined(_DEBUG)
#define DXTRACE           DXUtil_Trace
#else
#define DXTRACE           sizeof
#endif//-----------------------------------------------------------------------------
// Name: ArrayListType
// Desc: Indicates how data should be stored in a CArrayList
//-----------------------------------------------------------------------------
enum ArrayListType
{AL_VALUE,       // entry data is copied into the listAL_REFERENCE,   // entry pointers are copied into the list
};//-----------------------------------------------------------------------------
// Name: CArrayList
// Desc: A growable array
//-----------------------------------------------------------------------------
class CArrayList
{
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);void Remove(UINT Entry);void* GetPtr(UINT Entry);UINT Count(void) { return m_NumEntries; }bool Contains(void* pEntryData);void Clear(void) { m_NumEntries = 0; }
};//-----------------------------------------------------------------------------
// WinCE build support
//-----------------------------------------------------------------------------#ifdef UNDER_CE#define CheckDlgButton(hdialog, id, state) ::SendMessage(::GetDlgItem(hdialog, id), BM_SETCHECK, state, 0)
#define IsDlgButtonChecked(hdialog, id) ::SendMessage(::GetDlgItem(hdialog, id), BM_GETCHECK, 0L, 0L)
#define GETTIMESTAMP GetTickCount
#define _TWINCE(x) _T(x)__inline int GetScrollPos(HWND hWnd, int nBar)
{SCROLLINFO si;memset(&si, 0, sizeof(si));si.cbSize = sizeof(si);si.fMask = SIF_POS;if (!GetScrollInfo(hWnd, nBar, &si)){return 0;}else{return si.nPos;}
}#else // !UNDER_CE#define GETTIMESTAMP timeGetTime
#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
//-----------------------------------------------------------------------------
#ifndef STRICT
#define STRICT
#endif // !STRICT
#include <windows.h>
#include <mmsystem.h>
#include <tchar.h>
#include <stdio.h> 
#include <stdarg.h>
#include "DXUtil.h"#ifdef UNICODE
typedef HINSTANCE(WINAPI* LPShellExecute)(HWND hwnd, LPCWSTR lpOperation, LPCWSTR lpFile, LPCWSTR lpParameters, LPCWSTR lpDirectory, INT nShowCmd);
#else
typedef HINSTANCE(WINAPI* LPShellExecute)(HWND hwnd, LPCSTR lpOperation, LPCSTR lpFile, LPCSTR lpParameters, LPCSTR lpDirectory, INT nShowCmd);
#endif#ifndef UNDER_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 keyHKEY  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#ifndef UNDER_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 pathfile = 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 spacereturn HRESULT_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;return 0.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;return 0.0f;}// Stop the timerif (command == TIMER_STOP){if (!m_bTimerStopped){m_llStopTime = qwTime.QuadPart;m_llLastElapsedTime = qwTime.QuadPart;m_bTimerStopped = TRUE;}return 0.0f;}// Advance the timer by 1/10th secondif (command == TIMER_ADVANCE){m_llStopTime += m_llQPFTicksPerSec / 10;return 0.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()static double m_fLastElapsedTime = 0.0;static double m_fBaseTime = 0.0;static double 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;elsefTime = 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;return 0.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;return 0.0f;}// Stop the timerif (command == TIMER_STOP){if (!m_bTimerStopped){m_fStopTime = fTime;m_fLastElapsedTime = fTime;m_bTimerStopped = TRUE;}return 0.0f;}// Advance the timer by 1/10th secondif (command == TIMER_ADVANCE){m_fStopTime += 0.1f;return 0.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 _UNICODEreturn DXUtil_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;
#elsereturn DXUtil_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 _UNICODEreturn DXUtil_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;
#elsereturn DXUtil_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)
{#ifdef UNDER_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;
#else bool 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 namestrLastSlash = _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.cppLPShellExecute pShellExecute = NULL;HINSTANCE hInstShell32 = LoadLibrary(TEXT("shell32.dll"));if (hInstShell32 != NULL){
#ifdef UNICODEpShellExecute = (LPShellExecute)GetProcAddress(hInstShell32, _TWINCE("ShellExecuteW"));
#elsepShellExecute = (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, ...)
{
#if defined(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;elseNumEntriesAllocatedNew = 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. 
//-----------------------------------------------------------------------------
void CArrayList::Remove(UINT Entry)
{// Decrement countm_NumEntries--;// Find the entry addressBYTE* 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.
//-----------------------------------------------------------------------------
bool CArrayList::Contains(void* pEntryData)
{for (UINT iEntry = 0; iEntry < m_NumEntries; iEntry++){if (m_ArrayListType == AL_VALUE){if (memcmp(GetPtr(iEntry), pEntryData, m_BytesPerEntry) == 0)return true;}else{if (GetPtr(iEntry) == pEntryData)return true;}}return false;
}//-----------------------------------------------------------------------------
// 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)
{return DXUtil_ConvertAnsiStringToWideCch(wstrDestination, strSource, cbDestChar / sizeof(WCHAR));
}HRESULT DXUtil_ConvertWideStringToAnsiCb(CHAR* strDestination, const WCHAR* wstrSource, int cbDestChar)
{return DXUtil_ConvertWideStringToAnsiCch(strDestination, wstrSource, cbDestChar / sizeof(CHAR));
}HRESULT DXUtil_ConvertGenericStringToAnsiCb(CHAR* strDestination, const TCHAR* tstrSource, int cbDestChar)
{return DXUtil_ConvertGenericStringToAnsiCch(strDestination, tstrSource, cbDestChar / sizeof(CHAR));
}HRESULT DXUtil_ConvertGenericStringToWideCb(WCHAR* wstrDestination, const TCHAR* tstrSource, int cbDestChar)
{return DXUtil_ConvertGenericStringToWideCch(wstrDestination, tstrSource, cbDestChar / sizeof(WCHAR));
}HRESULT DXUtil_ConvertAnsiStringToGenericCb(TCHAR* tstrDestination, const CHAR* strSource, int cbDestChar)
{return DXUtil_ConvertAnsiStringToGenericCch(tstrDestination, strSource, cbDestChar / sizeof(TCHAR));
}HRESULT DXUtil_ConvertWideStringToGenericCb(TCHAR* tstrDestination, const WCHAR* wstrSource, int cbDestChar)
{return DXUtil_ConvertWideStringToGenericCch(tstrDestination, wstrSource, cbDestChar / sizeof(TCHAR));
}HRESULT DXUtil_ReadStringRegKeyCb(HKEY hKey, TCHAR* strRegName, TCHAR* strDest, DWORD cbDest, TCHAR* strDefault)
{return DXUtil_ReadStringRegKeyCch(hKey, strRegName, strDest, cbDest / sizeof(TCHAR), strDefault);
}HRESULT DXUtil_ConvertGUIDToStringCb(const GUID* pGuidSrc, TCHAR* strDest, int cbDestChar)
{return DXUtil_ConvertGUIDToStringCch(pGuidSrc, strDest, cbDestChar / sizeof(TCHAR));
}#ifndef UNDER_CE
HRESULT DXUtil_GetDXSDKMediaPathCb(TCHAR* szDest, int cbDest)
{return DXUtil_GetDXSDKMediaPathCch(szDest, cbDest / sizeof(TCHAR));
}HRESULT DXUtil_FindMediaFileCb(TCHAR* szDestPath, int cbDest, TCHAR* strFilename)
{return DXUtil_FindMediaFileCch(szDestPath, cbDest / sizeof(TCHAR), strFilename);
}
#endif // !UNDER_CE

fps.h

#pragma once
#include "d3dfont.h"
#include <sstream>class FPSCounter
{
public:FPSCounter(IDirect3DDevice9* device);~FPSCounter();bool render(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 = new CD3DFont("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;}
}bool FPSCounter::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);}return true;
}

terrain.h

#pragma once
#include "d3dUtility.h"
#include <string>
#include <vector>class Terrain
{
public:Terrain(IDirect3DDevice9* device,std::string heightmapFileName,int numVertsPerRow,int numVertsPerCol,int cellSpacing,    // space between cellsfloat heightScale);~Terrain();int  getHeightmapEntry(int row, int col);void setHeightmapEntry(int row, int col, int value);float getHeight(float x, float z);bool  loadTexture(std::string fileName);bool  genTexture(D3DXVECTOR3* directionToLight);bool  draw(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 methodsbool  readRawFile(std::string fileName);bool  computeVertices();bool  computeIndices();bool  lightTerrain(D3DXVECTOR3* directionToLight);float computeShade(int cellRow, int cellCol, D3DXVECTOR3* directionToLight);struct TerrainVertex{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;static const 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);
}int Terrain::getHeightmapEntry(int row, int col)
{return _heightmap[row * _numVertsPerRow + col];
}void Terrain::setHeightmapEntry(int row, int col, int value)
{_heightmap[row * _numVertsPerRow + col] = value;
}bool Terrain::computeVertices()
{HRESULT hr = 0;hr = _device->CreateVertexBuffer(_numVertices * sizeof(TerrainVertex),D3DUSAGE_WRITEONLY,TerrainVertex::FVF,D3DPOOL_MANAGED,&_vb,0);if (FAILED(hr))return false;// 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();return true;
}bool Terrain::computeIndices()
{HRESULT hr = 0;hr = _device->CreateIndexBuffer(_numTriangles * 3 * sizeof(WORD), // 3 indices per triangleD3DUSAGE_WRITEONLY,D3DFMT_INDEX16,D3DPOOL_MANAGED,&_ib,0);if (FAILED(hr))return false;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 quadbaseIndex += 6;}}_ib->Unlock();return true;
}bool Terrain::loadTexture(std::string fileName)
{HRESULT hr = 0;hr = D3DXCreateTextureFromFile(_device,fileName.c_str(),&_tex);if (FAILED(hr))return false;return true;
}bool Terrain::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 texturehr = D3DXCreateTexture(_device,texWidth, texHeight,0, // create a complete mipmap chain0, // usageD3DFMT_X8R8G8B8,// 32 bit XRGB formatD3DPOOL_MANAGED, &_tex);if (FAILED(hr))return false;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)return false;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;else if ((height) < 85.0f)	 c = d3d::LIGHT_YELLOW_GREEN;else if ((height) < 127.5f) c = d3d::PUREGREEN;else if ((height) < 170.0f) c = d3d::DARK_YELLOW_GREEN;else if ((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);return false;}hr = D3DXFilterTexture(_tex,0, // default palette0, // use top level as source levelD3DX_DEFAULT); // default filterif (FAILED(hr)){::MessageBox(0, "D3DXFilterTexture() - FAILED", 0, 0);return false;}return true;
}bool Terrain::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)return false;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 specifiedDWORD* 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 quadD3DXCOLOR c(imageData[index]);// shade current quadc *= computeShade(i, j, directionToLight);;// save shaded colorimageData[index] = (D3DCOLOR)c;}}_tex->UnlockRect(0);return true;
}float Terrain::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 quadD3DXVECTOR3 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;
}bool Terrain::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 vertexstd::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], // bufferin.size());// number of bytes to read into bufferinFile.close();// copy BYTE vector to int vector_heightmap.resize(_numVertices);for (int i = 0; i < in.size(); i++)_heightmap[i] = in[i];return true;
}float Terrain::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;
}bool Terrain::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))return false;}return true;
}

camera.h

#pragma once
#include <d3dx9.h>class Camera
{
public:enum CameraType { LANDOBJECT, AIRCRAFT };Camera();Camera(CameraType cameraType);~Camera();void strafe(float units);	//left/rightvoid fly(float units);	//up/downvoid walk(float units);	//forward/backwardvoid pitch(float angle);	//rotate on right vectorvoid yaw(float angle);	//rotate on up vectorvoid roll(float angle);	//rotate on look vectorvoid getViewMatrix(D3DXMATRIX* V);void setCameraType(CameraType cameraType);void getPosition(D3DXVECTOR3* pos);void setPosition(D3DXVECTOR3* pos);void getRight(D3DXVECTOR3* right);void getUp(D3DXVECTOR3* up);void getLook(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()
{}void Camera::getPosition(D3DXVECTOR3* pos)
{*pos = _pos;
}void Camera::setPosition(D3DXVECTOR3* pos)
{_pos = *pos;
}void Camera::getRight(D3DXVECTOR3* right)
{*right = _right;
}void Camera::getUp(D3DXVECTOR3* up)
{*up = _up;
}void Camera::getLook(D3DXVECTOR3* look)
{*look = _look;
}void Camera::walk(float units)
{if (_cameraType == LANDOBJECT)_pos += D3DXVECTOR3(_look.x, 0.0f, _look.z) * units;if (_cameraType == AIRCRAFT)_pos += _look * units;
}void Camera::strafe(float units)
{if (_cameraType == LANDOBJECT)_pos += D3DXVECTOR3(_right.x, 0.0f, _right.z) * units;if (_cameraType == AIRCRAFT)_pos += _right * units;
}void Camera::fly(float units)
{if (_cameraType == LANDOBJECT)_pos.y += units;if (_cameraType == AIRCRAFT)_pos += _up * units;
}void Camera::pitch(float angle)
{D3DXMATRIX T;D3DXMatrixRotationAxis(&T, &_right, angle);D3DXVec3TransformCoord(&_up, &_up, &T);D3DXVec3TransformCoord(&_look, &_look, &T);
}void Camera::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);
}void Camera::roll(float angle)
{if (_cameraType == AIRCRAFT){D3DXMATRIX T;D3DXMatrixRotationAxis(&T, &_look, angle);D3DXVec3TransformCoord(&_up, &_up, &T);D3DXVec3TransformCoord(&_right, &_right, &T);}
}void Camera::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;
}void Camera::setCameraType(CameraType cameraType)
{_cameraType = cameraType;
}

d3dutil.h

#pragma once
#include <d3d9.h>
#include <d3dx9math.h>namespace d3d
{bool InitD3D(HINSTANCE hInstance, int width, int height, bool windowed, D3DDEVTYPE deviceType, IDirect3DDevice9** device);int EnterMsgLoop(bool (*ptr_display)(float timeDelta));LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);template<class T> void Release(T t){if (t){t->Release();t = nullptr;}}template<class T> void Delete(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.bool DrawBasicScene(IDirect3DDevice9* device,// Pass in 0 for cleanup.float scale);            // uniform scale struct Vertex{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;static const DWORD FVF;};//// Randomness//// Desc: Return random float in [lowBound, highBound] interval.float GetRandomFloat(float lowBound, float highBound);// Desc: Returns a random vector in the bounds specified by min and max.void GetRandomVector(D3DXVECTOR3* out,D3DXVECTOR3* min,D3DXVECTOR3* max);//// Conversion//DWORD FtoDw(float f);//// Interpolation//float Lerp(float a, float b, float t);
}

d3dutil.cpp

#include "d3dUtility.h"// vertex formats
const 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)
{//注册wndclassWNDCLASS 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);return false;}//创建窗口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;	//支持硬件顶点处理elsevp = D3DCREATE_SOFTWARE_VERTEXPROCESSING;	//不支持D3DDISPLAYMODE d3ddm;if (FAILED(d3d9->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3ddm)))return false;//填充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 screend3dpp.EnableAutoDepthStencil = true;d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;//depth formatd3dpp.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);return false;}d3d9->Release();return true;
}int d3d::EnterMsgLoop(bool(*ptr_display)(float timeDelta))
{MSG msg;memset(&msg, 0, sizeof(msg));static float 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;}return DefWindowProc(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);}}else if (!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 pillarsdevice->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);}}return true;
}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"#pragma comment(lib, "d3d9.lib")
#pragma comment(lib, "d3dx9.lib")
#pragma comment(lib, "winmm.lib")#define KEY_DOWN(vk_code) (GetAsyncKeyState(vk_code) & 0x8000 ? 1 : 0)//
// Globals
//IDirect3DDevice9* device = 0;const int Width = 640;
const int Height = 480;Terrain* TheTerrain = 0;
Camera   TheCamera(Camera::LANDOBJECT);FPSCounter* FPS = 0;//
// Framework Functions
//
bool setup()
{//// Create the terrain.//D3DXVECTOR3 lightDirection(0.0f, 1.0f, 0.0f);TheTerrain = new Terrain(device, "coastMountain64.raw", 64, 64, 10, 0.5f);TheTerrain->genTexture(&lightDirection);//// Create the font.//FPS = new FPSCounter(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);return true;
}void cleanup()
{d3d::Delete<Terrain*>(TheTerrain);d3d::Delete<FPSCounter*>(FPS);
}bool display(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 upTheCamera.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);}return true;
}//
// 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);return 0;}if (!setup()){MessageBox(nullptr, TEXT("setup() - FAILED"), TEXT("ERROR"), MB_ICONERROR);return 0;}d3d::EnterMsgLoop(display);cleanup();device->Release();return 1;
}

这篇关于dx9.0地形的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/256998

相关文章

第二十二篇——地形篇:将领犯错误会导致的常见败局

目录 一、背景介绍二、思路&方案三、过程1.思维导图2.文章中经典的句子理解3.学习之后对于投资市场的理解4.通过这篇文章结合我知道的东西我能想到什么? 四、总结五、升华 一、背景介绍 本章介绍的将领面临的选择;这个和一个企业的管理者是一样的;也是要动态的去系统性的看待现状做出精准的判断 二、思路&方案 1.思维导图2.文章中经典的句子理解3.学习之后对于投资市场的理解4.通

cesium 使用异步函数 getHeightAtPoint,获取指定经纬度点的地形高度。

这个函数使用 CesiumJS 库的 sampleTerrain 方法来获取地形数据。下面是代码的详细解释: async getHeightAtPoint(LngLat) {// 将经纬度转为 Cartographic 对象let cartographics = [Cesium.Cartographic.fromDegrees(LngLat[0], LngLat[1])];// console.

第二十一篇——地形篇:六种地形的战术要点

目录 一、背景介绍二、思路&方案三、过程1.思维导图2.文章中经典的句子理解3.学习之后对于投资市场的理解4.通过这篇文章结合我知道的东西我能想到什么? 四、总结五、升华 一、背景介绍 通过地形的不同分析,动态的看待每一种地形的方式;通过不同的组合结果再结合实际的情况当做判断的依据 二、思路&方案 1.思维导图2.文章中经典的句子理解3.学习之后对于投资市场的理解4.通过这篇

沐风老师3DMax地形拟合插件使用方法详解

3DMax地形拟合插件使用教程                       3DMax地形拟合插件,只需单击几下鼠标,即可将地形表面与道路对齐。它很容易使用。 (注意:如果不仔细阅读,会误认为是这是一个道路拟合(投影)到地形的插件,实际上恰恰相反,这是一个地面拟合到道路的插件。)            【适用版本】 3dMax2010及更高版本            【安

【Unity 3D】学习笔记三十:游戏元素——游戏地形

游戏地形 在游戏的世界中,必定会有很多丰富多彩的游戏元素融合其中。它们种类繁多,作用也不大相同。一般对于游戏元素可分为两种:经常用,不经常用。常用的元素是游戏中比较重要的元素,一般需要使用脚本来实现某些特殊功能。比如:玩家控制的主角对象,需要攻击的敌人等。因此常用的元素直接影响游戏的运行,而不常有的元素,比如说游戏里的天空,云朵等。不影响游戏的主线,仅仅提升游戏的整体效果。 创建地形

cesium 地形获取和生成

1.先从网上下载12.5m精度的地形,然后叠加无人机的地形数据  2.使用global mapper pro合并并导出完整的tiff    3.使用cesiumLab进行tiff的文件数据切片生成terrain格式的数据

Cesium 展示——获取指定区域地形的最大最小高程

文章目录 需求分析方法一:方法二: 需求 在地图上勾选某一处的区域,分析获取区域内最大最小高程 分析 方法一: function getAreaHeight(viewer, positions) {const startP = positions[0

unity游戏开发——(细)深入解析 Unity 地形系统:从基础到高级应用

Unity游戏开发 “好读书,不求甚解;每有会意,便欣然忘食。” 本文目录: Unity游戏开发 Unity游戏开发前言深入解析 Unity 地形系统:从基础到高级应用一、初识 Unity 地形系统1. 地形尺寸与分辨率 二、地形编辑工具详解1. 高度工具(Raise/Lower Terrain)2. 平滑工具(Smooth Height)3. 平整工具(Set Heigh

Direct9学习之--------------------------地形

一. 地形的作用:              地形,不言而喻是用来描绘游戏中高山 盆地 平原等地貌,用于确定对象在游戏世界的空间高度。 二. 地形基本原理:        地形的实现是用地形网格(N行M列矩形网格)和高度图实现,地形网格用于绘制地表,高度图信息则用来表示地形高度。通过高度图的不同高度使地形形成高山盆地等。(高度图中保存了地形高度信息)        地形网格

LintCode 778 给定一个m×n的非负矩阵代表一个大洲,矩阵的每个单元格的值代表此处的地形高度,矩阵的左边缘和上边缘是“太平洋”,下边缘和右边缘是“大西洋”。

一、遍历每个点,每个点来一次dfs,结果超时 class Solution {public:/*** @param matrix: the given matrix* @return: The list of grid coordinates*/vector<vector<int>> globalans;vector<vector<int>> pacificAtlantic(vector<ve