admin 管理员组文章数量: 1184232
dx9.0地形
照相机
这里照相机有
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.平移:将摄像机的位置移动到原点地形
1.从raw文件加载高度图readRawFile
2.生成地形几何数据:
顶点缓存v[index]=TerrainVertex((float)x,(float)_heightmap[index],(float)z,(float)j * uCoordIncrementSize,(float)i * vCoordIncrementSize);索引缓存
indices[baseIndex]= i * _numVertsPerRow + j; indices[baseIndex +1]= i * _numVertsPerRow + j +1; indices[baseIndex +2]=(i +1)* _numVertsPerRow + j; indices[baseIndex +3]=(i +1)* _numVertsPerRow + j; indices[baseIndex +4]= i * _numVertsPerRow + j +1; indices[baseIndex +5]=(i +1)* _numVertsPerRow + j +1;3.根据高度生成纹理
DWORD* imageData =(DWORD*)lockedRect.pBits;for(int i =0; i < texHeight; i++){for(int j =0; j < texWidth; j++){ D3DXCOLOR c;// get height of upper left vertex of quad.float height =(float)getHeightmapEntry(i, j)/ _heightScale;if((height)<42.5f) c = d3d::BEACH_SAND;elseif((height)<85.0f) c = d3d::LIGHT_YELLOW_GREEN;elseif((height)<127.5f) c = d3d::PUREGREEN;elseif((height)<170.0f) c = d3d::DARK_YELLOW_GREEN;elseif((height)<212.5f) c = d3d::DARKBROWN;else c = d3d::WHITE;// fill locked data, note we divide the pitch by four because the// pitch is given in bytes and there are 4 bytes per DWORD. imageData[i * lockedRect.Pitch /4+ j]=(D3DCOLOR)c;}}4.根据光线和平面法线的照射角度生成明暗属性
// build two vectors on the quad D3DXVECTOR3 u(_cellSpacing, heightB - heightA,0.0f); D3DXVECTOR3 v(0.0f, heightC - heightA,-_cellSpacing);// find the normal by taking the cross product of two// vectors on the quad. D3DXVECTOR3 n;D3DXVec3Cross(&n,&u,&v);D3DXVec3Normalize(&n,&n);float cosine =D3DXVec3Dot(&n, directionToLight);if(cosine <0.0f) cosine =0.0f;5.根据位置判断上下三角形获取位置高度
// A B// *---*// | / |// *---* // C 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->B float vy = C - A; // A->C // Linearly interpolate on each vector. The height is the vertex // height the vectors u and v originate from {A}, plus the heights // found by interpolating on each vector u and v. height = A + d3d::Lerp(0.0f, uy, dx) + d3d::Lerp(0.0f, vy, dz); } else // lower triangle DCB { float uy = C - D; // D->C float vy = B - D; // D->B // Linearly interpolate on each vector. The height is the vertex // height the vectors u and v originate from {D}, plus the heights // found by interpolating on each vector u and v. height = D + d3d::Lerp(0.0f, uy, 1.0f - dx) + d3d::Lerp(0.0f, vy, 1.0f - dz); }原书代码修改部分
这里sprintf_s(_fpsString, 8, “%f”, _fps)的_fps的长度会超过8位,改为stringstream就不用担心这个问题
boolFPSCounter::render(D3DCOLOR color,float timeDelta){if(_font){
_frameCnt++;
_timeElapsed += timeDelta;if(_timeElapsed >=1.0f){
_fps =(float)_frameCnt / _timeElapsed;
std::stringstream ss;//std::string fpsStr;
ss << _fps;
ss >> _fpsString;//strncpy_s(_fpsString, 9, fpsStr.c_str(), 9);//sprintf_s(_fpsString, 8, "%f", _fps);
_fpsString[8]='\0';// mark end of string
_timeElapsed =0.0f;
_frameCnt =0;}
_font->DrawText(20,20, color, _fpsString);}returntrue;}-
运行效果
#pragmaonce#include<tchar.h>#include<D3D9.h>// Font creation flags#defineD3DFONT_BOLD0x0001#defineD3DFONT_ITALIC0x0002#defineD3DFONT_ZENABLE0x0004// Font rendering flags#defineD3DFONT_CENTERED_X0x0001#defineD3DFONT_CENTERED_Y0x0002#defineD3DFONT_TWOSIDED0x0004#defineD3DFONT_FILTERED0x0008//-----------------------------------------------------------------------------// Name: class CD3DFont// Desc: Texture-based font class for doing text in a 3D scene.//-----------------------------------------------------------------------------classCD3DFont{
TCHAR m_strFontName[80];// Font properties
DWORD m_dwFontHeight;
DWORD m_dwFontFlags;
LPDIRECT3DDEVICE9 m_pd3dDevice;// A D3DDevice used for rendering
LPDIRECT3DTEXTURE9 m_pTexture;// The d3d texture for this font
LPDIRECT3DVERTEXBUFFER9 m_pVB;// VertexBuffer for rendering text
DWORD m_dwTexWidth;// Texture dimensions
DWORD m_dwTexHeight;
FLOAT m_fTextScale;
FLOAT m_fTexCoords[128-32][4];
DWORD m_dwSpacing;// Character pixel spacing per side// Stateblocks for setting and restoring render states
LPDIRECT3DSTATEBLOCK9 m_pStateBlockSaved;
LPDIRECT3DSTATEBLOCK9 m_pStateBlockDrawText;public:// 2D and 3D text drawing functions
HRESULT DrawText(FLOAT x, FLOAT y, DWORD dwColor,const TCHAR* strText, DWORD dwFlags =0L);
HRESULT DrawTextScaled(FLOAT x, FLOAT y, FLOAT z,
FLOAT fXScale, FLOAT fYScale, DWORD dwColor,const TCHAR* strText, DWORD dwFlags =0L);
HRESULT Render3DText(const TCHAR* strText, DWORD dwFlags =0L);// Function to get extent of text
HRESULT GetTextExtent(const TCHAR* strText, SIZE* pSize);// Initializing and destroying device-dependent objects
HRESULT InitDeviceObjects(LPDIRECT3DDEVICE9 pd3dDevice);
HRESULT RestoreDeviceObjects();
HRESULT InvalidateDeviceObjects();
HRESULT DeleteDeviceObjects();// Constructor / destructorCD3DFont(const TCHAR* strFontName, DWORD dwHeight, DWORD dwFlags =0L);~CD3DFont();};d3dfont.cpp
//-----------------------------------------------------------------------------// File: D3DFont.cpp//// Desc: Texture-based font class//// Copyright (c) 1999-2001 Microsoft Corporation. All rights reserved.//-----------------------------------------------------------------------------#defineSTRICT#include<stdio.h>#include<tchar.h>#include<D3DX9.h>#include"D3DFont.h"#include"D3DUtil.h"#include"DXUtil.h"//-----------------------------------------------------------------------------// Custom vertex types for rendering text//-----------------------------------------------------------------------------#defineMAX_NUM_VERTICES50*6structFONT2DVERTEX{ D3DXVECTOR4 p; DWORD color; FLOAT tu, tv;};structFONT3DVERTEX{ D3DXVECTOR3 p; D3DXVECTOR3 n; FLOAT tu, tv;};#defineD3DFVF_FONT2DVERTEX(D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1)#defineD3DFVF_FONT3DVERTEX(D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX1)inline FONT2DVERTEX InitFont2DVertex(const D3DXVECTOR4& p, D3DCOLOR color,
FLOAT tu, FLOAT tv){
FONT2DVERTEX v; v.p = p; v.color = color; v.tu = tu; v.tv = tv;return v;}inline FONT3DVERTEX InitFont3DVertex(const D3DXVECTOR3& p,const D3DXVECTOR3& n,
FLOAT tu, FLOAT tv){
FONT3DVERTEX v; v.p = p; v.n = n; v.tu = tu; v.tv = tv;return v;}//-----------------------------------------------------------------------------// Name: CD3DFont()// Desc: Font class constructor//-----------------------------------------------------------------------------CD3DFont::CD3DFont(const TCHAR* strFontName, DWORD dwHeight, DWORD dwFlags){_tcsncpy_s(m_strFontName, strFontName,sizeof(m_strFontName)/sizeof(TCHAR));
m_strFontName[sizeof(m_strFontName)/sizeof(TCHAR)-1]=_T('\0');
m_dwFontHeight = dwHeight;
m_dwFontFlags = dwFlags;
m_dwSpacing =0;
m_pd3dDevice =NULL;
m_pTexture =NULL;
m_pVB =NULL;
m_pStateBlockSaved =NULL;
m_pStateBlockDrawText =NULL;}//-----------------------------------------------------------------------------// Name: ~CD3DFont()// Desc: Font class destructor//-----------------------------------------------------------------------------CD3DFont::~CD3DFont(){InvalidateDeviceObjects();DeleteDeviceObjects();}//-----------------------------------------------------------------------------// Name: InitDeviceObjects()// Desc: Initializes device-dependent objects, including the vertex buffer used// for rendering text and the texture map which stores the font image.//-----------------------------------------------------------------------------
HRESULT CD3DFont::InitDeviceObjects(LPDIRECT3DDEVICE9 pd3dDevice){
HRESULT hr;// Keep a local copy of the device
m_pd3dDevice = pd3dDevice;// Establish the font and texture size
m_fTextScale =1.0f;// Draw fonts into texture without scaling// Large fonts need larger texturesif(m_dwFontHeight >60)
m_dwTexWidth = m_dwTexHeight =2048;elseif(m_dwFontHeight >30)
m_dwTexWidth = m_dwTexHeight =1024;elseif(m_dwFontHeight >15)
m_dwTexWidth = m_dwTexHeight =512;else
m_dwTexWidth = m_dwTexHeight =256;// If requested texture is too big, use a smaller texture and smaller font,// and scale up when rendering.
D3DCAPS9 d3dCaps;
m_pd3dDevice->GetDeviceCaps(&d3dCaps);if(m_dwTexWidth > d3dCaps.MaxTextureWidth){
m_fTextScale =(FLOAT)d3dCaps.MaxTextureWidth /(FLOAT)m_dwTexWidth;
m_dwTexWidth = m_dwTexHeight = d3dCaps.MaxTextureWidth;}// Create a new texture for the font
hr = m_pd3dDevice->CreateTexture(m_dwTexWidth, m_dwTexHeight,1,0, D3DFMT_A4R4G4B4,
D3DPOOL_MANAGED,&m_pTexture,NULL);if(FAILED(hr))return hr;// Prepare to create a bitmap
DWORD* pBitmapBits;
BITMAPINFO bmi;ZeroMemory(&bmi.bmiHeader,sizeof(BITMAPINFOHEADER));
bmi.bmiHeader.biSize =sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biWidth =(int)m_dwTexWidth;
bmi.bmiHeader.biHeight =-(int)m_dwTexHeight;
bmi.bmiHeader.biPlanes =1;
bmi.bmiHeader.biCompression = BI_RGB;
bmi.bmiHeader.biBitCount =32;// Create a DC and a bitmap for the font
HDC hDC =CreateCompatibleDC(NULL);
HBITMAP hbmBitmap =CreateDIBSection(hDC,&bmi, DIB_RGB_COLORS,(void**)&pBitmapBits,NULL,0);SetMapMode(hDC, MM_TEXT);// Create a font. By specifying ANTIALIASED_QUALITY, we might get an// antialiased font, but this is not guaranteed.
INT nHeight =-MulDiv(m_dwFontHeight,(INT)(GetDeviceCaps(hDC, LOGPIXELSY)* m_fTextScale),72);
DWORD dwBold =(m_dwFontFlags & D3DFONT_BOLD)? FW_BOLD : FW_NORMAL;
DWORD dwItalic =(m_dwFontFlags & D3DFONT_ITALIC)? TRUE : FALSE;
HFONT hFont =CreateFont(nHeight,0,0,0, dwBold, dwItalic,
FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY,
VARIABLE_PITCH, m_strFontName);if(NULL== hFont)return E_FAIL;
HGDIOBJ hbmOld =SelectObject(hDC, hbmBitmap);
HGDIOBJ hFontOld =SelectObject(hDC, hFont);// Set text propertiesSetTextColor(hDC,RGB(255,255,255));SetBkColor(hDC,0x00000000);SetTextAlign(hDC, TA_TOP);// Loop through all printable character and output them to the bitmap..// Meanwhile, keep track of the corresponding tex coords for each character.
DWORD x =0;
DWORD y =0;
TCHAR str[2]=_T("x");
SIZE size;// Calculate the spacing between characters based on line heightGetTextExtentPoint32(hDC,TEXT(" "),1,&size);
x = m_dwSpacing =(DWORD)ceil(size.cy *0.3f);for(TCHAR c =32; c <127; c++){
str[0]= c;GetTextExtentPoint32(hDC, str,1,&size);if((DWORD)(x + size.cx + m_dwSpacing)> m_dwTexWidth){
x = m_dwSpacing;
y += size.cy +1;}ExtTextOut(hDC, x +0, y +0, ETO_OPAQUE,NULL, str,1,NULL);
m_fTexCoords[c -32][0]=((FLOAT)(x +0- m_dwSpacing))/ m_dwTexWidth;
m_fTexCoords[c -32][1]=((FLOAT)(y +0+0))/ m_dwTexHeight;
m_fTexCoords[c -32][2]=((FLOAT)(x + size.cx + m_dwSpacing))/ m_dwTexWidth;
m_fTexCoords[c -32][3]=((FLOAT)(y + size.cy +0))/ m_dwTexHeight;
x += size.cx +(2* m_dwSpacing);}// Lock the surface and write the alpha values for the set pixels
D3DLOCKED_RECT d3dlr;
m_pTexture->LockRect(0,&d3dlr,0,0);
BYTE* pDstRow =(BYTE*)d3dlr.pBits;
WORD* pDst16;
BYTE bAlpha;// 4-bit measure of pixel intensityfor(y =0; y < m_dwTexHeight; y++){
pDst16 =(WORD*)pDstRow;for(x =0; x < m_dwTexWidth; x++){
bAlpha =(BYTE)((pBitmapBits[m_dwTexWidth * y + x]&0xff)>>4);if(bAlpha >0){*pDst16++=(WORD)((bAlpha <<12)|0x0fff);}else{*pDst16++=0x0000;}}
pDstRow += d3dlr.Pitch;}// Done updating texture, so clean up used objects
m_pTexture->UnlockRect(0);SelectObject(hDC, hbmOld);SelectObject(hDC, hFontOld);DeleteObject(hbmBitmap);DeleteObject(hFont);DeleteDC(hDC);return S_OK;}//-----------------------------------------------------------------------------// Name: RestoreDeviceObjects()// Desc://-----------------------------------------------------------------------------
HRESULT CD3DFont::RestoreDeviceObjects(){
HRESULT hr;// Create vertex buffer for the lettersint vertexSize =max(sizeof(FONT2DVERTEX),sizeof(FONT3DVERTEX));if(FAILED(hr = m_pd3dDevice->CreateVertexBuffer(MAX_NUM_VERTICES * vertexSize,
D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC,0,
D3DPOOL_DEFAULT,&m_pVB,NULL))){return hr;}// Create the state blocks for rendering textfor(UINT which =0; which <2; which++){
m_pd3dDevice->BeginStateBlock();
m_pd3dDevice->SetTexture(0, m_pTexture);if(D3DFONT_ZENABLE & m_dwFontFlags)
m_pd3dDevice->SetRenderState(D3DRS_ZENABLE, TRUE);else
m_pd3dDevice->SetRenderState(D3DRS_ZENABLE, FALSE);
m_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
m_pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
m_pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
m_pd3dDevice->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE);
m_pd3dDevice->SetRenderState(D3DRS_ALPHAREF,0x08);
m_pd3dDevice->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL);
m_pd3dDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
m_pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);
m_pd3dDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE);
m_pd3dDevice->SetRenderState(D3DRS_CLIPPING, TRUE);
m_pd3dDevice->SetRenderState(D3DRS_CLIPPLANEENABLE, FALSE);
m_pd3dDevice->SetRenderState(D3DRS_VERTEXBLEND, D3DVBF_DISABLE);
m_pd3dDevice->SetRenderState(D3DRS_INDEXEDVERTEXBLENDENABLE, FALSE);
m_pd3dDevice->SetRenderState(D3DRS_FOGENABLE, FALSE);
m_pd3dDevice->SetRenderState(D3DRS_COLORWRITEENABLE,
D3DCOLORWRITEENABLE_RED | D3DCOLORWRITEENABLE_GREEN |
D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_ALPHA);
m_pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
m_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
m_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
m_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
m_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
m_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
m_pd3dDevice->SetTextureStageState(0, D3DTSS_TEXCOORDINDEX,0);
m_pd3dDevice->SetTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE);
m_pd3dDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
m_pd3dDevice->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
m_pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);
m_pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
m_pd3dDevice->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_NONE);if(which ==0)
m_pd3dDevice->EndStateBlock(&m_pStateBlockSaved);else
m_pd3dDevice->EndStateBlock(&m_pStateBlockDrawText);}return S_OK;}//-----------------------------------------------------------------------------// Name: InvalidateDeviceObjects()// Desc: Destroys all device-dependent objects//-----------------------------------------------------------------------------
HRESULT CD3DFont::InvalidateDeviceObjects(){SAFE_RELEASE(m_pVB);SAFE_RELEASE(m_pStateBlockSaved);SAFE_RELEASE(m_pStateBlockDrawText);return S_OK;}//-----------------------------------------------------------------------------// Name: DeleteDeviceObjects()// Desc: Destroys all device-dependent objects//-----------------------------------------------------------------------------
HRESULT CD3DFont::DeleteDeviceObjects(){SAFE_RELEASE(m_pTexture);
m_pd3dDevice =NULL;return S_OK;}//-----------------------------------------------------------------------------// Name: GetTextExtent()// Desc: Get the dimensions of a text string//-----------------------------------------------------------------------------
HRESULT CD3DFont::GetTextExtent(const TCHAR* strText, SIZE* pSize){if(NULL== strText ||NULL== pSize)return E_FAIL;
FLOAT fRowWidth =0.0f;
FLOAT fRowHeight =(m_fTexCoords[0][3]- m_fTexCoords[0][1])* m_dwTexHeight;
FLOAT fWidth =0.0f;
FLOAT fHeight = fRowHeight;while(*strText){
TCHAR c =*strText++;if(c ==_T('\n')){
fRowWidth =0.0f;
fHeight += fRowHeight;}if((c -32)<0||(c -32)>=128-32)continue;
FLOAT tx1 = m_fTexCoords[c -32][0];
FLOAT tx2 = m_fTexCoords[c -32][2];
fRowWidth +=(tx2 - tx1)* m_dwTexWidth -2* m_dwSpacing;if(fRowWidth > fWidth)
fWidth = fRowWidth;}
pSize->cx =(int)fWidth;
pSize->cy =(int)fHeight;return S_OK;}//-----------------------------------------------------------------------------// Name: DrawTextScaled()// Desc: Draws scaled 2D text. Note that x and y are in viewport coordinates// (ranging from -1 to +1). fXScale and fYScale are the size fraction // relative to the entire viewport. For example, a fXScale of 0.25 is// 1/8th of the screen width. This allows you to output text at a fixed// fraction of the viewport, even if the screen or window size changes.//-----------------------------------------------------------------------------
HRESULT CD3DFont::DrawTextScaled(FLOAT x, FLOAT y, FLOAT z,
FLOAT fXScale, FLOAT fYScale, DWORD dwColor,const TCHAR* strText, DWORD dwFlags){if(m_pd3dDevice ==NULL)return E_FAIL;// Set up renderstate
m_pStateBlockSaved->Capture();
m_pStateBlockDrawText->Apply();
m_pd3dDevice->SetFVF(D3DFVF_FONT2DVERTEX);
m_pd3dDevice->SetPixelShader(NULL);
m_pd3dDevice->SetStreamSource(0, m_pVB,0,sizeof(FONT2DVERTEX));// Set filter statesif(dwFlags & D3DFONT_FILTERED){
m_pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
m_pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);}
D3DVIEWPORT9 vp;
m_pd3dDevice->GetViewport(&vp);
FLOAT fLineHeight =(m_fTexCoords[0][3]- m_fTexCoords[0][1])* m_dwTexHeight;// Center the text block in the viewportif(dwFlags & D3DFONT_CENTERED_X){const TCHAR* strTextTmp = strText;float xFinal =0.0f;while(*strTextTmp){
TCHAR c =*strTextTmp++;if(c ==_T('\n'))break;// Isn't supported. if((c -32)<0||(c -32)>=128-32)continue;
FLOAT tx1 = m_fTexCoords[c -32][0];
FLOAT tx2 = m_fTexCoords[c -32][2];
FLOAT w =(tx2 - tx1)* m_dwTexWidth;
w *=(fXScale * vp.Height)/ fLineHeight;
xFinal += w -(2* m_dwSpacing)*(fXScale * vp.Height)/ fLineHeight;}
x =-xFinal / vp.Width;}if(dwFlags & D3DFONT_CENTERED_Y){
y =-fLineHeight / vp.Height;}
FLOAT sx =(x +1.0f)* vp.Width /2;
FLOAT sy =(y +1.0f)* vp.Height /2;
FLOAT sz = z;
FLOAT rhw =1.0f;// Adjust for character spacing
sx -= m_dwSpacing *(fXScale * vp.Height)/ fLineHeight;
FLOAT fStartX = sx;// Fill vertex buffer
FONT2DVERTEX* pVertices;
DWORD dwNumTriangles =0L;
m_pVB->Lock(0,0,(void**)&pVertices, D3DLOCK_DISCARD);while(*strText){
TCHAR c =*strText++;if(c ==_T('\n')){
sx = fStartX;
sy += fYScale * vp.Height;}if((c -32)<0||(c -32)>=128-32)continue;
FLOAT tx1 = m_fTexCoords[c -32][0];
FLOAT ty1 = m_fTexCoords[c -32][1];
FLOAT tx2 = m_fTexCoords[c -32][2];
FLOAT ty2 = m_fTexCoords[c -32][3];
FLOAT w =(tx2 - tx1)* m_dwTexWidth;
FLOAT h =(ty2 - ty1)* m_dwTexHeight;
w *=(fXScale * vp.Height)/ fLineHeight;
h *=(fYScale * vp.Height)/ fLineHeight;if(c !=_T(' ')){*pVertices++=InitFont2DVertex(D3DXVECTOR4(sx +0-0.5f, sy + h -0.5f, sz, rhw), dwColor, tx1, ty2);*pVertices++=InitFont2DVertex(D3DXVECTOR4(sx +0-0.5f, sy +0-0.5f, sz, rhw), dwColor, tx1, ty1);*pVertices++=InitFont2DVertex(D3DXVECTOR4(sx + w -0.5f, sy + h -0.5f, sz, rhw), dwColor, tx2, ty2);*pVertices++=InitFont2DVertex(D3DXVECTOR4(sx + w -0.5f, sy +0-0.5f, sz, rhw), dwColor, tx2, ty1);*pVertices++=InitFont2DVertex(D3DXVECTOR4(sx + w -0.5f, sy + h -0.5f, sz, rhw), dwColor, tx2, ty2);*pVertices++=InitFont2DVertex(D3DXVECTOR4(sx +0-0.5f, sy +0-0.5f, sz, rhw), dwColor, tx1, ty1);
dwNumTriangles +=2;if(dwNumTriangles *3>(MAX_NUM_VERTICES -6)){// Unlock, render, and relock the vertex buffer
m_pVB->Unlock();
m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST,0, dwNumTriangles);
m_pVB->Lock(0,0,(void**)&pVertices, D3DLOCK_DISCARD);
dwNumTriangles =0L;}}
sx += w -(2* m_dwSpacing)*(fXScale * vp.Height)/ fLineHeight;}// Unlock and render the vertex buffer
m_pVB->Unlock();if(dwNumTriangles >0)
m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST,0, dwNumTriangles);// Restore the modified renderstates
m_pStateBlockSaved->Apply();return S_OK;}//-----------------------------------------------------------------------------// Name: DrawText()// Desc: Draws 2D text. Note that sx and sy are in pixels//-----------------------------------------------------------------------------
HRESULT CD3DFont::DrawText(FLOAT sx, FLOAT sy, DWORD dwColor,const TCHAR* strText, DWORD dwFlags){if(m_pd3dDevice ==NULL)return E_FAIL;// Setup renderstate
m_pStateBlockSaved->Capture();
m_pStateBlockDrawText->Apply();
m_pd3dDevice->SetFVF(D3DFVF_FONT2DVERTEX);
m_pd3dDevice->SetPixelShader(NULL);
m_pd3dDevice->SetStreamSource(0, m_pVB,0,sizeof(FONT2DVERTEX));// Set filter statesif(dwFlags & D3DFONT_FILTERED){
m_pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
m_pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);}// Center the text block in the viewportif(dwFlags & D3DFONT_CENTERED_X){
D3DVIEWPORT9 vp;
m_pd3dDevice->GetViewport(&vp);const TCHAR* strTextTmp = strText;float xFinal =0.0f;while(*strTextTmp){
TCHAR c =*strTextTmp++;if(c ==_T('\n'))break;// Isn't supported. if((c -32)<0||(c -32)>=128-32)continue;
FLOAT tx1 = m_fTexCoords[c -32][0];
FLOAT tx2 = m_fTexCoords[c -32][2];
FLOAT w =(tx2 - tx1)* m_dwTexWidth / m_fTextScale;
xFinal += w -(2* m_dwSpacing);}
sx =(vp.Width - xFinal)/2.0f;}if(dwFlags & D3DFONT_CENTERED_Y){
D3DVIEWPORT9 vp;
m_pd3dDevice->GetViewport(&vp);float fLineHeight =((m_fTexCoords[0][3]- m_fTexCoords[0][1])* m_dwTexHeight);
sy =(vp.Height - fLineHeight)/2;}// Adjust for character spacing
sx -= m_dwSpacing;
FLOAT fStartX = sx;// Fill vertex buffer
FONT2DVERTEX* pVertices =NULL;
DWORD dwNumTriangles =0;
m_pVB->Lock(0,0,(void**)&pVertices, D3DLOCK_DISCARD);while(*strText){
TCHAR c =*strText++;if(c ==_T('\n')){
sx = fStartX;
sy +=(m_fTexCoords[0][3]- m_fTexCoords[0][1])* m_dwTexHeight;}if((c -32)<0||(c -32)>=128-32)continue;
FLOAT tx1 = m_fTexCoords[c -32][0];
FLOAT ty1 = m_fTexCoords[c -32][1];
FLOAT tx2 = m_fTexCoords[c -32][2];
FLOAT ty2 = m_fTexCoords[c -32][3];
FLOAT w =(tx2 - tx1)* m_dwTexWidth / m_fTextScale;
FLOAT h =(ty2 - ty1)* m_dwTexHeight / m_fTextScale;if(c !=_T(' ')){*pVertices++=InitFont2DVertex(D3DXVECTOR4(sx +0-0.5f, sy + h -0.5f,0.9f,1.0f), dwColor, tx1, ty2);*pVertices++=InitFont2DVertex(D3DXVECTOR4(sx +0-0.5f, sy +0-0.5f,0.9f,1.0f), dwColor, tx1, ty1);*pVertices++=InitFont2DVertex(D3DXVECTOR4(sx + w -0.5f, sy + h -0.5f,0.9f,1.0f), dwColor, tx2, ty2);*pVertices++=InitFont2DVertex(D3DXVECTOR4(sx + w -0.5f, sy +0-0.5f,0.9f,1.0f), dwColor, tx2, ty1);*pVertices++=InitFont2DVertex(D3DXVECTOR4(sx + w -0.5f, sy + h -0.5f,0.9f,1.0f), dwColor, tx2, ty2);*pVertices++=InitFont2DVertex(D3DXVECTOR4(sx +0-0.5f, sy +0-0.5f,0.9f,1.0f), dwColor, tx1, ty1);
dwNumTriangles +=2;if(dwNumTriangles *3>(MAX_NUM_VERTICES -6)){// Unlock, render, and relock the vertex buffer
m_pVB->Unlock();
m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST,0, dwNumTriangles);
pVertices =NULL;
m_pVB->Lock(0,0,(void**)&pVertices, D3DLOCK_DISCARD);
dwNumTriangles =0L;}}
sx += w -(2* m_dwSpacing);}// Unlock and render the vertex buffer
m_pVB->Unlock();if(dwNumTriangles >0)
m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST,0, dwNumTriangles);// Restore the modified renderstates
m_pStateBlockSaved->Apply();return S_OK;}//-----------------------------------------------------------------------------// Name: Render3DText()// Desc: Renders 3D text//-----------------------------------------------------------------------------
HRESULT CD3DFont::Render3DText(const TCHAR* strText, DWORD dwFlags){if(m_pd3dDevice ==NULL)return E_FAIL;// Setup renderstate
m_pStateBlockSaved->Capture();
m_pStateBlockDrawText->Apply();
m_pd3dDevice->SetFVF(D3DFVF_FONT3DVERTEX);
m_pd3dDevice->SetPixelShader(NULL);
m_pd3dDevice->SetStreamSource(0, m_pVB,0,sizeof(FONT3DVERTEX));// Set filter statesif(dwFlags & D3DFONT_FILTERED){
m_pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
m_pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);}// Position for each text element
FLOAT x =0.0f;
FLOAT y =0.0f;// Center the text block at the origin (not the viewport)if(dwFlags & D3DFONT_CENTERED_X){
SIZE sz;GetTextExtent(strText,&sz);
x =-(((FLOAT)sz.cx)/10.0f)/2.0f;}if(dwFlags & D3DFONT_CENTERED_Y){
SIZE sz;GetTextExtent(strText,&sz);
y =-(((FLOAT)sz.cy)/10.0f)/2.0f;}// Turn off culling for two-sided textif(dwFlags & D3DFONT_TWOSIDED)
m_pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);// Adjust for character spacing
x -= m_dwSpacing /10.0f;
FLOAT fStartX = x;
TCHAR c;// Fill vertex buffer
FONT3DVERTEX* pVertices;
DWORD dwNumTriangles =0L;
m_pVB->Lock(0,0,(void**)&pVertices, D3DLOCK_DISCARD);while((c =*strText++)!=0){if(c =='\n'){
x = fStartX;
y -=(m_fTexCoords[0][3]- m_fTexCoords[0][1])* m_dwTexHeight /10.0f;}if((c -32)<0||(c -32)>=128-32)continue;
FLOAT tx1 = m_fTexCoords[c -32][0];
FLOAT ty1 = m_fTexCoords[c -32][1];
FLOAT tx2 = m_fTexCoords[c -32][2];
FLOAT ty2 = m_fTexCoords[c -32][3];
FLOAT w =(tx2 - tx1)* m_dwTexWidth /(10.0f* m_fTextScale);
FLOAT h =(ty2 - ty1)* m_dwTexHeight /(10.0f* m_fTextScale);if(c !=_T(' ')){*pVertices++=InitFont3DVertex(D3DXVECTOR3(x +0, y +0,0),D3DXVECTOR3(0,0,-1), tx1, ty2);*pVertices++=InitFont3DVertex(D3DXVECTOR3(x +0, y + h,0),D3DXVECTOR3(0,0,-1), tx1, ty1);*pVertices++=InitFont3DVertex(D3DXVECTOR3(x + w, y +0,0),D3DXVECTOR3(0,0,-1), tx2, ty2);*pVertices++=InitFont3DVertex(D3DXVECTOR3(x + w, y + h,0),D3DXVECTOR3(0,0,-1), tx2, ty1);*pVertices++=InitFont3DVertex(D3DXVECTOR3(x + w, y +0,0),D3DXVECTOR3(0,0,-1), tx2, ty2);*pVertices++=InitFont3DVertex(D3DXVECTOR3(x +0, y + h,0),D3DXVECTOR3(0,0,-1), tx1, ty1);
dwNumTriangles +=2;if(dwNumTriangles *3>(MAX_NUM_VERTICES -6)){// Unlock, render, and relock the vertex buffer
m_pVB->Unlock();
m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST,0, dwNumTriangles);
m_pVB->Lock(0,0,(void**)&pVertices, D3DLOCK_DISCARD);
dwNumTriangles =0L;}}
x += w -(2* m_dwSpacing)/10.0f;}// Unlock and render the vertex buffer
m_pVB->Unlock();if(dwNumTriangles >0)
m_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST,0, dwNumTriangles);// Restore the modified renderstates
m_pStateBlockSaved->Apply();return S_OK;}d3dutil.h
#pragmaonce#include<D3D9.h>#include<D3DX9Math.h>//-----------------------------------------------------------------------------// Name: D3DUtil_InitMaterial()// Desc: Initializes a D3DMATERIAL9 structure, setting the diffuse and ambient// colors. It does not set emissive or specular colors.//-----------------------------------------------------------------------------
VOID D3DUtil_InitMaterial(D3DMATERIAL9& mtrl, FLOAT r =0.0f, FLOAT g =0.0f,
FLOAT b =0.0f, FLOAT a =1.0f);//-----------------------------------------------------------------------------// Name: D3DUtil_InitLight()// Desc: Initializes a D3DLIGHT structure, setting the light position. The// diffuse color is set to white, specular and ambient left as black.//-----------------------------------------------------------------------------
VOID D3DUtil_InitLight(D3DLIGHT9& light, D3DLIGHTTYPE ltType,
FLOAT x =0.0f, FLOAT y =0.0f, FLOAT z =0.0f);//-----------------------------------------------------------------------------// Name: D3DUtil_CreateTexture()// Desc: Helper function to create a texture. It checks the root path first,// then tries the DXSDK media path (as specified in the system registry).//-----------------------------------------------------------------------------
HRESULT D3DUtil_CreateTexture(LPDIRECT3DDEVICE9 pd3dDevice, TCHAR* strTexture,
LPDIRECT3DTEXTURE9* ppTexture,
D3DFORMAT d3dFormat = D3DFMT_UNKNOWN);//-----------------------------------------------------------------------------// Name: D3DUtil_GetCubeMapViewMatrix()// Desc: Returns a view matrix for rendering to a face of a cubemap.//-----------------------------------------------------------------------------
D3DXMATRIX D3DUtil_GetCubeMapViewMatrix(DWORD dwFace);//-----------------------------------------------------------------------------// Name: D3DUtil_GetRotationFromCursor()// Desc: Returns a quaternion for the rotation implied by the window's cursor// position.//-----------------------------------------------------------------------------
D3DXQUATERNION D3DUtil_GetRotationFromCursor(HWND hWnd,
FLOAT fTrackBallRadius =1.0f);//-----------------------------------------------------------------------------// Name: D3DUtil_SetDeviceCursor// Desc: Builds and sets a cursor for the D3D device based on hCursor.//-----------------------------------------------------------------------------
HRESULT D3DUtil_SetDeviceCursor(LPDIRECT3DDEVICE9 pd3dDevice, HCURSOR hCursor,
BOOL bAddWatermark);//-----------------------------------------------------------------------------// Name: D3DUtil_D3DFormatToString// Desc: Returns the string for the given D3DFORMAT.// bWithPrefix determines whether the string should include the "D3DFMT_"//-----------------------------------------------------------------------------
TCHAR*D3DUtil_D3DFormatToString(D3DFORMAT format,bool bWithPrefix =true);//-----------------------------------------------------------------------------// Name: class CD3DArcBall// Desc://-----------------------------------------------------------------------------classCD3DArcBall{
INT m_iWidth;// ArcBall's window width
INT m_iHeight;// ArcBall's window height
FLOAT m_fRadius;// ArcBall's radius in screen coords
FLOAT m_fRadiusTranslation;// ArcBall's radius for translating the target
D3DXQUATERNION m_qDown;// Quaternion before button down
D3DXQUATERNION m_qNow;// Composite quaternion for current drag
D3DXMATRIXA16 m_matRotation;// Matrix for arcball's orientation
D3DXMATRIXA16 m_matRotationDelta;// Matrix for arcball's orientation
D3DXMATRIXA16 m_matTranslation;// Matrix for arcball's position
D3DXMATRIXA16 m_matTranslationDelta;// Matrix for arcball's position
BOOL m_bDrag;// Whether user is dragging arcball
BOOL m_bRightHanded;// Whether to use RH coordinate system
D3DXVECTOR3 ScreenToVector(int sx,int sy);public:
LRESULT HandleMouseMessages(HWND, UINT, WPARAM, LPARAM);
D3DXMATRIX*GetRotationMatrix(){return&m_matRotation;}
D3DXMATRIX*GetRotationDeltaMatrix(){return&m_matRotationDelta;}
D3DXMATRIX*GetTranslationMatrix(){return&m_matTranslation;}
D3DXMATRIX*GetTranslationDeltaMatrix(){return&m_matTranslationDelta;}
BOOL IsBeingDragged(){return m_bDrag;}
VOID SetRadius(FLOAT fRadius);
VOID SetWindow(INT w, INT h, FLOAT r =0.9);
VOID SetRightHanded(BOOL bRightHanded){ m_bRightHanded = bRightHanded;}CD3DArcBall();
VOID Init();};//-----------------------------------------------------------------------------// Name: class CD3DCamera// Desc://-----------------------------------------------------------------------------classCD3DCamera{
D3DXVECTOR3 m_vEyePt;// Attributes for view matrix
D3DXVECTOR3 m_vLookatPt;
D3DXVECTOR3 m_vUpVec;
D3DXVECTOR3 m_vView;
D3DXVECTOR3 m_vCross;
D3DXMATRIXA16 m_matView;
D3DXMATRIXA16 m_matBillboard;// Special matrix for billboarding effects
FLOAT m_fFOV;// Attributes for projection matrix
FLOAT m_fAspect;
FLOAT m_fNearPlane;
FLOAT m_fFarPlane;
D3DXMATRIXA16 m_matProj;public:// Access functions
D3DXVECTOR3 GetEyePt(){return m_vEyePt;}
D3DXVECTOR3 GetLookatPt(){return m_vLookatPt;}
D3DXVECTOR3 GetUpVec(){return m_vUpVec;}
D3DXVECTOR3 GetViewDir(){return m_vView;}
D3DXVECTOR3 GetCross(){return m_vCross;}
FLOAT GetFOV(){return m_fFOV;}
FLOAT GetAspect(){return m_fAspect;}
FLOAT GetNearPlane(){return m_fNearPlane;}
FLOAT GetFarPlane(){return m_fFarPlane;}
D3DXMATRIX GetViewMatrix(){return m_matView;}
D3DXMATRIX GetBillboardMatrix(){return m_matBillboard;}
D3DXMATRIX GetProjMatrix(){return m_matProj;}
VOID SetViewParams(D3DXVECTOR3& vEyePt, D3DXVECTOR3& vLookatPt,
D3DXVECTOR3& vUpVec);
VOID SetProjParams(FLOAT fFOV, FLOAT fAspect, FLOAT fNearPlane,
FLOAT fFarPlane);CD3DCamera();};d3dutil.cpp
#defineSTRICT#include<Windows.h>#include<WindowsX.h>#include<tchar.h>#include<stdio.h>#include"D3DUtil.h"#include"DXUtil.h"#include"D3DX9.h"//-----------------------------------------------------------------------------// Name: D3DUtil_InitMaterial()// Desc: Initializes a D3DMATERIAL9 structure, setting the diffuse and ambient// colors. It does not set emissive or specular colors.//-----------------------------------------------------------------------------
VOID D3DUtil_InitMaterial(D3DMATERIAL9& mtrl, FLOAT r, FLOAT g, FLOAT b,
FLOAT a){ZeroMemory(&mtrl,sizeof(D3DMATERIAL9));
mtrl.Diffuse.r = mtrl.Ambient.r = r;
mtrl.Diffuse.g = mtrl.Ambient.g = g;
mtrl.Diffuse.b = mtrl.Ambient.b = b;
mtrl.Diffuse.a = mtrl.Ambient.a = a;}//-----------------------------------------------------------------------------// Name: D3DUtil_InitLight()// Desc: Initializes a D3DLIGHT structure, setting the light position. The// diffuse color is set to white; specular and ambient are left as black.//-----------------------------------------------------------------------------
VOID D3DUtil_InitLight(D3DLIGHT9& light, D3DLIGHTTYPE ltType,
FLOAT x, FLOAT y, FLOAT z){
D3DXVECTOR3 vecLightDirUnnormalized(x, y, z);ZeroMemory(&light,sizeof(D3DLIGHT9));
light.Type = ltType;
light.Diffuse.r =1.0f;
light.Diffuse.g =1.0f;
light.Diffuse.b =1.0f;D3DXVec3Normalize((D3DXVECTOR3*)&light.Direction,&vecLightDirUnnormalized);
light.Position.x = x;
light.Position.y = y;
light.Position.z = z;
light.Range =1000.0f;}//-----------------------------------------------------------------------------// Name: D3DUtil_CreateTexture()// Desc: Helper function to create a texture. It checks the root path first,// then tries the DXSDK media path (as specified in the system registry).//-----------------------------------------------------------------------------
HRESULT D3DUtil_CreateTexture(LPDIRECT3DDEVICE9 pd3dDevice, TCHAR* strTexture,
LPDIRECT3DTEXTURE9* ppTexture, D3DFORMAT d3dFormat){
HRESULT hr;
TCHAR strPath[MAX_PATH];// Get the path to the textureif(FAILED(hr =DXUtil_FindMediaFileCb(strPath,sizeof(strPath), strTexture)))return hr;// Create the texture using D3DXreturnD3DXCreateTextureFromFileEx(pd3dDevice, strPath,
D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT,0, d3dFormat,
D3DPOOL_MANAGED, D3DX_FILTER_TRIANGLE | D3DX_FILTER_MIRROR,
D3DX_FILTER_TRIANGLE | D3DX_FILTER_MIRROR,0,NULL,NULL, ppTexture);}//-----------------------------------------------------------------------------// Name: D3DUtil_GetCubeMapViewMatrix()// Desc: Returns a view matrix for rendering to a face of a cubemap.//-----------------------------------------------------------------------------
D3DXMATRIX D3DUtil_GetCubeMapViewMatrix(DWORD dwFace){
D3DXVECTOR3 vEyePt =D3DXVECTOR3(0.0f,0.0f,0.0f);
D3DXVECTOR3 vLookDir;
D3DXVECTOR3 vUpDir;switch(dwFace){case D3DCUBEMAP_FACE_POSITIVE_X:
vLookDir =D3DXVECTOR3(1.0f,0.0f,0.0f);
vUpDir =D3DXVECTOR3(0.0f,1.0f,0.0f);break;case D3DCUBEMAP_FACE_NEGATIVE_X:
vLookDir =D3DXVECTOR3(-1.0f,0.0f,0.0f);
vUpDir =D3DXVECTOR3(0.0f,1.0f,0.0f);break;case D3DCUBEMAP_FACE_POSITIVE_Y:
vLookDir =D3DXVECTOR3(0.0f,1.0f,0.0f);
vUpDir =D3DXVECTOR3(0.0f,0.0f,-1.0f);break;case D3DCUBEMAP_FACE_NEGATIVE_Y:
vLookDir =D3DXVECTOR3(0.0f,-1.0f,0.0f);
vUpDir =D3DXVECTOR3(0.0f,0.0f,1.0f);break;case D3DCUBEMAP_FACE_POSITIVE_Z:
vLookDir =D3DXVECTOR3(0.0f,0.0f,1.0f);
vUpDir =D3DXVECTOR3(0.0f,1.0f,0.0f);break;case D3DCUBEMAP_FACE_NEGATIVE_Z:
vLookDir =D3DXVECTOR3(0.0f,0.0f,-1.0f);
vUpDir =D3DXVECTOR3(0.0f,1.0f,0.0f);break;}// Set the view transform for this cubemap surface
D3DXMATRIXA16 matView;D3DXMatrixLookAtLH(&matView,&vEyePt,&vLookDir,&vUpDir);return matView;}//-----------------------------------------------------------------------------// Name: D3DUtil_GetRotationFromCursor()// Desc: Returns a quaternion for the rotation implied by the window's cursor// position.//-----------------------------------------------------------------------------
D3DXQUATERNION D3DUtil_GetRotationFromCursor(HWND hWnd,
FLOAT fTrackBallRadius){
POINT pt;
RECT rc;GetCursorPos(&pt);GetClientRect(hWnd,&rc);ScreenToClient(hWnd,&pt);
FLOAT sx =(((2.0f* pt.x)/(rc.right - rc.left))-1);
FLOAT sy =(((2.0f* pt.y)/(rc.bottom - rc.top))-1);
FLOAT sz;if(sx ==0.0f&& sy ==0.0f)returnD3DXQUATERNION(0.0f,0.0f,0.0f,1.0f);
FLOAT d2 =sqrtf(sx * sx + sy * sy);if(d2 < fTrackBallRadius *0.70710678118654752440)// Inside sphere
sz =sqrtf(fTrackBallRadius * fTrackBallRadius - d2 * d2);else// On hyperbola
sz =(fTrackBallRadius * fTrackBallRadius)/(2.0f* d2);// Get two points on trackball's sphere
D3DXVECTOR3 p1(sx, sy, sz);
D3DXVECTOR3 p2(0.0f,0.0f, fTrackBallRadius);// Get axis of rotation, which is cross product of p1 and p2
D3DXVECTOR3 vAxis;D3DXVec3Cross(&vAxis,&p1,&p2);// Calculate angle for the rotation about that axis
D3DXVECTOR3 vecDiff = p2 - p1;
FLOAT t =D3DXVec3Length(&vecDiff)/(2.0f* fTrackBallRadius);if(t >+1.0f) t =+1.0f;if(t <-1.0f) t =-1.0f;
FLOAT fAngle =2.0f*asinf(t);// Convert axis to quaternion
D3DXQUATERNION quat;D3DXQuaternionRotationAxis(&quat,&vAxis, fAngle);return quat;}//-----------------------------------------------------------------------------// Name: D3DUtil_SetDeviceCursor// Desc: Gives the D3D device a cursor with image and hotspot from hCursor.//-----------------------------------------------------------------------------
HRESULT D3DUtil_SetDeviceCursor(LPDIRECT3DDEVICE9 pd3dDevice, HCURSOR hCursor,
BOOL bAddWatermark){
HRESULT hr = E_FAIL;
ICONINFO iconinfo;
BOOL bBWCursor;
LPDIRECT3DSURFACE9 pCursorSurface =NULL;
HDC hdcColor =NULL;
HDC hdcMask =NULL;
HDC hdcScreen =NULL;
BITMAP bm;
DWORD dwWidth;
DWORD dwHeightSrc;
DWORD dwHeightDest;
COLORREF crColor;
COLORREF crMask;
UINT x;
UINT y;
BITMAPINFO bmi;
COLORREF* pcrArrayColor =NULL;
COLORREF* pcrArrayMask =NULL;
DWORD* pBitmap;
HGDIOBJ hgdiobjOld;ZeroMemory(&iconinfo,sizeof(iconinfo));if(!GetIconInfo(hCursor,&iconinfo))goto End;if(0==GetObject((HGDIOBJ)iconinfo.hbmMask,sizeof(BITMAP),(LPVOID)&bm))goto End;
dwWidth = bm.bmWidth;
dwHeightSrc = bm.bmHeight;if(iconinfo.hbmColor ==NULL){
bBWCursor = TRUE;
dwHeightDest = dwHeightSrc /2;}else{
bBWCursor = FALSE;
dwHeightDest = dwHeightSrc;}// Create a surface for the fullscreen cursorif(FAILED(hr = pd3dDevice->CreateOffscreenPlainSurface(dwWidth, dwHeightDest,
D3DFMT_A8R8G8B8, D3DPOOL_SCRATCH,&pCursorSurface,NULL))){goto End;}
pcrArrayMask =new DWORD[dwWidth * dwHeightSrc];ZeroMemory(&bmi,sizeof(bmi));
bmi.bmiHeader.biSize =sizeof(bmi.bmiHeader);
bmi.bmiHeader.biWidth = dwWidth;
bmi.bmiHeader.biHeight = dwHeightSrc;
bmi.bmiHeader.biPlanes =1;
bmi.bmiHeader.biBitCount =32;
bmi.bmiHeader.biCompression = BI_RGB;
hdcScreen =GetDC(NULL);
hdcMask =CreateCompatibleDC(hdcScreen);if(hdcMask ==NULL){
hr = E_FAIL;goto End;}
hgdiobjOld =SelectObject(hdcMask, iconinfo.hbmMask);GetDIBits(hdcMask, iconinfo.hbmMask,0, dwHeightSrc,
pcrArrayMask,&bmi, DIB_RGB_COLORS);SelectObject(hdcMask, hgdiobjOld);if(!bBWCursor){
pcrArrayColor =new DWORD[dwWidth * dwHeightDest];
hdcColor =CreateCompatibleDC(hdcScreen);if(hdcColor ==NULL){
hr = E_FAIL;goto End;}SelectObject(hdcColor, iconinfo.hbmColor);GetDIBits(hdcColor, iconinfo.hbmColor,0, dwHeightDest,
pcrArrayColor,&bmi, DIB_RGB_COLORS);}// Transfer cursor image into the surface
D3DLOCKED_RECT lr;
pCursorSurface->LockRect(&lr,NULL,0);
pBitmap =(DWORD*)lr.pBits;for(y =0; y < dwHeightDest; y++){for(x =0; x < dwWidth; x++){if(bBWCursor){
crColor = pcrArrayMask[dwWidth *(dwHeightDest -1- y)+ x];
crMask = pcrArrayMask[dwWidth *(dwHeightSrc -1- y)+ x];}else{
crColor = pcrArrayColor[dwWidth *(dwHeightDest -1- y)+ x];
crMask = pcrArrayMask[dwWidth *(dwHeightDest -1- y)+ x];}if(crMask ==0)
pBitmap[dwWidth * y + x]=0xff000000| crColor;else
pBitmap[dwWidth * y + x]=0x00000000;// It may be helpful to make the D3D cursor look slightly // different from the Windows cursor so you can distinguish // between the two when developing/testing code. When// bAddWatermark is TRUE, the following code adds some// small grey "D3D" characters to the upper-left corner of// the D3D cursor image.if(bAddWatermark && x <12&& y <5){// 11.. 11.. 11.. .... CCC0// 1.1. ..1. 1.1. .... A2A0// 1.1. .1.. 1.1. .... A4A0// 1.1. ..1. 1.1. .... A2A0// 11.. 11.. 11.. .... CCC0const WORD wMask[5]={0xccc0,0xa2a0,0xa4a0,0xa2a0,0xccc0};if(wMask[y]&(1<<(15- x))){
pBitmap[dwWidth * y + x]|=0xff808080;}}}}
pCursorSurface->UnlockRect();// Set the device cursorif(FAILED(hr = pd3dDevice->SetCursorProperties(iconinfo.xHotspot,
iconinfo.yHotspot, pCursorSurface))){goto End;}
hr = S_OK;
End:if(iconinfo.hbmMask !=NULL)DeleteObject(iconinfo.hbmMask);if(iconinfo.hbmColor !=NULL)DeleteObject(iconinfo.hbmColor);if(hdcScreen !=NULL)ReleaseDC(NULL, hdcScreen);if(hdcColor !=NULL)DeleteDC(hdcColor);if(hdcMask !=NULL)DeleteDC(hdcMask);SAFE_DELETE_ARRAY(pcrArrayColor);SAFE_DELETE_ARRAY(pcrArrayMask);SAFE_RELEASE(pCursorSurface);return hr;}//-----------------------------------------------------------------------------// Name: D3DFormatToString// Desc: Returns the string for the given D3DFORMAT.//-----------------------------------------------------------------------------
TCHAR*D3DUtil_D3DFormatToString(D3DFORMAT format,bool bWithPrefix){
TCHAR* pstr =NULL;switch(format){case D3DFMT_UNKNOWN: pstr =(TCHAR*)TEXT("D3DFMT_UNKNOWN");break;case D3DFMT_R8G8B8: pstr =(TCHAR*)TEXT("D3DFMT_R8G8B8");break;case D3DFMT_A8R8G8B8: pstr =(TCHAR*)TEXT("D3DFMT_A8R8G8B8");break;case D3DFMT_X8R8G8B8: pstr =(TCHAR*)TEXT("D3DFMT_X8R8G8B8");break;case D3DFMT_R5G6B5: pstr =(TCHAR*)TEXT("D3DFMT_R5G6B5");break;case D3DFMT_X1R5G5B5: pstr =(TCHAR*)TEXT("D3DFMT_X1R5G5B5");break;case D3DFMT_A1R5G5B5: pstr =(TCHAR*)TEXT("D3DFMT_A1R5G5B5");break;case D3DFMT_A4R4G4B4: pstr =(TCHAR*)TEXT("D3DFMT_A4R4G4B4");break;case D3DFMT_R3G3B2: pstr =(TCHAR*)TEXT("D3DFMT_R3G3B2");break;case D3DFMT_A8: pstr =(TCHAR*)TEXT("D3DFMT_A8");break;case D3DFMT_A8R3G3B2: pstr =(TCHAR*)TEXT("D3DFMT_A8R3G3B2");break;case D3DFMT_X4R4G4B4: pstr =(TCHAR*)TEXT("D3DFMT_X4R4G4B4");break;case D3DFMT_A2B10G10R10: pstr =(TCHAR*)TEXT("D3DFMT_A2B10G10R10");break;case D3DFMT_A8B8G8R8: pstr =(TCHAR*)TEXT("D3DFMT_A8B8G8R8");break;case D3DFMT_X8B8G8R8: pstr =(TCHAR*)TEXT("D3DFMT_X8B8G8R8");break;case D3DFMT_G16R16: pstr =(TCHAR*)TEXT("D3DFMT_G16R16");break;case D3DFMT_A2R10G10B10: pstr =(TCHAR*)TEXT("D3DFMT_A2R10G10B10");break;case D3DFMT_A16B16G16R16: pstr =(TCHAR*)TEXT("D3DFMT_A16B16G16R16");break;case D3DFMT_A8P8: pstr =(TCHAR*)TEXT("D3DFMT_A8P8");break;case D3DFMT_P8: pstr =(TCHAR*)TEXT("D3DFMT_P8");break;case D3DFMT_L8: pstr =(TCHAR*)TEXT("D3DFMT_L8");break;case D3DFMT_A8L8: pstr =(TCHAR*)TEXT("D3DFMT_A8L8");break;case D3DFMT_A4L4: pstr =(TCHAR*)TEXT("D3DFMT_A4L4");break;case D3DFMT_V8U8: pstr =(TCHAR*)TEXT("D3DFMT_V8U8");break;case D3DFMT_L6V5U5: pstr =(TCHAR*)TEXT("D3DFMT_L6V5U5");break;case D3DFMT_X8L8V8U8: pstr =(TCHAR*)TEXT("D3DFMT_X8L8V8U8");break;case D3DFMT_Q8W8V8U8: pstr =(TCHAR*)TEXT("D3DFMT_Q8W8V8U8");break;case D3DFMT_V16U16: pstr =(TCHAR*)TEXT("D3DFMT_V16U16");break;case D3DFMT_A2W10V10U10: pstr =(TCHAR*)TEXT("D3DFMT_A2W10V10U10");break;case D3DFMT_UYVY: pstr =(TCHAR*)TEXT("D3DFMT_UYVY");break;case D3DFMT_YUY2: pstr =(TCHAR*)TEXT("D3DFMT_YUY2");break;case D3DFMT_DXT1: pstr =(TCHAR*)TEXT("D3DFMT_DXT1");break;case D3DFMT_DXT2: pstr =(TCHAR*)TEXT("D3DFMT_DXT2");break;case D3DFMT_DXT3: pstr =(TCHAR*)TEXT("D3DFMT_DXT3");break;case D3DFMT_DXT4: pstr =(TCHAR*)TEXT("D3DFMT_DXT4");break;case D3DFMT_DXT5: pstr =(TCHAR*)TEXT("D3DFMT_DXT5");break;case D3DFMT_D16_LOCKABLE: pstr =(TCHAR*)TEXT("D3DFMT_D16_LOCKABLE");break;case D3DFMT_D32: pstr =(TCHAR*)TEXT("D3DFMT_D32");break;case D3DFMT_D15S1: pstr =(TCHAR*)TEXT("D3DFMT_D15S1");break;case D3DFMT_D24S8: pstr =(TCHAR*)TEXT("D3DFMT_D24S8");break;case D3DFMT_D24X8: pstr =(TCHAR*)TEXT("D3DFMT_D24X8");break;case D3DFMT_D24X4S4: pstr =(TCHAR*)TEXT("D3DFMT_D24X4S4");break;case D3DFMT_D16: pstr =(TCHAR*)TEXT("D3DFMT_D16");break;case D3DFMT_L16: pstr =(TCHAR*)TEXT("D3DFMT_L16");break;case D3DFMT_VERTEXDATA: pstr =(TCHAR*)TEXT("D3DFMT_VERTEXDATA");break;case D3DFMT_INDEX16: pstr =(TCHAR*)TEXT("D3DFMT_INDEX16");break;case D3DFMT_INDEX32: pstr =(TCHAR*)TEXT("D3DFMT_INDEX32");break;case D3DFMT_Q16W16V16U16: pstr =(TCHAR*)TEXT("D3DFMT_Q16W16V16U16");break;case D3DFMT_MULTI2_ARGB8: pstr =(TCHAR*)TEXT("D3DFMT_MULTI2_ARGB8");break;case D3DFMT_R16F: pstr =(TCHAR*)TEXT("D3DFMT_R16F");break;case D3DFMT_G16R16F: pstr =(TCHAR*)TEXT("D3DFMT_G16R16F");break;case D3DFMT_A16B16G16R16F: pstr =(TCHAR*)TEXT("D3DFMT_A16B16G16R16F");break;case D3DFMT_R32F: pstr =(TCHAR*)TEXT("D3DFMT_R32F");break;case D3DFMT_G32R32F: pstr =(TCHAR*)TEXT("D3DFMT_G32R32F");break;case D3DFMT_A32B32G32R32F: pstr =(TCHAR*)TEXT("D3DFMT_A32B32G32R32F");break;case D3DFMT_CxV8U8: pstr =(TCHAR*)TEXT("D3DFMT_CxV8U8");break;default: pstr =(TCHAR*)TEXT("Unknown format");break;}if(bWithPrefix ||_tcsstr(pstr,TEXT("D3DFMT_"))==NULL)return pstr;elsereturn pstr +lstrlen(TEXT("D3DFMT_"));}//-----------------------------------------------------------------------------// Name: D3DXQuaternionUnitAxisToUnitAxis2// Desc: Axis to axis quaternion double angle (no normalization)// Takes two points on unit sphere an angle THETA apart, returns// quaternion that represents a rotation around cross product by 2*THETA.//-----------------------------------------------------------------------------inline D3DXQUATERNION* WINAPI D3DXQuaternionUnitAxisToUnitAxis2(D3DXQUATERNION* pOut,const D3DXVECTOR3* pvFrom,const D3DXVECTOR3* pvTo){
D3DXVECTOR3 vAxis;D3DXVec3Cross(&vAxis, pvFrom, pvTo);// proportional to sin(theta)
pOut->x = vAxis.x;
pOut->y = vAxis.y;
pOut->z = vAxis.z;
pOut->w =D3DXVec3Dot(pvFrom, pvTo);return pOut;}//-----------------------------------------------------------------------------// Name: D3DXQuaternionAxisToAxis// Desc: Axis to axis quaternion // Takes two points on unit sphere an angle THETA apart, returns// quaternion that represents a rotation around cross product by theta.//-----------------------------------------------------------------------------inline D3DXQUATERNION* WINAPI D3DXQuaternionAxisToAxis(D3DXQUATERNION* pOut,const D3DXVECTOR3* pvFrom,const D3DXVECTOR3* pvTo){
D3DXVECTOR3 vA, vB;D3DXVec3Normalize(&vA, pvFrom);D3DXVec3Normalize(&vB, pvTo);
D3DXVECTOR3 vHalf(vA + vB);D3DXVec3Normalize(&vHalf,&vHalf);returnD3DXQuaternionUnitAxisToUnitAxis2(pOut,&vA,&vHalf);}//-----------------------------------------------------------------------------// Name:// Desc://-----------------------------------------------------------------------------CD3DArcBall::CD3DArcBall(){Init();}//-----------------------------------------------------------------------------// Name:// Desc://-----------------------------------------------------------------------------voidCD3DArcBall::Init(){D3DXQuaternionIdentity(&m_qDown);D3DXQuaternionIdentity(&m_qNow);D3DXMatrixIdentity(&m_matRotation);D3DXMatrixIdentity(&m_matRotationDelta);D3DXMatrixIdentity(&m_matTranslation);D3DXMatrixIdentity(&m_matTranslationDelta);
m_bDrag = FALSE;
m_fRadiusTranslation =1.0f;
m_bRightHanded = FALSE;}//-----------------------------------------------------------------------------// Name:// Desc://-----------------------------------------------------------------------------
VOID CD3DArcBall::SetWindow(int iWidth,int iHeight,float fRadius){// Set ArcBall info
m_iWidth = iWidth;
m_iHeight = iHeight;
m_fRadius = fRadius;}//-----------------------------------------------------------------------------// Name:// Desc://-----------------------------------------------------------------------------
D3DXVECTOR3 CD3DArcBall::ScreenToVector(int sx,int sy){// Scale to screen
FLOAT x =-(sx - m_iWidth /2)/(m_fRadius * m_iWidth /2);
FLOAT y =(sy - m_iHeight /2)/(m_fRadius * m_iHeight /2);if(m_bRightHanded){
x =-x;
y =-y;}
FLOAT z =0.0f;
FLOAT mag = x * x + y * y;if(mag >1.0f){
FLOAT scale =1.0f/sqrtf(mag);
x *= scale;
y *= scale;}else
z =sqrtf(1.0f- mag);// Return vectorreturnD3DXVECTOR3(x, y, z);}//-----------------------------------------------------------------------------// Name:// Desc://-----------------------------------------------------------------------------
VOID CD3DArcBall::SetRadius(FLOAT fRadius){
m_fRadiusTranslation = fRadius;}//-----------------------------------------------------------------------------// Name:// Desc://-----------------------------------------------------------------------------
LRESULT CD3DArcBall::HandleMouseMessages(HWND hWnd, UINT uMsg, WPARAM wParam,
LPARAM lParam){UNREFERENCED_PARAMETER(hWnd);staticint iCurMouseX;// Saved mouse positionstaticint iCurMouseY;static D3DXVECTOR3 s_vDown;// Button down vector// Current mouse positionint iMouseX =GET_X_LPARAM(lParam);int iMouseY =GET_Y_LPARAM(lParam);switch(uMsg){case WM_RBUTTONDOWN:case WM_MBUTTONDOWN:// Store off the position of the cursor when the button is pressed
iCurMouseX = iMouseX;
iCurMouseY = iMouseY;return TRUE;case WM_LBUTTONDOWN:// Start drag mode
m_bDrag = TRUE;
s_vDown =ScreenToVector(iMouseX, iMouseY);
m_qDown = m_qNow;return TRUE;case WM_LBUTTONUP:// End drag mode
m_bDrag = FALSE;return TRUE;case WM_MOUSEMOVE:// Drag objectif(MK_LBUTTON & wParam){if(m_bDrag){// recompute m_qNow
D3DXVECTOR3 vCur =ScreenToVector(iMouseX, iMouseY);
D3DXQUATERNION qAxisToAxis;D3DXQuaternionAxisToAxis(&qAxisToAxis,&s_vDown,&vCur);
m_qNow = m_qDown;
m_qNow *= qAxisToAxis;D3DXMatrixRotationQuaternion(&m_matRotationDelta,&qAxisToAxis);}elseD3DXMatrixIdentity(&m_matRotationDelta);D3DXMatrixRotationQuaternion(&m_matRotation,&m_qNow);
m_bDrag = TRUE;}elseif((MK_RBUTTON & wParam)||(MK_MBUTTON & wParam)){// Normalize based on size of window and bounding sphere radius
FLOAT fDeltaX =(iCurMouseX - iMouseX)* m_fRadiusTranslation / m_iWidth;
FLOAT fDeltaY =(iCurMouseY - iMouseY)* m_fRadiusTranslation / m_iHeight;if(wParam & MK_RBUTTON){D3DXMatrixTranslation(&m_matTranslationDelta,-2* fDeltaX,2* fDeltaY,0.0f);D3DXMatrixMultiply(&m_matTranslation,&m_matTranslation,&m_matTranslationDelta);}else// wParam & MK_MBUTTON{D3DXMatrixTranslation(&m_matTranslationDelta,0.0f,0.0f,5* fDeltaY);D3DXMatrixMultiply(&m_matTranslation,&m_matTranslation,&m_matTranslationDelta);}// Store mouse coordinate
iCurMouseX = iMouseX;
iCurMouseY = iMouseY;}return TRUE;}return FALSE;}//-----------------------------------------------------------------------------// Name:// Desc://-----------------------------------------------------------------------------CD3DCamera::CD3DCamera(){// Set attributes for the view matrix
D3DXVECTOR3 vEyePt(0.0f,0.0f,0.0f);
D3DXVECTOR3 vLookatPt(0.0f,0.0f,1.0f);
D3DXVECTOR3 vUpVec(0.0f,1.0f,0.0f);SetViewParams(vEyePt, vLookatPt, vUpVec);// Set attributes for the projection matrixSetProjParams(D3DX_PI /4,1.0f,1.0f,1000.0f);}//-----------------------------------------------------------------------------// Name:// Desc://-----------------------------------------------------------------------------
VOID CD3DCamera::SetViewParams(D3DXVECTOR3& vEyePt, D3DXVECTOR3& vLookatPt,
D3DXVECTOR3& vUpVec){// Set attributes for the view matrix
m_vEyePt = vEyePt;
m_vLookatPt = vLookatPt;
m_vUpVec = vUpVec;
D3DXVECTOR3 vDir = m_vLookatPt - m_vEyePt;D3DXVec3Normalize(&m_vView,&vDir);D3DXVec3Cross(&m_vCross,&m_vView,&m_vUpVec);D3DXMatrixLookAtLH(&m_matView,&m_vEyePt,&m_vLookatPt,&m_vUpVec);D3DXMatrixInverse(&m_matBillboard,NULL,&m_matView);
m_matBillboard._41 =0.0f;
m_matBillboard._42 =0.0f;
m_matBillboard._43 =0.0f;}//-----------------------------------------------------------------------------// Name:// Desc://-----------------------------------------------------------------------------
VOID CD3DCamera::SetProjParams(FLOAT fFOV, FLOAT fAspect, FLOAT fNearPlane,
FLOAT fFarPlane){// Set attributes for the projection matrix
m_fFOV = fFOV;
m_fAspect = fAspect;
m_fNearPlane = fNearPlane;
m_fFarPlane = fFarPlane;D3DXMatrixPerspectiveFovLH(&m_matProj, fFOV, fAspect, fNearPlane, fFarPlane);}dxutil.h
#pragmaonce//-----------------------------------------------------------------------------// Miscellaneous helper functions//-----------------------------------------------------------------------------#defineSAFE_DELETE(p){if(p){delete(p);(p)=NULL;}}#defineSAFE_DELETE_ARRAY(p){if(p){delete[](p);(p)=NULL;}}#defineSAFE_RELEASE(p){if(p){(p)->Release();(p)=NULL;}}#ifndefUNDER_CE//-----------------------------------------------------------------------------// Name: DXUtil_GetDXSDKMediaPath() and DXUtil_FindMediaFile() // Desc: Returns the DirectX SDK path, as stored in the system registry// during the SDK install.//-----------------------------------------------------------------------------
HRESULT DXUtil_GetDXSDKMediaPathCch(TCHAR* strDest,int cchDest);
HRESULT DXUtil_GetDXSDKMediaPathCb(TCHAR* szDest,int cbDest);
HRESULT DXUtil_FindMediaFileCch(TCHAR* strDestPath,int cchDest, TCHAR* strFilename);
HRESULT DXUtil_FindMediaFileCb(TCHAR* szDestPath,int cbDest, TCHAR* strFilename);#endif// !UNDER_CE//-----------------------------------------------------------------------------// Name: DXUtil_Read*RegKey() and DXUtil_Write*RegKey()// Desc: Helper functions to read/write a string registry key //-----------------------------------------------------------------------------
HRESULT DXUtil_WriteStringRegKey(HKEY hKey, TCHAR* strRegName, TCHAR* strValue);
HRESULT DXUtil_WriteIntRegKey(HKEY hKey, TCHAR* strRegName, DWORD dwValue);
HRESULT DXUtil_WriteGuidRegKey(HKEY hKey, TCHAR* strRegName, GUID guidValue);
HRESULT DXUtil_WriteBoolRegKey(HKEY hKey, TCHAR* strRegName, BOOL bValue);
HRESULT DXUtil_ReadStringRegKeyCch(HKEY hKey, TCHAR* strRegName, TCHAR* strDest, DWORD cchDest, TCHAR* strDefault);
HRESULT DXUtil_ReadStringRegKeyCb(HKEY hKey, TCHAR* strRegName, TCHAR* strDest, DWORD cbDest, TCHAR* strDefault);
HRESULT DXUtil_ReadIntRegKey(HKEY hKey, TCHAR* strRegName, DWORD* pdwValue, DWORD dwDefault);
HRESULT DXUtil_ReadGuidRegKey(HKEY hKey, TCHAR* strRegName, GUID* pGuidValue, GUID& guidDefault);
HRESULT DXUtil_ReadBoolRegKey(HKEY hKey, TCHAR* strRegName, BOOL* pbValue, BOOL bDefault);//-----------------------------------------------------------------------------// Name: DXUtil_Timer()// Desc: Performs timer opertations. Use the following commands:// TIMER_RESET - to reset the timer// TIMER_START - to start the timer// TIMER_STOP - to stop (or pause) the timer// TIMER_ADVANCE - to advance the timer by 0.1 seconds// TIMER_GETABSOLUTETIME - to get the absolute system time// TIMER_GETAPPTIME - to get the current time// TIMER_GETELAPSEDTIME - to get the time that elapsed between // TIMER_GETELAPSEDTIME calls//-----------------------------------------------------------------------------enumTIMER_COMMAND{
TIMER_RESET, TIMER_START, TIMER_STOP, TIMER_ADVANCE,
TIMER_GETABSOLUTETIME, TIMER_GETAPPTIME, TIMER_GETELAPSEDTIME
};
FLOAT __stdcall DXUtil_Timer(TIMER_COMMAND command);//-----------------------------------------------------------------------------// UNICODE support for converting between CHAR, TCHAR, and WCHAR strings//-----------------------------------------------------------------------------
HRESULT DXUtil_ConvertAnsiStringToWideCch(WCHAR* wstrDestination,const CHAR* strSource,int cchDestChar);
HRESULT DXUtil_ConvertWideStringToAnsiCch(CHAR* strDestination,const WCHAR* wstrSource,int cchDestChar);
HRESULT DXUtil_ConvertGenericStringToAnsiCch(CHAR* strDestination,const TCHAR* tstrSource,int cchDestChar);
HRESULT DXUtil_ConvertGenericStringToWideCch(WCHAR* wstrDestination,const TCHAR* tstrSource,int cchDestChar);
HRESULT DXUtil_ConvertAnsiStringToGenericCch(TCHAR* tstrDestination,const CHAR* strSource,int cchDestChar);
HRESULT DXUtil_ConvertWideStringToGenericCch(TCHAR* tstrDestination,const WCHAR* wstrSource,int cchDestChar);
HRESULT DXUtil_ConvertAnsiStringToWideCb(WCHAR* wstrDestination,const CHAR* strSource,int cbDestChar);
HRESULT DXUtil_ConvertWideStringToAnsiCb(CHAR* strDestination,const WCHAR* wstrSource,int cbDestChar);
HRESULT DXUtil_ConvertGenericStringToAnsiCb(CHAR* strDestination,const TCHAR* tstrSource,int cbDestChar);
HRESULT DXUtil_ConvertGenericStringToWideCb(WCHAR* wstrDestination,const TCHAR* tstrSource,int cbDestChar);
HRESULT DXUtil_ConvertAnsiStringToGenericCb(TCHAR* tstrDestination,const CHAR* strSource,int cbDestChar);
HRESULT DXUtil_ConvertWideStringToGenericCb(TCHAR* tstrDestination,const WCHAR* wstrSource,int cbDestChar);//-----------------------------------------------------------------------------// Readme functions//-----------------------------------------------------------------------------
VOID DXUtil_LaunchReadme(HWND hWnd, TCHAR* strLoc =NULL);//-----------------------------------------------------------------------------// GUID to String converting //-----------------------------------------------------------------------------
HRESULT DXUtil_ConvertGUIDToStringCch(const GUID* pGuidSrc, TCHAR* strDest,int cchDestChar);
HRESULT DXUtil_ConvertGUIDToStringCb(const GUID* pGuidSrc, TCHAR* strDest,int cbDestChar);
HRESULT DXUtil_ConvertStringToGUID(const TCHAR* strIn, GUID* pGuidOut);//-----------------------------------------------------------------------------// Debug printing support// See dxerr9.h for more debug printing support//-----------------------------------------------------------------------------
VOID DXUtil_Trace(TCHAR* strMsg,...);#ifdefined(DEBUG)|defined(_DEBUG)#defineDXTRACEDXUtil_Trace#else#defineDXTRACEsizeof#endif//-----------------------------------------------------------------------------// Name: ArrayListType// Desc: Indicates how data should be stored in a CArrayList//-----------------------------------------------------------------------------enumArrayListType{
AL_VALUE,// entry data is copied into the list
AL_REFERENCE,// entry pointers are copied into the list};//-----------------------------------------------------------------------------// Name: CArrayList// Desc: A growable array//-----------------------------------------------------------------------------classCArrayList{protected:
ArrayListType m_ArrayListType;void* m_pData;
UINT m_BytesPerEntry;
UINT m_NumEntries;
UINT m_NumEntriesAllocated;public:CArrayList(ArrayListType Type, UINT BytesPerEntry =0);~CArrayList(void);
HRESULT Add(void* pEntry);voidRemove(UINT Entry);void*GetPtr(UINT Entry);
UINT Count(void){return m_NumEntries;}boolContains(void* pEntryData);voidClear(void){ m_NumEntries =0;}};//-----------------------------------------------------------------------------// WinCE build support//-----------------------------------------------------------------------------#ifdefUNDER_CE#defineCheckDlgButton(hdialog, id, state)::SendMessage(::GetDlgItem(hdialog, id), BM_SETCHECK, state,0)#defineIsDlgButtonChecked(hdialog, id)::SendMessage(::GetDlgItem(hdialog, id), BM_GETCHECK,0L,0L)#defineGETTIMESTAMPGetTickCount#define_TWINCE(x)_T(x)
__inline intGetScrollPos(HWND hWnd,int nBar){
SCROLLINFO si;memset(&si,0,sizeof(si));
si.cbSize =sizeof(si);
si.fMask = SIF_POS;if(!GetScrollInfo(hWnd, nBar,&si)){return0;}else{return si.nPos;}}#else// !UNDER_CE#defineGETTIMESTAMPtimeGetTime#define_TWINCE(x) x#endif// UNDER_CEdxutil.cpp
//-----------------------------------------------------------------------------// File: DXUtil.cpp//// Desc: Shortcut macros and functions for using DX objects//// Copyright (c) Microsoft Corporation. All rights reserved//-----------------------------------------------------------------------------#ifndefSTRICT#defineSTRICT#endif// !STRICT#include<windows.h>#include<mmsystem.h>#include<tchar.h>#include<stdio.h>#include<stdarg.h>#include"DXUtil.h"#ifdefUNICODEtypedefHINSTANCE(WINAPI* LPShellExecute)(HWND hwnd, LPCWSTR lpOperation, LPCWSTR lpFile, LPCWSTR lpParameters, LPCWSTR lpDirectory, INT nShowCmd);#elsetypedefHINSTANCE(WINAPI* LPShellExecute)(HWND hwnd, LPCSTR lpOperation, LPCSTR lpFile, LPCSTR lpParameters, LPCSTR lpDirectory, INT nShowCmd);#endif#ifndefUNDER_CE//-----------------------------------------------------------------------------// Name: DXUtil_GetDXSDKMediaPathCch()// Desc: Returns the DirectX SDK media path// cchDest is the size in TCHARs of strDest. Be careful not to // pass in sizeof(strDest) on UNICODE builds.//-----------------------------------------------------------------------------
HRESULT DXUtil_GetDXSDKMediaPathCch(TCHAR* strDest,int cchDest){if(strDest ==NULL|| cchDest <1)return E_INVALIDARG;lstrcpy(strDest,TEXT(""));// Open the appropriate registry key
HKEY hKey;
LONG lResult =RegOpenKeyEx(HKEY_LOCAL_MACHINE,_T("Software\\Microsoft\\DirectX SDK"),0, KEY_READ,&hKey);if(ERROR_SUCCESS != lResult)return E_FAIL;
DWORD dwType;
DWORD dwSize = cchDest *sizeof(TCHAR);
lResult =RegQueryValueEx(hKey,_T("DX9SDK Samples Path"),NULL,&dwType,(BYTE*)strDest,&dwSize);
strDest[cchDest -1]=0;// RegQueryValueEx doesn't NULL term if buffer too smallRegCloseKey(hKey);if(ERROR_SUCCESS != lResult)return E_FAIL;const TCHAR* strMedia =_T("\\Media\\");if(lstrlen(strDest)+lstrlen(strMedia)< cchDest)_tcscat_s(strDest, cchDest, strMedia);elsereturn E_INVALIDARG;return S_OK;}#endif// !UNDER_CE#ifndefUNDER_CE//-----------------------------------------------------------------------------// Name: DXUtil_FindMediaFileCch()// Desc: Returns a valid path to a DXSDK media file// cchDest is the size in TCHARs of strDestPath. Be careful not to // pass in sizeof(strDest) on UNICODE builds.//-----------------------------------------------------------------------------
HRESULT DXUtil_FindMediaFileCch(TCHAR* strDestPath,int cchDest, TCHAR* strFilename){
HRESULT hr;
HANDLE file;
TCHAR* strShortNameTmp =NULL;
TCHAR strShortName[MAX_PATH];int cchPath;if(NULL== strFilename ||NULL== strDestPath || cchDest <1)return E_INVALIDARG;lstrcpy(strDestPath,TEXT(""));lstrcpy(strShortName,TEXT(""));// Build full path name from strFileName (strShortName will be just the leaf filename)
cchPath =GetFullPathName(strFilename, cchDest, strDestPath,&strShortNameTmp);if((cchPath ==0)||(cchDest <= cchPath))return E_FAIL;if(strShortNameTmp)lstrcpyn(strShortName, strShortNameTmp, MAX_PATH);// first try to find the filename given a full path
file =CreateFile(strDestPath, GENERIC_READ, FILE_SHARE_READ,NULL,
OPEN_EXISTING,0,NULL);if(INVALID_HANDLE_VALUE != file){CloseHandle(file);return S_OK;}// next try to find the filename in the current working directory (path stripped)
file =CreateFile(strShortName, GENERIC_READ, FILE_SHARE_READ,NULL,
OPEN_EXISTING,0,NULL);if(INVALID_HANDLE_VALUE != file){_tcsncpy_s(strDestPath, cchDest, strShortName, cchDest);
strDestPath[cchDest -1]=0;// _tcsncpy doesn't NULL term if it runs out of spaceCloseHandle(file);return S_OK;}// last, check if the file exists in the media directoryif(FAILED(hr =DXUtil_GetDXSDKMediaPathCch(strDestPath, cchDest)))return hr;if(lstrlen(strDestPath)+lstrlen(strShortName)< cchDest)lstrcat(strDestPath, strShortName);elsereturn E_INVALIDARG;
file =CreateFile(strDestPath, GENERIC_READ, FILE_SHARE_READ,NULL,
OPEN_EXISTING,0,NULL);if(INVALID_HANDLE_VALUE != file){CloseHandle(file);return S_OK;}// On failure, just return the file as the path_tcsncpy_s(strDestPath, cchDest, strFilename, cchDest);
strDestPath[cchDest -1]=0;// _tcsncpy doesn't NULL term if it runs out of spacereturnHRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);}#endif// !UNDER_CE//-----------------------------------------------------------------------------// Name: DXUtil_ReadStringRegKeyCch()// Desc: Helper function to read a registry key string// cchDest is the size in TCHARs of strDest. Be careful not to // pass in sizeof(strDest) on UNICODE builds.//-----------------------------------------------------------------------------
HRESULT DXUtil_ReadStringRegKeyCch(HKEY hKey, TCHAR* strRegName, TCHAR* strDest,
DWORD cchDest, TCHAR* strDefault){
DWORD dwType;
DWORD cbDest = cchDest *sizeof(TCHAR);if(ERROR_SUCCESS !=RegQueryValueEx(hKey, strRegName,0,&dwType,(BYTE*)strDest,&cbDest)){_tcsncpy_s(strDest, cchDest, strDefault, cchDest);
strDest[cchDest -1]=0;if(dwType != REG_SZ)return E_FAIL;return S_OK;}return E_FAIL;}//-----------------------------------------------------------------------------// Name: DXUtil_WriteStringRegKey()// Desc: Helper function to write a registry key string//-----------------------------------------------------------------------------
HRESULT DXUtil_WriteStringRegKey(HKEY hKey, TCHAR* strRegName,
TCHAR* strValue){if(NULL== strValue)return E_INVALIDARG;
DWORD cbValue =((DWORD)_tcslen(strValue)+1)*sizeof(TCHAR);if(ERROR_SUCCESS !=RegSetValueEx(hKey, strRegName,0, REG_SZ,(BYTE*)strValue, cbValue))return E_FAIL;return S_OK;}//-----------------------------------------------------------------------------// Name: DXUtil_ReadIntRegKey()// Desc: Helper function to read a registry key int//-----------------------------------------------------------------------------
HRESULT DXUtil_ReadIntRegKey(HKEY hKey, TCHAR* strRegName, DWORD* pdwDest,
DWORD dwDefault){
DWORD dwType;
DWORD dwLength =sizeof(DWORD);if(ERROR_SUCCESS !=RegQueryValueEx(hKey, strRegName,0,&dwType,(BYTE*)pdwDest,&dwLength)){*pdwDest = dwDefault;if(dwType != REG_DWORD)return E_FAIL;return S_OK;}return E_FAIL;}//-----------------------------------------------------------------------------// Name: DXUtil_WriteIntRegKey()// Desc: Helper function to write a registry key int//-----------------------------------------------------------------------------
HRESULT DXUtil_WriteIntRegKey(HKEY hKey, TCHAR* strRegName, DWORD dwValue){if(ERROR_SUCCESS !=RegSetValueEx(hKey, strRegName,0, REG_DWORD,(BYTE*)&dwValue,sizeof(DWORD)))return E_FAIL;return S_OK;}//-----------------------------------------------------------------------------// Name: DXUtil_ReadBoolRegKey()// Desc: Helper function to read a registry key BOOL//-----------------------------------------------------------------------------
HRESULT DXUtil_ReadBoolRegKey(HKEY hKey, TCHAR* strRegName, BOOL* pbDest,
BOOL bDefault){
DWORD dwType;
DWORD dwLength =sizeof(BOOL);if(ERROR_SUCCESS !=RegQueryValueEx(hKey, strRegName,0,&dwType,(BYTE*)pbDest,&dwLength)){*pbDest = bDefault;if(dwType != REG_DWORD)return E_FAIL;return S_OK;}return E_FAIL;}//-----------------------------------------------------------------------------// Name: DXUtil_WriteBoolRegKey()// Desc: Helper function to write a registry key BOOL//-----------------------------------------------------------------------------
HRESULT DXUtil_WriteBoolRegKey(HKEY hKey, TCHAR* strRegName, BOOL bValue){if(ERROR_SUCCESS !=RegSetValueEx(hKey, strRegName,0, REG_DWORD,(BYTE*)&bValue,sizeof(BOOL)))return E_FAIL;return S_OK;}//-----------------------------------------------------------------------------// Name: DXUtil_ReadGuidRegKey()// Desc: Helper function to read a registry key guid//-----------------------------------------------------------------------------
HRESULT DXUtil_ReadGuidRegKey(HKEY hKey, TCHAR* strRegName, GUID* pGuidDest,
GUID& guidDefault){
DWORD dwType;
DWORD dwLength =sizeof(GUID);if(ERROR_SUCCESS !=RegQueryValueEx(hKey, strRegName,0,&dwType,(LPBYTE)pGuidDest,&dwLength)){*pGuidDest = guidDefault;if(dwType != REG_BINARY)return E_FAIL;return S_OK;}return E_FAIL;}//-----------------------------------------------------------------------------// Name: DXUtil_WriteGuidRegKey()// Desc: Helper function to write a registry key guid//-----------------------------------------------------------------------------
HRESULT DXUtil_WriteGuidRegKey(HKEY hKey, TCHAR* strRegName, GUID guidValue){if(ERROR_SUCCESS !=RegSetValueEx(hKey, strRegName,0, REG_BINARY,(BYTE*)&guidValue,sizeof(GUID)))return E_FAIL;return S_OK;}//-----------------------------------------------------------------------------// Name: DXUtil_Timer()// Desc: Performs timer opertations. Use the following commands:// TIMER_RESET - to reset the timer// TIMER_START - to start the timer// TIMER_STOP - to stop (or pause) the timer// TIMER_ADVANCE - to advance the timer by 0.1 seconds// TIMER_GETABSOLUTETIME - to get the absolute system time// TIMER_GETAPPTIME - to get the current time// TIMER_GETELAPSEDTIME - to get the time that elapsed between // TIMER_GETELAPSEDTIME calls//-----------------------------------------------------------------------------
FLOAT __stdcall DXUtil_Timer(TIMER_COMMAND command){static BOOL m_bTimerInitialized = FALSE;static BOOL m_bUsingQPF = FALSE;static BOOL m_bTimerStopped = TRUE;static LONGLONG m_llQPFTicksPerSec =0;// Initialize the timerif(FALSE == m_bTimerInitialized){
m_bTimerInitialized = TRUE;// Use QueryPerformanceFrequency() to get frequency of timer. If QPF is// not supported, we will timeGetTime() which returns milliseconds.
LARGE_INTEGER qwTicksPerSec;
m_bUsingQPF =QueryPerformanceFrequency(&qwTicksPerSec);if(m_bUsingQPF)
m_llQPFTicksPerSec = qwTicksPerSec.QuadPart;}if(m_bUsingQPF){static LONGLONG m_llStopTime =0;static LONGLONG m_llLastElapsedTime =0;static LONGLONG m_llBaseTime =0;double fTime;double fElapsedTime;
LARGE_INTEGER qwTime;// Get either the current time or the stop time, depending// on whether we're stopped and what command was sentif(m_llStopTime !=0&& command != TIMER_START && command != TIMER_GETABSOLUTETIME)
qwTime.QuadPart = m_llStopTime;elseQueryPerformanceCounter(&qwTime);// Return the elapsed timeif(command == TIMER_GETELAPSEDTIME){
fElapsedTime =(double)(qwTime.QuadPart - m_llLastElapsedTime)/(double)m_llQPFTicksPerSec;
m_llLastElapsedTime = qwTime.QuadPart;return(FLOAT)fElapsedTime;}// Return the current timeif(command == TIMER_GETAPPTIME){double fAppTime =(double)(qwTime.QuadPart - m_llBaseTime)/(double)m_llQPFTicksPerSec;return(FLOAT)fAppTime;}// Reset the timerif(command == TIMER_RESET){
m_llBaseTime = qwTime.QuadPart;
m_llLastElapsedTime = qwTime.QuadPart;
m_llStopTime =0;
m_bTimerStopped = FALSE;return0.0f;}// Start the timerif(command == TIMER_START){if(m_bTimerStopped)
m_llBaseTime += qwTime.QuadPart - m_llStopTime;
m_llStopTime =0;
m_llLastElapsedTime = qwTime.QuadPart;
m_bTimerStopped = FALSE;return0.0f;}// Stop the timerif(command == TIMER_STOP){if(!m_bTimerStopped){
m_llStopTime = qwTime.QuadPart;
m_llLastElapsedTime = qwTime.QuadPart;
m_bTimerStopped = TRUE;}return0.0f;}// Advance the timer by 1/10th secondif(command == TIMER_ADVANCE){
m_llStopTime += m_llQPFTicksPerSec /10;return0.0f;}if(command == TIMER_GETABSOLUTETIME){
fTime = qwTime.QuadPart /(double)m_llQPFTicksPerSec;return(FLOAT)fTime;}return-1.0f;// Invalid command specified}else{// Get the time using timeGetTime()staticdouble m_fLastElapsedTime =0.0;staticdouble m_fBaseTime =0.0;staticdouble m_fStopTime =0.0;double fTime;double fElapsedTime;// Get either the current time or the stop time, depending// on whether we're stopped and what command was sentif(m_fStopTime !=0.0&& command != TIMER_START && command != TIMER_GETABSOLUTETIME)
fTime = m_fStopTime;else
fTime =GETTIMESTAMP()*0.001;// Return the elapsed timeif(command == TIMER_GETELAPSEDTIME){
fElapsedTime =(double)(fTime - m_fLastElapsedTime);
m_fLastElapsedTime = fTime;return(FLOAT)fElapsedTime;}// Return the current timeif(command == TIMER_GETAPPTIME){return(FLOAT)(fTime - m_fBaseTime);}// Reset the timerif(command == TIMER_RESET){
m_fBaseTime = fTime;
m_fLastElapsedTime = fTime;
m_fStopTime =0;
m_bTimerStopped = FALSE;return0.0f;}// Start the timerif(command == TIMER_START){if(m_bTimerStopped)
m_fBaseTime += fTime - m_fStopTime;
m_fStopTime =0.0f;
m_fLastElapsedTime = fTime;
m_bTimerStopped = FALSE;return0.0f;}// Stop the timerif(command == TIMER_STOP){if(!m_bTimerStopped){
m_fStopTime = fTime;
m_fLastElapsedTime = fTime;
m_bTimerStopped = TRUE;}return0.0f;}// Advance the timer by 1/10th secondif(command == TIMER_ADVANCE){
m_fStopTime +=0.1f;return0.0f;}if(command == TIMER_GETABSOLUTETIME){return(FLOAT)fTime;}return-1.0f;// Invalid command specified}}//-----------------------------------------------------------------------------// Name: DXUtil_ConvertAnsiStringToWideCch()// Desc: This is a UNICODE conversion utility to convert a CHAR string into a// WCHAR string. // cchDestChar is the size in TCHARs of wstrDestination. Be careful not to // pass in sizeof(strDest) //-----------------------------------------------------------------------------
HRESULT DXUtil_ConvertAnsiStringToWideCch(WCHAR* wstrDestination,const CHAR* strSource,int cchDestChar){if(wstrDestination ==NULL|| strSource ==NULL|| cchDestChar <1)return E_INVALIDARG;int nResult =MultiByteToWideChar(CP_ACP,0, strSource,-1,
wstrDestination, cchDestChar);
wstrDestination[cchDestChar -1]=0;if(nResult ==0)return E_FAIL;return S_OK;}//-----------------------------------------------------------------------------// Name: DXUtil_ConvertWideStringToAnsi()// Desc: This is a UNICODE conversion utility to convert a WCHAR string into a// CHAR string. // cchDestChar is the size in TCHARs of strDestination//-----------------------------------------------------------------------------
HRESULT DXUtil_ConvertWideStringToAnsiCch(CHAR* strDestination,const WCHAR* wstrSource,int cchDestChar){if(strDestination ==NULL|| wstrSource ==NULL|| cchDestChar <1)return E_INVALIDARG;int nResult =WideCharToMultiByte(CP_ACP,0, wstrSource,-1, strDestination,
cchDestChar *sizeof(CHAR),NULL,NULL);
strDestination[cchDestChar -1]=0;if(nResult ==0)return E_FAIL;return S_OK;}//-----------------------------------------------------------------------------// Name: DXUtil_ConvertGenericStringToAnsi()// Desc: This is a UNICODE conversion utility to convert a TCHAR string into a// CHAR string. // cchDestChar is the size in TCHARs of strDestination//-----------------------------------------------------------------------------
HRESULT DXUtil_ConvertGenericStringToAnsiCch(CHAR* strDestination,const TCHAR* tstrSource,int cchDestChar){if(strDestination ==NULL|| tstrSource ==NULL|| cchDestChar <1)return E_INVALIDARG;#ifdef_UNICODEreturnDXUtil_ConvertWideStringToAnsiCch(strDestination, tstrSource, cchDestChar);#elsestrncpy_s(strDestination, cchDestChar, tstrSource, cchDestChar);
strDestination[cchDestChar -1]='\0';return S_OK;#endif}//-----------------------------------------------------------------------------// Name: DXUtil_ConvertGenericStringToWide()// Desc: This is a UNICODE conversion utility to convert a TCHAR string into a// WCHAR string. // cchDestChar is the size in TCHARs of wstrDestination. Be careful not to // pass in sizeof(strDest) //-----------------------------------------------------------------------------
HRESULT DXUtil_ConvertGenericStringToWideCch(WCHAR* wstrDestination,const TCHAR* tstrSource,int cchDestChar){if(wstrDestination ==NULL|| tstrSource ==NULL|| cchDestChar <1)return E_INVALIDARG;#ifdef_UNICODEwcsncpy(wstrDestination, tstrSource, cchDestChar);
wstrDestination[cchDestChar -1]= L'\0';return S_OK;#elsereturnDXUtil_ConvertAnsiStringToWideCch(wstrDestination, tstrSource, cchDestChar);#endif}//-----------------------------------------------------------------------------// Name: DXUtil_ConvertAnsiStringToGeneric()// Desc: This is a UNICODE conversion utility to convert a CHAR string into a// TCHAR string. // cchDestChar is the size in TCHARs of tstrDestination. Be careful not to // pass in sizeof(strDest) on UNICODE builds//-----------------------------------------------------------------------------
HRESULT DXUtil_ConvertAnsiStringToGenericCch(TCHAR* tstrDestination,const CHAR* strSource,int cchDestChar){if(tstrDestination ==NULL|| strSource ==NULL|| cchDestChar <1)return E_INVALIDARG;#ifdef_UNICODEreturnDXUtil_ConvertAnsiStringToWideCch(tstrDestination, strSource, cchDestChar);#elsestrncpy_s(tstrDestination, cchDestChar, strSource, cchDestChar);
tstrDestination[cchDestChar -1]='\0';return S_OK;#endif}//-----------------------------------------------------------------------------// Name: DXUtil_ConvertAnsiStringToGeneric()// Desc: This is a UNICODE conversion utility to convert a WCHAR string into a// TCHAR string. // cchDestChar is the size in TCHARs of tstrDestination. Be careful not to // pass in sizeof(strDest) on UNICODE builds//-----------------------------------------------------------------------------
HRESULT DXUtil_ConvertWideStringToGenericCch(TCHAR* tstrDestination,const WCHAR* wstrSource,int cchDestChar){if(tstrDestination ==NULL|| wstrSource ==NULL|| cchDestChar <1)return E_INVALIDARG;#ifdef_UNICODEwcsncpy(tstrDestination, wstrSource, cchDestChar);
tstrDestination[cchDestChar -1]= L'\0';return S_OK;#elsereturnDXUtil_ConvertWideStringToAnsiCch(tstrDestination, wstrSource, cchDestChar);#endif}//-----------------------------------------------------------------------------// Name: DXUtil_LaunchReadme()// Desc: Finds and opens the readme.txt for this sample//-----------------------------------------------------------------------------
VOID DXUtil_LaunchReadme(HWND hWnd, TCHAR* strLoc){#ifdefUNDER_CE// This is not available on PocketPCMessageBox(hWnd,TEXT("For operating instructions, please open the ")TEXT("readme.txt file included with the project."),TEXT("DirectX SDK Sample"), MB_ICONWARNING | MB_OK);return;#elsebool bSuccess =false;bool bFound =false;
TCHAR strReadmePath[1024];
TCHAR strExeName[MAX_PATH];
TCHAR strExePath[MAX_PATH];
TCHAR strSamplePath[MAX_PATH];
TCHAR* strLastSlash =NULL;lstrcpy(strReadmePath,TEXT(""));lstrcpy(strExePath,TEXT(""));lstrcpy(strExeName,TEXT(""));lstrcpy(strSamplePath,TEXT(""));// If the user provided a location for the readme, check there first.if(strLoc){
HKEY hKey;
LONG lResult =RegOpenKeyEx(HKEY_LOCAL_MACHINE,_T("Software\\Microsoft\\DirectX SDK"),0, KEY_READ,&hKey);if(ERROR_SUCCESS == lResult){
DWORD dwType;
DWORD dwSize = MAX_PATH *sizeof(TCHAR);
lResult =RegQueryValueEx(hKey,_T("DX9SDK Samples Path"),NULL,&dwType,(BYTE*)strSamplePath,&dwSize);
strSamplePath[MAX_PATH -1]=0;// RegQueryValueEx doesn't NULL term if buffer too smallif(ERROR_SUCCESS == lResult){_sntprintf_s(strReadmePath,1023,TEXT("%s\\C++\\%s\\readme.txt"),
strSamplePath, strLoc);
strReadmePath[1023]=0;if(GetFileAttributes(strReadmePath)!=0xFFFFFFFF)
bFound = TRUE;}}RegCloseKey(hKey);}// Get the exe name, and exe pathGetModuleFileName(NULL, strExePath, MAX_PATH);
strExePath[MAX_PATH -1]=0;
strLastSlash =_tcsrchr(strExePath,TEXT('\\'));if(strLastSlash){_tcsncpy_s(strExeName,&strLastSlash[1], MAX_PATH);
strExeName[MAX_PATH -1]=0;// Chop the exe name from the exe path*strLastSlash =0;// Chop the .exe from the exe name
strLastSlash =_tcsrchr(strExeName,TEXT('.'));if(strLastSlash)*strLastSlash =0;}if(!bFound){// Search in "%EXE_DIR%\..\%EXE_NAME%". This matchs the DirectX SDK layout_tcscpy_s(strReadmePath, strExePath);
strLastSlash =_tcsrchr(strReadmePath,TEXT('\\'));if(strLastSlash)*strLastSlash =0;lstrcat(strReadmePath,TEXT("\\"));lstrcat(strReadmePath, strExeName);lstrcat(strReadmePath,TEXT("\\readme.txt"));if(GetFileAttributes(strReadmePath)!=0xFFFFFFFF)
bFound = TRUE;}if(!bFound){// Search in "%EXE_DIR%\"_tcscpy_s(strReadmePath, strExePath);lstrcat(strReadmePath,TEXT("\\readme.txt"));if(GetFileAttributes(strReadmePath)!=0xFFFFFFFF)
bFound = TRUE;}if(!bFound){// Search in "%EXE_DIR%\.."_tcscpy_s(strReadmePath, strExePath);
strLastSlash =_tcsrchr(strReadmePath,TEXT('\\'));if(strLastSlash)*strLastSlash =0;lstrcat(strReadmePath,TEXT("\\readme.txt"));if(GetFileAttributes(strReadmePath)!=0xFFFFFFFF)
bFound = TRUE;}if(!bFound){// Search in "%EXE_DIR%\..\.."_tcscpy_s(strReadmePath, strExePath);
strLastSlash =_tcsrchr(strReadmePath,TEXT('\\'));if(strLastSlash)*strLastSlash =0;
strLastSlash =_tcsrchr(strReadmePath,TEXT('\\'));if(strLastSlash)*strLastSlash =0;lstrcat(strReadmePath,TEXT("\\readme.txt"));if(GetFileAttributes(strReadmePath)!=0xFFFFFFFF)
bFound = TRUE;}if(bFound){// GetProcAddress for ShellExecute, so we don't have to include shell32.lib // in every project that uses dxutil.cpp
LPShellExecute pShellExecute =NULL;
HINSTANCE hInstShell32 =LoadLibrary(TEXT("shell32.dll"));if(hInstShell32 !=NULL){#ifdefUNICODE
pShellExecute =(LPShellExecute)GetProcAddress(hInstShell32,_TWINCE("ShellExecuteW"));#else
pShellExecute =(LPShellExecute)GetProcAddress(hInstShell32,_TWINCE("ShellExecuteA"));#endifif(pShellExecute !=NULL){if(pShellExecute(hWnd,TEXT("open"), strReadmePath,NULL,NULL, SW_SHOW)>(HINSTANCE)32)
bSuccess =true;}FreeLibrary(hInstShell32);}}if(!bSuccess){// Tell the user that the readme couldn't be openedMessageBox(hWnd,TEXT("Could not find readme.txt"),TEXT("DirectX SDK Sample"), MB_ICONWARNING | MB_OK);}#endif// UNDER_CE}//-----------------------------------------------------------------------------// Name: DXUtil_Trace()// Desc: Outputs to the debug stream a formatted string with a variable-// argument list.//-----------------------------------------------------------------------------
VOID DXUtil_Trace(TCHAR* strMsg,...){#ifdefined(DEBUG)|defined(_DEBUG)
TCHAR strBuffer[512];
va_list args;va_start(args, strMsg);_vsntprintf_s(strBuffer,512, strMsg, args);va_end(args);OutputDebugString(strBuffer);#elseUNREFERENCED_PARAMETER(strMsg);#endif}//-----------------------------------------------------------------------------// Name: DXUtil_ConvertStringToGUID()// Desc: Converts a string to a GUID//-----------------------------------------------------------------------------
HRESULT DXUtil_ConvertStringToGUID(const TCHAR* strSrc, GUID* pGuidDest){
UINT aiTmp[10];if(_stscanf_s(strSrc,TEXT("{%8X-%4X-%4X-%2X%2X-%2X%2X%2X%2X%2X%2X}"),&pGuidDest->Data1,&aiTmp[0],&aiTmp[1],&aiTmp[2],&aiTmp[3],&aiTmp[4],&aiTmp[5],&aiTmp[6],&aiTmp[7],&aiTmp[8],&aiTmp[9])!=11){ZeroMemory(pGuidDest,sizeof(GUID));return E_FAIL;}else{
pGuidDest->Data2 =(USHORT)aiTmp[0];
pGuidDest->Data3 =(USHORT)aiTmp[1];
pGuidDest->Data4[0]=(BYTE)aiTmp[2];
pGuidDest->Data4[1]=(BYTE)aiTmp[3];
pGuidDest->Data4[2]=(BYTE)aiTmp[4];
pGuidDest->Data4[3]=(BYTE)aiTmp[5];
pGuidDest->Data4[4]=(BYTE)aiTmp[6];
pGuidDest->Data4[5]=(BYTE)aiTmp[7];
pGuidDest->Data4[6]=(BYTE)aiTmp[8];
pGuidDest->Data4[7]=(BYTE)aiTmp[9];return S_OK;}}//-----------------------------------------------------------------------------// Name: DXUtil_ConvertGUIDToStringCch()// Desc: Converts a GUID to a string // cchDestChar is the size in TCHARs of strDest. Be careful not to // pass in sizeof(strDest) on UNICODE builds//-----------------------------------------------------------------------------
HRESULT DXUtil_ConvertGUIDToStringCch(const GUID* pGuidSrc, TCHAR* strDest,int cchDestChar){int nResult =_sntprintf_s(strDest, cchDestChar, cchDestChar,TEXT("{%0.8X-%0.4X-%0.4X-%0.2X%0.2X-%0.2X%0.2X%0.2X%0.2X%0.2X%0.2X}"),
pGuidSrc->Data1, pGuidSrc->Data2, pGuidSrc->Data3,
pGuidSrc->Data4[0], pGuidSrc->Data4[1],
pGuidSrc->Data4[2], pGuidSrc->Data4[3],
pGuidSrc->Data4[4], pGuidSrc->Data4[5],
pGuidSrc->Data4[6], pGuidSrc->Data4[7]);if(nResult <0)return E_FAIL;return S_OK;}//-----------------------------------------------------------------------------// Name: CArrayList constructor// Desc: //-----------------------------------------------------------------------------CArrayList::CArrayList(ArrayListType Type, UINT BytesPerEntry){if(Type == AL_REFERENCE)
BytesPerEntry =sizeof(void*);
m_ArrayListType = Type;
m_pData =NULL;
m_BytesPerEntry = BytesPerEntry;
m_NumEntries =0;
m_NumEntriesAllocated =0;}//-----------------------------------------------------------------------------// Name: CArrayList destructor// Desc: //-----------------------------------------------------------------------------CArrayList::~CArrayList(void){if(m_pData !=NULL)delete[] m_pData;}//-----------------------------------------------------------------------------// Name: CArrayList::Add// Desc: Adds pEntry to the list.//-----------------------------------------------------------------------------
HRESULT CArrayList::Add(void* pEntry){if(m_BytesPerEntry ==0)return E_FAIL;if(m_pData ==NULL|| m_NumEntries +1> m_NumEntriesAllocated){void* pDataNew;
UINT NumEntriesAllocatedNew;if(m_NumEntriesAllocated ==0)
NumEntriesAllocatedNew =16;else
NumEntriesAllocatedNew = m_NumEntriesAllocated *2;
pDataNew =new BYTE[NumEntriesAllocatedNew * m_BytesPerEntry];if(pDataNew ==NULL)return E_OUTOFMEMORY;if(m_pData !=NULL){CopyMemory(pDataNew, m_pData, m_NumEntries * m_BytesPerEntry);delete[] m_pData;}
m_pData = pDataNew;
m_NumEntriesAllocated = NumEntriesAllocatedNew;}if(m_ArrayListType == AL_VALUE)CopyMemory((BYTE*)m_pData +(m_NumEntries * m_BytesPerEntry), pEntry, m_BytesPerEntry);else*(((void**)m_pData)+ m_NumEntries)= pEntry;
m_NumEntries++;return S_OK;}//-----------------------------------------------------------------------------// Name: CArrayList::Remove// Desc: Remove the item at Entry in the list, and collapse the array. //-----------------------------------------------------------------------------voidCArrayList::Remove(UINT Entry){// Decrement count
m_NumEntries--;// Find the entry address
BYTE* pData =(BYTE*)m_pData +(Entry * m_BytesPerEntry);// Collapse the arrayMoveMemory(pData, pData + m_BytesPerEntry,(m_NumEntries - Entry)* m_BytesPerEntry);}//-----------------------------------------------------------------------------// Name: CArrayList::GetPtr// Desc: Returns a pointer to the Entry'th entry in the list.//-----------------------------------------------------------------------------void*CArrayList::GetPtr(UINT Entry){if(m_ArrayListType == AL_VALUE)return(BYTE*)m_pData +(Entry * m_BytesPerEntry);elsereturn*(((void**)m_pData)+ Entry);}//-----------------------------------------------------------------------------// Name: CArrayList::Contains// Desc: Returns whether the list contains an entry identical to the // specified entry data.//-----------------------------------------------------------------------------boolCArrayList::Contains(void* pEntryData){for(UINT iEntry =0; iEntry < m_NumEntries; iEntry++){if(m_ArrayListType == AL_VALUE){if(memcmp(GetPtr(iEntry), pEntryData, m_BytesPerEntry)==0)returntrue;}else{if(GetPtr(iEntry)== pEntryData)returntrue;}}returnfalse;}//-----------------------------------------------------------------------------// Name: BYTE helper functions// Desc: cchDestChar is the size in BYTEs of strDest. Be careful not to // pass use sizeof() if the strDest is a string pointer. // eg.// TCHAR* sz = new TCHAR[100]; // sizeof(sz) == 4// TCHAR sz2[100]; // sizeof(sz2) == 200//-----------------------------------------------------------------------------
HRESULT DXUtil_ConvertAnsiStringToWideCb(WCHAR* wstrDestination,const CHAR* strSource,int cbDestChar){returnDXUtil_ConvertAnsiStringToWideCch(wstrDestination, strSource, cbDestChar /sizeof(WCHAR));}
HRESULT DXUtil_ConvertWideStringToAnsiCb(CHAR* strDestination,const WCHAR* wstrSource,int cbDestChar){returnDXUtil_ConvertWideStringToAnsiCch(strDestination, wstrSource, cbDestChar /sizeof(CHAR));}
HRESULT DXUtil_ConvertGenericStringToAnsiCb(CHAR* strDestination,const TCHAR* tstrSource,int cbDestChar){returnDXUtil_ConvertGenericStringToAnsiCch(strDestination, tstrSource, cbDestChar /sizeof(CHAR));}
HRESULT DXUtil_ConvertGenericStringToWideCb(WCHAR* wstrDestination,const TCHAR* tstrSource,int cbDestChar){returnDXUtil_ConvertGenericStringToWideCch(wstrDestination, tstrSource, cbDestChar /sizeof(WCHAR));}
HRESULT DXUtil_ConvertAnsiStringToGenericCb(TCHAR* tstrDestination,const CHAR* strSource,int cbDestChar){returnDXUtil_ConvertAnsiStringToGenericCch(tstrDestination, strSource, cbDestChar /sizeof(TCHAR));}
HRESULT DXUtil_ConvertWideStringToGenericCb(TCHAR* tstrDestination,const WCHAR* wstrSource,int cbDestChar){returnDXUtil_ConvertWideStringToGenericCch(tstrDestination, wstrSource, cbDestChar /sizeof(TCHAR));}
HRESULT DXUtil_ReadStringRegKeyCb(HKEY hKey, TCHAR* strRegName, TCHAR* strDest, DWORD cbDest, TCHAR* strDefault){returnDXUtil_ReadStringRegKeyCch(hKey, strRegName, strDest, cbDest /sizeof(TCHAR), strDefault);}
HRESULT DXUtil_ConvertGUIDToStringCb(const GUID* pGuidSrc, TCHAR* strDest,int cbDestChar){returnDXUtil_ConvertGUIDToStringCch(pGuidSrc, strDest, cbDestChar /sizeof(TCHAR));}#ifndefUNDER_CE
HRESULT DXUtil_GetDXSDKMediaPathCb(TCHAR* szDest,int cbDest){returnDXUtil_GetDXSDKMediaPathCch(szDest, cbDest /sizeof(TCHAR));}
HRESULT DXUtil_FindMediaFileCb(TCHAR* szDestPath,int cbDest, TCHAR* strFilename){returnDXUtil_FindMediaFileCch(szDestPath, cbDest /sizeof(TCHAR), strFilename);}#endif// !UNDER_CEfps.h
#pragmaonce#include"d3dfont.h"#include<sstream>classFPSCounter{public:FPSCounter(IDirect3DDevice9* device);~FPSCounter();boolrender(D3DCOLOR color,float timeDelta);private:
IDirect3DDevice9* _device;
CD3DFont* _font;
DWORD _frameCnt;float _timeElapsed;float _fps;char _fpsString[9];};fps.cpp
#include"fps.h"#include<cstdio>FPSCounter::FPSCounter(IDirect3DDevice9* device){
_device = device;
_font =newCD3DFont("Times New Roman",24,0);
_font->InitDeviceObjects(_device);
_font->RestoreDeviceObjects();
_frameCnt =0;
_timeElapsed =0.0f;
_fps =0.0f;}FPSCounter::~FPSCounter(){if(_font){
_font->InvalidateDeviceObjects();
_font->DeleteDeviceObjects();delete _font;}}boolFPSCounter::render(D3DCOLOR color,float timeDelta){if(_font){
_frameCnt++;
_timeElapsed += timeDelta;if(_timeElapsed >=1.0f){
_fps =(float)_frameCnt / _timeElapsed;
std::stringstream ss;//std::string fpsStr;
ss << _fps;
ss >> _fpsString;//strncpy_s(_fpsString, 9, fpsStr.c_str(), 9);//sprintf_s(_fpsString, 8, "%f", _fps);
_fpsString[8]='\0';// mark end of string
_timeElapsed =0.0f;
_frameCnt =0;}
_font->DrawText(20,20, color, _fpsString);}returntrue;}terrain.h
#pragmaonce#include"d3dUtility.h"#include<string>#include<vector>classTerrain{public:Terrain(
IDirect3DDevice9* device,
std::string heightmapFileName,int numVertsPerRow,int numVertsPerCol,int cellSpacing,// space between cellsfloat heightScale);~Terrain();intgetHeightmapEntry(int row,int col);voidsetHeightmapEntry(int row,int col,int value);floatgetHeight(float x,float z);boolloadTexture(std::string fileName);boolgenTexture(D3DXVECTOR3* directionToLight);booldraw(D3DXMATRIX* world,bool drawTris);private:
IDirect3DDevice9* _device;
IDirect3DTexture9* _tex;
IDirect3DVertexBuffer9* _vb;
IDirect3DIndexBuffer9* _ib;int _numVertsPerRow;int _numVertsPerCol;int _cellSpacing;int _numCellsPerRow;int _numCellsPerCol;int _width;int _depth;int _numVertices;int _numTriangles;float _heightScale;
std::vector<int> _heightmap;// helper methodsboolreadRawFile(std::string fileName);boolcomputeVertices();boolcomputeIndices();boollightTerrain(D3DXVECTOR3* directionToLight);floatcomputeShade(int cellRow,int cellCol, D3DXVECTOR3* directionToLight);structTerrainVertex{TerrainVertex(){}TerrainVertex(float x,float y,float z,float u,float v){
_x = x; _y = y; _z = z; _u = u; _v = v;}float _x, _y, _z;float _u, _v;staticconst DWORD FVF;};};terrain.cpp
#include"terrain.h"#include<fstream>#include<cmath>const DWORD Terrain::TerrainVertex::FVF = D3DFVF_XYZ | D3DFVF_TEX1;Terrain::Terrain(IDirect3DDevice9* device,
std::string heightmapFileName,int numVertsPerRow,int numVertsPerCol,int cellSpacing,float heightScale){
_device = device;
_numVertsPerRow = numVertsPerRow;
_numVertsPerCol = numVertsPerCol;
_cellSpacing = cellSpacing;
_numCellsPerRow = _numVertsPerRow -1;
_numCellsPerCol = _numVertsPerCol -1;
_width = _numCellsPerRow * _cellSpacing;
_depth = _numCellsPerCol * _cellSpacing;
_numVertices = _numVertsPerRow * _numVertsPerCol;
_numTriangles = _numCellsPerRow * _numCellsPerCol *2;
_heightScale = heightScale;// load heightmapif(!readRawFile(heightmapFileName)){::MessageBox(0,"readRawFile - FAILED",0,0);::PostQuitMessage(0);}// scale heightsfor(int i =0; i < _heightmap.size(); i++)
_heightmap[i]*= heightScale;// compute the verticesif(!computeVertices()){::MessageBox(0,"computeVertices - FAILED",0,0);::PostQuitMessage(0);}// compute the indicesif(!computeIndices()){::MessageBox(0,"computeIndices - FAILED",0,0);::PostQuitMessage(0);}}Terrain::~Terrain(){
d3d::Release<IDirect3DVertexBuffer9*>(_vb);
d3d::Release<IDirect3DIndexBuffer9*>(_ib);
d3d::Release<IDirect3DTexture9*>(_tex);}intTerrain::getHeightmapEntry(int row,int col){return _heightmap[row * _numVertsPerRow + col];}voidTerrain::setHeightmapEntry(int row,int col,int value){
_heightmap[row * _numVertsPerRow + col]= value;}boolTerrain::computeVertices(){
HRESULT hr =0;
hr = _device->CreateVertexBuffer(
_numVertices *sizeof(TerrainVertex),
D3DUSAGE_WRITEONLY,
TerrainVertex::FVF,
D3DPOOL_MANAGED,&_vb,0);if(FAILED(hr))returnfalse;// coordinates to start generating vertices atint startX =-_width /2;int startZ = _depth /2;// coordinates to end generating vertices atint endX = _width /2;int endZ =-_depth /2;// compute the increment size of the texture coordinates// from one vertex to the next.float uCoordIncrementSize =1.0f/(float)_numCellsPerRow;float vCoordIncrementSize =1.0f/(float)_numCellsPerCol;
TerrainVertex* v =0;
_vb->Lock(0,0,(void**)&v,0);int i =0;for(int z = startZ; z >= endZ; z -= _cellSpacing){int j =0;for(int x = startX; x <= endX; x += _cellSpacing){// compute the correct index into the vertex buffer and heightmap// based on where we are in the nested loop.int index = i * _numVertsPerRow + j;
v[index]=TerrainVertex((float)x,(float)_heightmap[index],(float)z,(float)j * uCoordIncrementSize,(float)i * vCoordIncrementSize);
j++;// next column}
i++;// next row}
_vb->Unlock();returntrue;}boolTerrain::computeIndices(){
HRESULT hr =0;
hr = _device->CreateIndexBuffer(
_numTriangles *3*sizeof(WORD),// 3 indices per triangle
D3DUSAGE_WRITEONLY,
D3DFMT_INDEX16,
D3DPOOL_MANAGED,&_ib,0);if(FAILED(hr))returnfalse;
WORD* indices =0;
_ib->Lock(0,0,(void**)&indices,0);// index to start of a group of 6 indices that describe the// two triangles that make up a quadint baseIndex =0;// loop through and compute the triangles of each quadfor(int i =0; i < _numCellsPerCol; i++){for(int j =0; j < _numCellsPerRow; j++){
indices[baseIndex]= i * _numVertsPerRow + j;
indices[baseIndex +1]= i * _numVertsPerRow + j +1;
indices[baseIndex +2]=(i +1)* _numVertsPerRow + j;
indices[baseIndex +3]=(i +1)* _numVertsPerRow + j;
indices[baseIndex +4]= i * _numVertsPerRow + j +1;
indices[baseIndex +5]=(i +1)* _numVertsPerRow + j +1;// next quad
baseIndex +=6;}}
_ib->Unlock();returntrue;}boolTerrain::loadTexture(std::string fileName){
HRESULT hr =0;
hr =D3DXCreateTextureFromFile(
_device,
fileName.c_str(),&_tex);if(FAILED(hr))returnfalse;returntrue;}boolTerrain::genTexture(D3DXVECTOR3* directionToLight){// Method fills the top surface of a texture procedurally. Then// lights the top surface. Finally, it fills the other mipmap// surfaces based on the top surface data using D3DXFilterTexture.
HRESULT hr =0;// texel for each quad cellint texWidth = _numCellsPerRow;int texHeight = _numCellsPerCol;// create an empty texture
hr =D3DXCreateTexture(
_device,
texWidth, texHeight,0,// create a complete mipmap chain0,// usage
D3DFMT_X8R8G8B8,// 32 bit XRGB format
D3DPOOL_MANAGED,&_tex);if(FAILED(hr))returnfalse;
D3DSURFACE_DESC textureDesc;
_tex->GetLevelDesc(0/*level*/,&textureDesc);// make sure we got the requested format because our code // that fills the texture is hard coded to a 32 bit pixel depth.if(textureDesc.Format != D3DFMT_X8R8G8B8)returnfalse;
D3DLOCKED_RECT lockedRect;
_tex->LockRect(0/*lock top surface*/,&lockedRect,0/* lock entire tex*/,0/*flags*/);
DWORD* imageData =(DWORD*)lockedRect.pBits;for(int i =0; i < texHeight; i++){for(int j =0; j < texWidth; j++){
D3DXCOLOR c;// get height of upper left vertex of quad.float height =(float)getHeightmapEntry(i, j)/ _heightScale;if((height)<42.5f) c = d3d::BEACH_SAND;elseif((height)<85.0f) c = d3d::LIGHT_YELLOW_GREEN;elseif((height)<127.5f) c = d3d::PUREGREEN;elseif((height)<170.0f) c = d3d::DARK_YELLOW_GREEN;elseif((height)<212.5f) c = d3d::DARKBROWN;else c = d3d::WHITE;// fill locked data, note we divide the pitch by four because the// pitch is given in bytes and there are 4 bytes per DWORD.
imageData[i * lockedRect.Pitch /4+ j]=(D3DCOLOR)c;}}
_tex->UnlockRect(0);if(!lightTerrain(directionToLight)){::MessageBox(0,"lightTerrain() - FAILED",0,0);returnfalse;}
hr =D3DXFilterTexture(
_tex,0,// default palette0,// use top level as source level
D3DX_DEFAULT);// default filterif(FAILED(hr)){::MessageBox(0,"D3DXFilterTexture() - FAILED",0,0);returnfalse;}returntrue;}boolTerrain::lightTerrain(D3DXVECTOR3* directionToLight){
HRESULT hr =0;
D3DSURFACE_DESC textureDesc;
_tex->GetLevelDesc(0/*level*/,&textureDesc);// make sure we got the requested format because our code that fills the// texture is hard coded to a 32 bit pixel depth.if(textureDesc.Format != D3DFMT_X8R8G8B8)returnfalse;
D3DLOCKED_RECT lockedRect;
_tex->LockRect(0,// lock top surface level in mipmap chain&lockedRect,// pointer to receive locked data0,// lock entire texture image0);// no lock flags specified
DWORD* imageData =(DWORD*)lockedRect.pBits;for(int i =0; i < textureDesc.Height; i++){for(int j =0; j < textureDesc.Width; j++){// index into texture, note we use the pitch and divide by // four since the pitch is given in bytes and there are // 4 bytes per DWORD.int index = i * lockedRect.Pitch /4+ j;// get current color of quad
D3DXCOLOR c(imageData[index]);// shade current quad
c *=computeShade(i, j, directionToLight);;// save shaded color
imageData[index]=(D3DCOLOR)c;}}
_tex->UnlockRect(0);returntrue;}floatTerrain::computeShade(int cellRow,int cellCol, D3DXVECTOR3* directionToLight){// get heights of three vertices on the quadfloat heightA =getHeightmapEntry(cellRow, cellCol);float heightB =getHeightmapEntry(cellRow, cellCol +1);float heightC =getHeightmapEntry(cellRow +1, cellCol);// build two vectors on the quad
D3DXVECTOR3 u(_cellSpacing, heightB - heightA,0.0f);
D3DXVECTOR3 v(0.0f, heightC - heightA,-_cellSpacing);// find the normal by taking the cross product of two// vectors on the quad.
D3DXVECTOR3 n;D3DXVec3Cross(&n,&u,&v);D3DXVec3Normalize(&n,&n);float cosine =D3DXVec3Dot(&n, directionToLight);if(cosine <0.0f)
cosine =0.0f;return cosine;}boolTerrain::readRawFile(std::string fileName){// Restriction: RAW file dimensions must be >= to the// dimensions of the terrain. That is a 128x128 RAW file// can only be used with a terrain constructed with at most// 128x128 vertices.// A height for each vertex
std::vector<BYTE>in(_numVertices);
std::ifstream inFile(fileName.c_str(), std::ios_base::binary);/*if (inFile.is_open())
return false;*/
inFile.read((char*)&in[0],// buffer
in.size());// number of bytes to read into buffer
inFile.close();// copy BYTE vector to int vector
_heightmap.resize(_numVertices);for(int i =0; i < in.size(); i++)
_heightmap[i]= in[i];returntrue;}floatTerrain::getHeight(float x,float z){// Translate on xz-plane by the transformation that takes// the terrain START point to the origin.
x =((float)_width /2.0f)+ x;
z =((float)_depth /2.0f)- z;// Scale down by the transformation that makes the // cellspacing equal to one. This is given by // 1 / cellspacing since; cellspacing * 1 / cellspacing = 1.
x /=(float)_cellSpacing;
z /=(float)_cellSpacing;// From now on, we will interpret our positive z-axis as// going in the 'down' direction, rather than the 'up' direction.// This allows to extract the row and column simply by 'flooring'// x and z:float col =::floorf(x);float row =::floorf(z);// get the heights of the quad we're in:// // A B// *---*// | / |// *---* // C Dfloat A =getHeightmapEntry(row, col);float B =getHeightmapEntry(row, col +1);float C =getHeightmapEntry(row +1, col);float D =getHeightmapEntry(row +1, col +1);//// Find the triangle we are in://// Translate by the transformation that takes the upper-left// corner of the cell we are in to the origin. Recall that our // cellspacing was nomalized to 1. Thus we have a unit square// at the origin of our +x -> 'right' and +z -> 'down' system.float dx = x - col;float dz = z - row;// Note the below compuations of u and v are unneccessary, we really// only need the height, but we compute the entire vector to emphasis// the books discussion.float height =0.0f;if(dz <1.0f- dx)// upper triangle ABC{float uy = B - A;// A->Bfloat vy = C - A;// A->C// Linearly interpolate on each vector. The height is the vertex// height the vectors u and v originate from {A}, plus the heights// found by interpolating on each vector u and v.
height = A + d3d::Lerp(0.0f, uy, dx)+ d3d::Lerp(0.0f, vy, dz);}else// lower triangle DCB{float uy = C - D;// D->Cfloat vy = B - D;// D->B// Linearly interpolate on each vector. The height is the vertex// height the vectors u and v originate from {D}, plus the heights// found by interpolating on each vector u and v.
height = D + d3d::Lerp(0.0f, uy,1.0f- dx)+ d3d::Lerp(0.0f, vy,1.0f- dz);}return height;}boolTerrain::draw(D3DXMATRIX* world,bool drawTris){
HRESULT hr =0;if(_device){
_device->SetTransform(D3DTS_WORLD, world);
_device->SetStreamSource(0, _vb,0,sizeof(TerrainVertex));
_device->SetFVF(TerrainVertex::FVF);
_device->SetIndices(_ib);
_device->SetTexture(0, _tex);// turn off lighting since we're lighting it ourselves
_device->SetRenderState(D3DRS_LIGHTING,false);
hr = _device->DrawIndexedPrimitive(
D3DPT_TRIANGLELIST,0,0,
_numVertices,0,
_numTriangles);
_device->SetRenderState(D3DRS_LIGHTING,true);if(drawTris){
_device->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);
hr = _device->DrawIndexedPrimitive(
D3DPT_TRIANGLELIST,0,0,
_numVertices,0,
_numTriangles);
_device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);}if(FAILED(hr))returnfalse;}returntrue;}camera.h
#pragmaonce#include<d3dx9.h>classCamera{public:enumCameraType{ LANDOBJECT, AIRCRAFT };Camera();Camera(CameraType cameraType);~Camera();voidstrafe(float units);//left/rightvoidfly(float units);//up/downvoidwalk(float units);//forward/backwardvoidpitch(float angle);//rotate on right vectorvoidyaw(float angle);//rotate on up vectorvoidroll(float angle);//rotate on look vectorvoidgetViewMatrix(D3DXMATRIX* V);voidsetCameraType(CameraType cameraType);voidgetPosition(D3DXVECTOR3* pos);voidsetPosition(D3DXVECTOR3* pos);voidgetRight(D3DXVECTOR3* right);voidgetUp(D3DXVECTOR3* up);voidgetLook(D3DXVECTOR3* look);private:
CameraType _cameraType;
D3DXVECTOR3 _right;
D3DXVECTOR3 _up;
D3DXVECTOR3 _look;
D3DXVECTOR3 _pos;};camera.cpp
#include"camera.h"Camera::Camera(){
_cameraType = LANDOBJECT;
_pos =D3DXVECTOR3(0.0f,0.0f,0.0f);
_right =D3DXVECTOR3(1.0f,0.0f,0.0f);
_up =D3DXVECTOR3(0.0f,1.0f,0.0f);
_look =D3DXVECTOR3(0.0f,0.0f,1.0f);}Camera::Camera(CameraType cameraType){
_cameraType = cameraType;
_pos =D3DXVECTOR3(0.0f,0.0f,0.0f);
_right =D3DXVECTOR3(1.0f,0.0f,0.0f);
_up =D3DXVECTOR3(0.0f,1.0f,0.0f);
_look =D3DXVECTOR3(0.0f,0.0f,1.0f);}Camera::~Camera(){}voidCamera::getPosition(D3DXVECTOR3* pos){*pos = _pos;}voidCamera::setPosition(D3DXVECTOR3* pos){
_pos =*pos;}voidCamera::getRight(D3DXVECTOR3* right){*right = _right;}voidCamera::getUp(D3DXVECTOR3* up){*up = _up;}voidCamera::getLook(D3DXVECTOR3* look){*look = _look;}voidCamera::walk(float units){if(_cameraType == LANDOBJECT)
_pos +=D3DXVECTOR3(_look.x,0.0f, _look.z)* units;if(_cameraType == AIRCRAFT)
_pos += _look * units;}voidCamera::strafe(float units){if(_cameraType == LANDOBJECT)
_pos +=D3DXVECTOR3(_right.x,0.0f, _right.z)* units;if(_cameraType == AIRCRAFT)
_pos += _right * units;}voidCamera::fly(float units){if(_cameraType == LANDOBJECT)
_pos.y += units;if(_cameraType == AIRCRAFT)
_pos += _up * units;}voidCamera::pitch(float angle){
D3DXMATRIX T;D3DXMatrixRotationAxis(&T,&_right, angle);D3DXVec3TransformCoord(&_up,&_up,&T);D3DXVec3TransformCoord(&_look,&_look,&T);}voidCamera::yaw(float angle){
D3DXMATRIX T;if(_cameraType == LANDOBJECT)D3DXMatrixRotationY(&T, angle);if(_cameraType == AIRCRAFT)D3DXMatrixRotationAxis(&T,&_up, angle);D3DXVec3TransformCoord(&_right,&_right,&T);D3DXVec3TransformCoord(&_look,&_look,&T);}voidCamera::roll(float angle){if(_cameraType == AIRCRAFT){
D3DXMATRIX T;D3DXMatrixRotationAxis(&T,&_look, angle);D3DXVec3TransformCoord(&_up,&_up,&T);D3DXVec3TransformCoord(&_right,&_right,&T);}}voidCamera::getViewMatrix(D3DXMATRIX* V){//保持相机轴彼此正交D3DXVec3Normalize(&_look,&_look);D3DXVec3Cross(&_up,&_look,&_right);D3DXVec3Normalize(&_up,&_up);D3DXVec3Cross(&_right,&_up,&_look);D3DXVec3Normalize(&_right,&_right);//构建视图矩阵float x =-D3DXVec3Dot(&_right,&_pos);float y =-D3DXVec3Dot(&_up,&_pos);float z =-D3DXVec3Dot(&_look,&_pos);//视图矩阵=平移矩阵*旋转矩阵(*V)(0,0)= _right.x;(*V)(0,1)= _up.x;(*V)(0,2)= _look.x;(*V)(0,3)=0.0f;(*V)(1,0)= _right.y;(*V)(1,1)= _up.y;(*V)(1,2)= _look.y;(*V)(1,3)=0.0f;(*V)(2,0)= _right.z;(*V)(2,1)= _up.z;(*V)(2,2)= _look.z;(*V)(2,3)=0.0f;(*V)(3,0)= x;(*V)(3,1)= y;(*V)(3,2)= z;(*V)(3,3)=1.0f;}voidCamera::setCameraType(CameraType cameraType){
_cameraType = cameraType;}d3dutil.h
#pragmaonce#include<d3d9.h>#include<d3dx9math.h>namespace d3d
{boolInitD3D(HINSTANCE hInstance,int width,int height,bool windowed, D3DDEVTYPE deviceType, IDirect3DDevice9** device);intEnterMsgLoop(bool(*ptr_display)(float timeDelta));
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);template<classT>voidRelease(T t){if(t){
t->Release();
t =nullptr;}}template<classT>voidDelete(T t){if(t){delete t;
t =nullptr;}}const D3DXCOLOR WHITE(D3DCOLOR_XRGB(255,255,255));const D3DXCOLOR BLACK(D3DCOLOR_XRGB(0,0,0));const D3DXCOLOR RED(D3DCOLOR_XRGB(255,0,0));const D3DXCOLOR GREEN(D3DCOLOR_XRGB(0,255,0));const D3DXCOLOR BLUE(D3DCOLOR_XRGB(0,0,255));const D3DXCOLOR YELLOW(D3DCOLOR_XRGB(255,255,0));const D3DXCOLOR CYAN(D3DCOLOR_XRGB(0,255,255));const D3DXCOLOR MAGENTA(D3DCOLOR_XRGB(255,0,255));const D3DXCOLOR BEACH_SAND(D3DCOLOR_XRGB(255,249,157));const D3DXCOLOR DESERT_SAND(D3DCOLOR_XRGB(250,205,135));const D3DXCOLOR LIGHTGREEN(D3DCOLOR_XRGB(60,184,120));const D3DXCOLOR PUREGREEN(D3DCOLOR_XRGB(0,166,81));const D3DXCOLOR DARKGREEN(D3DCOLOR_XRGB(0,114,54));const D3DXCOLOR LIGHT_YELLOW_GREEN(D3DCOLOR_XRGB(124,197,118));const D3DXCOLOR PURE_YELLOW_GREEN(D3DCOLOR_XRGB(57,181,74));const D3DXCOLOR DARK_YELLOW_GREEN(D3DCOLOR_XRGB(25,123,48));const D3DXCOLOR LIGHTBROWN(D3DCOLOR_XRGB(198,156,109));const D3DXCOLOR DARKBROWN(D3DCOLOR_XRGB(115,100,87));//材质
D3DMATERIAL9 InitMtrl(D3DXCOLOR a, D3DXCOLOR d, D3DXCOLOR s, D3DXCOLOR e,float p);const D3DMATERIAL9 WHITE_MTRL =InitMtrl(WHITE, WHITE, WHITE, BLACK,8.0f);const D3DMATERIAL9 RED_MTRL =InitMtrl(RED, RED, RED, BLACK,8.0f);const D3DMATERIAL9 GREEN_MTRL =InitMtrl(GREEN, GREEN, GREEN, BLACK,8.0f);const D3DMATERIAL9 BLUE_MTRL =InitMtrl(BLUE, BLUE, BLUE, BLACK,8.0f);const D3DMATERIAL9 YELLOW_MTRL =InitMtrl(YELLOW, YELLOW, YELLOW, BLACK,8.0f);//光源
D3DLIGHT9 InitDirectionalLight(D3DXVECTOR3* direction, D3DXCOLOR* color);//D3DLIGHT9 InitPointLight(D3DXVECTOR3* position, D3DXCOLOR* color);//D3DLIGHT9 InitSpotLight(D3DXVECTOR3* position, D3DXVECTOR3* direction, D3DXCOLOR* color);// Function references "desert.bmp" internally. This file must// be in the working directory.boolDrawBasicScene(
IDirect3DDevice9* device,// Pass in 0 for cleanup.float scale);// uniform scale structVertex{Vertex(){}Vertex(float x,float y,float z,float nx,float ny,float nz,float u,float v){
_x = x; _y = y; _z = z;
_nx = nx; _ny = ny; _nz = nz;
_u = u; _v = v;}float _x, _y, _z;float _nx, _ny, _nz;float _u, _v;staticconst DWORD FVF;};//// Randomness//// Desc: Return random float in [lowBound, highBound] interval.floatGetRandomFloat(float lowBound,float highBound);// Desc: Returns a random vector in the bounds specified by min and max.voidGetRandomVector(
D3DXVECTOR3* out,
D3DXVECTOR3* min,
D3DXVECTOR3* max);//// Conversion//
DWORD FtoDw(float f);//// Interpolation//floatLerp(float a,float b,float t);}d3dutil.cpp
#include"d3dUtility.h"// vertex formatsconst DWORD d3d::Vertex::FVF = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1;bool d3d::InitD3D(HINSTANCE hInstance,int width,int height,bool windowed, D3DDEVTYPE deviceType, IDirect3DDevice9** device){//注册wndclass
WNDCLASS wndclass;
wndclass.style = CS_VREDRAW | CS_HREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra =0;
wndclass.cbWndExtra =0;
wndclass.hInstance = hInstance;
wndclass.hIcon =LoadIcon(nullptr, IDI_APPLICATION);
wndclass.hCursor =LoadCursor(nullptr, IDC_ARROW);
wndclass.hbrBackground =(HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName =nullptr;
wndclass.lpszClassName =TEXT("d3d");if(!RegisterClass(&wndclass)){MessageBox(nullptr,TEXT("RegisterClass() - FAILED"),TEXT("ERROR"), MB_ICONERROR);returnfalse;}//创建窗口
HWND hwnd =CreateWindow(TEXT("d3d"),TEXT("d3d window"),
WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, width, height,nullptr,nullptr, hInstance,nullptr);//设备列举和创建IDirect3DDevice9对象
IDirect3D9* d3d9 =Direct3DCreate9(D3D_SDK_VERSION);//检测硬件顶点处理
D3DCAPS9 caps;
d3d9->GetDeviceCaps(D3DADAPTER_DEFAULT, deviceType,&caps);int vp =0;if(caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT)
vp = D3DCREATE_HARDWARE_VERTEXPROCESSING;//支持硬件顶点处理else
vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING;//不支持
D3DDISPLAYMODE d3ddm;if(FAILED(d3d9->GetAdapterDisplayMode(D3DADAPTER_DEFAULT,&d3ddm)))returnfalse;//填充D3DPRESENT_PARAMETERS结构
D3DPRESENT_PARAMETERS d3dpp;
d3dpp.BackBufferWidth = width;
d3dpp.BackBufferHeight = height;//d3dpp.BackBufferFormat = D3DFMT_A8B8G8R8;//像素格式
d3dpp.BackBufferFormat = d3ddm.Format;
d3dpp.BackBufferCount =1;
d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
d3dpp.MultiSampleQuality =0;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.hDeviceWindow = hwnd;
d3dpp.Windowed = windowed;//full screen
d3dpp.EnableAutoDepthStencil =true;
d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;//depth format
d3dpp.Flags =0;
d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;//创建IDirect3DDevice9对象
HRESULT hr = d3d9->CreateDevice(D3DADAPTER_DEFAULT, deviceType, hwnd, vp,&d3dpp, device);if(FAILED(hr)){MessageBox(nullptr,TEXT("CraeteDevice() - FAILED"),TEXT("ERROR"), MB_ICONERROR);returnfalse;}
d3d9->Release();returntrue;}int d3d::EnterMsgLoop(bool(*ptr_display)(float timeDelta)){
MSG msg;memset(&msg,0,sizeof(msg));staticfloat lastTime =(float)timeGetTime();while(true){if(PeekMessage(&msg,nullptr,0,0, PM_REMOVE)){if(msg.message == WM_QUIT)break;TranslateMessage(&msg);DispatchMessage(&msg);}else{float currTime =(float)timeGetTime();float timeDelta =(currTime - lastTime)*0.001f;ptr_display(timeDelta);
lastTime = currTime;}}return msg.wParam;}
LRESULT CALLBACK d3d::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam){switch(msg){case WM_DESTROY:PostQuitMessage(0);break;case WM_KEYDOWN:if(wParam == VK_ESCAPE)DestroyWindow(hwnd);break;}returnDefWindowProc(hwnd, msg, wParam, lParam);}
D3DMATERIAL9 d3d::InitMtrl(D3DXCOLOR a, D3DXCOLOR d, D3DXCOLOR s, D3DXCOLOR e,float p){
D3DMATERIAL9 mtrl;
mtrl.Ambient = a;//环境光
mtrl.Diffuse = d;//漫反射
mtrl.Specular = s;//镜面反射
mtrl.Emissive = e;//表面添加颜色
mtrl.Power = p;//镜面高光return mtrl;}
D3DLIGHT9 d3d::InitDirectionalLight(D3DXVECTOR3* direction, D3DXCOLOR* color){
D3DLIGHT9 light;ZeroMemory(&light,sizeof(light));
light.Type = D3DLIGHT_DIRECTIONAL;
light.Diffuse =*color;
light.Ambient =*color *0.3f;
light.Specular =*color *0.6f;
light.Direction =*direction;return light;}bool d3d::DrawBasicScene(IDirect3DDevice9* device,float scale){static IDirect3DVertexBuffer9* floor =nullptr;static IDirect3DTexture9* tex =nullptr;static ID3DXMesh* pillar =nullptr;
HRESULT hr =0;if(device ==nullptr){if(floor && tex && pillar){
d3d::Release<IDirect3DVertexBuffer9*>(floor);
d3d::Release<IDirect3DTexture9*>(tex);
d3d::Release<ID3DXMesh*>(pillar);}}elseif(!floor &&!tex &&!pillar){
device->CreateVertexBuffer(6*sizeof(d3d::Vertex),0,
d3d::Vertex::FVF,
D3DPOOL_MANAGED,&floor,0);
Vertex* v =0;
floor->Lock(0,0,(void**)&v,0);
v[0]=Vertex(-20.0f,-2.5f,-20.0f,0.0f,1.0f,0.0f,0.0f,1.0f);
v[1]=Vertex(-20.0f,-2.5f,20.0f,0.0f,1.0f,0.0f,0.0f,0.0f);
v[2]=Vertex(20.0f,-2.5f,20.0f,0.0f,1.0f,0.0f,1.0f,0.0f);
v[3]=Vertex(-20.0f,-2.5f,-20.0f,0.0f,1.0f,0.0f,0.0f,1.0f);
v[4]=Vertex(20.0f,-2.5f,20.0f,0.0f,1.0f,0.0f,1.0f,0.0f);
v[5]=Vertex(20.0f,-2.5f,-20.0f,0.0f,1.0f,0.0f,1.0f,1.0f);
floor->Unlock();//使用左手坐标系创建包含缸的网格D3DXCreateCylinder(device,0.5f,0.5f,5.0f,20,20,&pillar,nullptr);D3DXCreateTextureFromFile(device,TEXT("desert.bmp"),&tex);}else{//设置过滤器
device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
device->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_POINT);//设置光源
D3DXVECTOR3 dir(0.707f,-0.707f,0.707f);
D3DXCOLOR col(1.0f,1.0f,1.0f,1.0f);
D3DLIGHT9 light = d3d::InitDirectionalLight(&dir,&col);
device->SetLight(0,&light);
device->LightEnable(0,true);
device->SetRenderState(D3DRS_NORMALIZENORMALS,true);
device->SetRenderState(D3DRS_SPECULARENABLE,true);//渲染
D3DXMATRIX T, R, P, S;//生成沿x、y、z轴缩放的矩阵D3DXMatrixScaling(&S, scale, scale, scale);//用于旋转圆柱体以与世界y轴平行D3DXMatrixRotationX(&R,-D3DX_PI *0.5f);//draw floorD3DXMatrixIdentity(&T);
T = T * S;
device->SetTransform(D3DTS_WORLD,&T);
device->SetMaterial(&d3d::WHITE_MTRL);
device->SetTexture(0, tex);
device->SetStreamSource(0, floor,0,sizeof(Vertex));
device->SetFVF(Vertex::FVF);
device->DrawPrimitive(D3DPT_TRIANGLELIST,0,2);//draw pillars
device->SetMaterial(&d3d::BLUE_MTRL);
device->SetTexture(0,0);for(int i =0; i <5; i++){D3DXMatrixTranslation(&T,-5.0f,0.0f,-15.0f+(i *7.5f));
P = R * T * S;
device->SetTransform(D3DTS_WORLD,&P);
pillar->DrawSubset(0);D3DXMatrixTranslation(&T,5.0f,0.0f,-15.0f+(i *7.5f));
P = R * T * S;
device->SetTransform(D3DTS_WORLD,&P);
pillar->DrawSubset(0);}}returntrue;}float d3d::GetRandomFloat(float lowBound,float highBound){if(lowBound >= highBound)// bad inputreturn lowBound;// get random float in [0, 1] intervalfloat f =(rand()%10000)*0.0001f;// return float in [lowBound, highBound] interval. return(f *(highBound - lowBound))+ lowBound;}void d3d::GetRandomVector(
D3DXVECTOR3* out,
D3DXVECTOR3* min,
D3DXVECTOR3* max){
out->x =GetRandomFloat(min->x, max->x);
out->y =GetRandomFloat(min->y, max->y);
out->z =GetRandomFloat(min->z, max->z);}
DWORD d3d::FtoDw(float f){return*((DWORD*)&f);}float d3d::Lerp(float a,float b,float t){return a -(a * t)+(b * t);}terrainDriver.cpp
#include"d3dUtility.h"#include"terrain.h"#include"camera.h"#include"fps.h"#pragmacomment(lib,"d3d9.lib")#pragmacomment(lib,"d3dx9.lib")#pragmacomment(lib,"winmm.lib")#defineKEY_DOWN(vk_code)(GetAsyncKeyState(vk_code)&0x8000?1:0)//// Globals//
IDirect3DDevice9* device =0;constint Width =640;constint Height =480;
Terrain* TheTerrain =0;
Camera TheCamera(Camera::LANDOBJECT);
FPSCounter* FPS =0;//// Framework Functions//boolsetup(){//// Create the terrain.//
D3DXVECTOR3 lightDirection(0.0f,1.0f,0.0f);
TheTerrain =newTerrain(device,"coastMountain64.raw",64,64,10,0.5f);
TheTerrain->genTexture(&lightDirection);//// Create the font.//
FPS =newFPSCounter(device);//// Set texture filters.//
device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
device->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);//// Set projection matrix.//
D3DXMATRIX proj;D3DXMatrixPerspectiveFovLH(&proj,
D3DX_PI *0.25f,// 45 - degree(float)Width /(float)Height,1.0f,1000.0f);
device->SetTransform(D3DTS_PROJECTION,&proj);returntrue;}voidcleanup(){
d3d::Delete<Terrain*>(TheTerrain);
d3d::Delete<FPSCounter*>(FPS);}booldisplay(float timeDelta){//// Update the scene://if(device){if(KEY_DOWN(VK_UP))
TheCamera.walk(100.0f* timeDelta);if(KEY_DOWN(VK_DOWN))
TheCamera.walk(-100.0f* timeDelta);if(KEY_DOWN(VK_LEFT))
TheCamera.yaw(-1.0f* timeDelta);if(KEY_DOWN(VK_RIGHT))
TheCamera.yaw(1.0f* timeDelta);if(KEY_DOWN('N'))
TheCamera.strafe(-100.0f* timeDelta);if(KEY_DOWN('M'))
TheCamera.strafe(100.0f* timeDelta);if(KEY_DOWN('W'))
TheCamera.pitch(1.0f* timeDelta);if(KEY_DOWN('S'))
TheCamera.pitch(-1.0f* timeDelta);
D3DXVECTOR3 pos;
TheCamera.getPosition(&pos);float height = TheTerrain->getHeight(pos.x, pos.z);
pos.y = height +5.0f;// add height because we're standing up
TheCamera.setPosition(&pos);
D3DXMATRIX V;
TheCamera.getViewMatrix(&V);
device->SetTransform(D3DTS_VIEW,&V);//// Draw the scene://
device->Clear(0,0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,0xff000000,1.0f,0);
device->BeginScene();
D3DXMATRIX I;D3DXMatrixIdentity(&I);if(TheTerrain)
TheTerrain->draw(&I,false);if(FPS)
FPS->render(0xffffffff, timeDelta);
device->EndScene();
device->Present(0,0,0,0);}returntrue;}//// WinMain//int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine,int iCmdShow){if(!d3d::InitD3D(hInstance, Width, Height,true, D3DDEVTYPE_HAL,&device)){MessageBox(nullptr,TEXT("InitD3D() - FAILED"),TEXT("ERROR"), MB_ICONERROR);return0;}if(!setup()){MessageBox(nullptr,TEXT("setup() - FAILED"),TEXT("ERROR"), MB_ICONERROR);return0;}
d3d::EnterMsgLoop(display);cleanup();
device->Release();return1;}版权声明:本文标题:轻松掌握DirectX9.0下地形相机的旋转功能 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.roclinux.cn/p/1774494534a3571812.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论