d3dUtility.h
////////////////////////////////////////////////////////////////////////////////////////////////// // // File: d3dUtility.h // // Author: Frank Luna (C) All Rights Reserved // // System: AMD Athlon 1800+ XP, 512 DDR, Geforce 3, Windows XP, MSVC++ 7.0 // // Desc: Provides utility functions for simplifying common tasks. // ////////////////////////////////////////////////////////////////////////////////////////////////// #ifndef __d3dUtilityH__ #define __d3dUtilityH__ #include <d3dx9.h> #include <string> #include <limits> namespace d3d { // // Init // bool InitD3D( HINSTANCE hInstance, // [in] Application instance. int width, int height, // [in] Backbuffer dimensions. bool windowed, // [in] Windowed (true)or full screen (false). D3DDEVTYPE deviceType, // [in] HAL or REF IDirect3DDevice9** device);// [out]The created device. int EnterMsgLoop( bool (*ptr_display)(float timeDelta)); LRESULT CALLBACK WndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); // // Cleanup // template<class T> void Release(T t) { if( t ) { t->Release(); t = 0; } } template<class T> void Delete(T t) { if( t ) { delete t; t = 0; } } // // Colors // 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)); // // Lights // D3DLIGHT9 InitDirectionalLight(D3DXVECTOR3* direction, D3DXCOLOR* color); D3DLIGHT9 InitPointLight(D3DXVECTOR3* position, D3DXCOLOR* color); D3DLIGHT9 InitSpotLight(D3DXVECTOR3* position, D3DXVECTOR3* direction, D3DXCOLOR* color); // // Materials // D3DMATERIAL9 InitMtrl(D3DXCOLOR a, D3DXCOLOR d, D3DXCOLOR s, D3DXCOLOR e, float p); const D3DMATERIAL9 WHITE_MTRL = InitMtrl(WHITE, WHITE, WHITE, BLACK, 2.0f); const D3DMATERIAL9 RED_MTRL = InitMtrl(RED, RED, RED, BLACK, 2.0f); const D3DMATERIAL9 GREEN_MTRL = InitMtrl(GREEN, GREEN, GREEN, BLACK, 2.0f); const D3DMATERIAL9 BLUE_MTRL = InitMtrl(BLUE, BLUE, BLUE, BLACK, 2.0f); const D3DMATERIAL9 YELLOW_MTRL = InitMtrl(YELLOW, YELLOW, YELLOW, BLACK, 2.0f); // // Bounding Objects // struct BoundingBox { BoundingBox(); bool isPointInside(D3DXVECTOR3& p); D3DXVECTOR3 _min; D3DXVECTOR3 _max; }; struct BoundingSphere { BoundingSphere(); D3DXVECTOR3 _center; float _radius; }; // // Constants // const float INFINITY = FLT_MAX; const float EPSILON = 0.001f; // // Drawing // // Function references "desert.bmp" internally. This file must // be in the working directory. bool DrawBasicScene( IDirect3DDevice9* device,// Pass in 0 for cleanup. float scale); // uniform scale // // Vertex Structures // struct Vertex { Vertex(){} Vertex(float x, float y, float z, float nx, float ny, float nz, float u, float v) { _x = x; _y = y; _z = z; _nx = nx; _ny = ny; _nz = nz; _u = u; _v = v; } float _x, _y, _z; float _nx, _ny, _nz; float _u, _v; static const DWORD FVF; }; // // Randomness // // Desc: Return random float in [lowBound, highBound] interval. float GetRandomFloat(float lowBound, float highBound); // Desc: Returns a random vector in the bounds specified by min and max. void GetRandomVector( D3DXVECTOR3* out, D3DXVECTOR3* min, D3DXVECTOR3* max); // // Conversion // DWORD FtoDw(float f); // // Interpolation // float Lerp(float a, float b, float t); } #endif // __d3dUtilityH__
camera.h
#ifndef __cameraH__ #define __cameraH__ #include <d3dx9.h> class Camera { public: enum CameraType { LANDOBJECT, AIRCRAFT }; Camera(); Camera(CameraType cameraType); ~Camera(); void strafe(float units); void fly(float units); void walk(float units); void pitch(float angles); void yaw(float angles); void roll(float angles); void getViewMatrix(D3DXMATRIX* V); void setCameraType(CameraType cameraType); void getPosition(D3DXVECTOR3* pos); void setPosition(D3DXVECTOR3* pos); void getRight(D3DXVECTOR3* right); void getUp(D3DXVECTOR3* up); void getLook(D3DXVECTOR3* look); private: CameraType _cameraType; D3DXVECTOR3 _right; D3DXVECTOR3 _up; D3DXVECTOR3 _look; D3DXVECTOR3 _pos; }; #endif
Terrain.h
#ifndef __terrainH__ #define __terrainH__ #include "d3dUtility.h" #include <string> #include <vector> class Terrain { public: Terrain(IDirect3DDevice9* device, std::string heightmapFileName, int numVertsPerRow, int numVertsPerCol, int cellSpacing, float heightScale); void draw(D3DXMATRIX* world); ~Terrain(void); 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; bool readRawFile(std::string fileName); bool computeVertices(); bool computeIndices(); struct TerrainVertex { TerrainVertex(){} TerrainVertex(float x, float y, float z, float u, float v) { _x = x; _y = y; _z = z; _u = u; _v = v; } float _x, _y, _z; float _u, _v; static const DWORD FVF; }; }; #endif
d3dUtility.cpp
////////////////////////////////////////////////////////////////////////////////////////////////// // // File: d3dUtility.cpp // // Author: Frank Luna (C) All Rights Reserved // // System: AMD Athlon 1800+ XP, 512 DDR, Geforce 3, Windows XP, MSVC++ 7.0 // // Desc: Provides utility functions for simplifying common tasks. // ////////////////////////////////////////////////////////////////////////////////////////////////// #include "d3dUtility.h" // vertex formats const DWORD d3d::Vertex::FVF = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1; bool d3d::InitD3D( HINSTANCE hInstance, int width, int height, bool windowed, D3DDEVTYPE deviceType, IDirect3DDevice9** device) { // // Create the main application window. // WNDCLASS wc; wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = (WNDPROC)d3d::WndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = LoadIcon(0, IDI_APPLICATION); wc.hCursor = LoadCursor(0, IDC_ARROW); wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wc.lpszMenuName = 0; wc.lpszClassName = "Direct3D9App"; if( !RegisterClass(&wc) ) { ::MessageBox(0, "RegisterClass() - FAILED", 0, 0); return false; } HWND hwnd = 0; hwnd = ::CreateWindow("Direct3D9App", "Direct3D9App", WS_EX_TOPMOST, 0, 0, width, height, 0 /*parent hwnd*/, 0 /* menu */, hInstance, 0 /*extra*/); if( !hwnd ) { ::MessageBox(0, "CreateWindow() - FAILED", 0, 0); return false; } ::ShowWindow(hwnd, SW_SHOW); ::UpdateWindow(hwnd); // // Init D3D: // HRESULT hr = 0; // Step 1: Create the IDirect3D9 object. IDirect3D9* d3d9 = 0; d3d9 = Direct3DCreate9(D3D_SDK_VERSION); if( !d3d9 ) { ::MessageBox(0, "Direct3DCreate9() - FAILED", 0, 0); return false; } // Step 2: Check for hardware vp. 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; // Step 3: Fill out the D3DPRESENT_PARAMETERS structure. D3DPRESENT_PARAMETERS d3dpp; d3dpp.BackBufferWidth = width; d3dpp.BackBufferHeight = height; d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8; d3dpp.BackBufferCount = 1; d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE; d3dpp.MultiSampleQuality = 0; d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; d3dpp.hDeviceWindow = hwnd; d3dpp.Windowed = windowed; d3dpp.EnableAutoDepthStencil = true; d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8; d3dpp.Flags = 0; d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT; d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; // Step 4: Create the device. hr = d3d9->CreateDevice( D3DADAPTER_DEFAULT, // primary adapter deviceType, // device type hwnd, // window associated with device vp, // vertex processing &d3dpp, // present parameters device); // return created device if( FAILED(hr) ) { // try again using a 16-bit depth buffer d3dpp.AutoDepthStencilFormat = D3DFMT_D16; hr = d3d9->CreateDevice( D3DADAPTER_DEFAULT, deviceType, hwnd, vp, &d3dpp, device); if( FAILED(hr) ) { d3d9->Release(); // done with d3d9 object ::MessageBox(0, "CreateDevice() - FAILED", 0, 0); return false; } } d3d9->Release(); // done with d3d9 object return true; } int d3d::EnterMsgLoop( bool (*ptr_display)(float timeDelta) ) { MSG msg; ::ZeroMemory(&msg, sizeof(MSG)); static float lastTime = (float)timeGetTime(); while(msg.message != WM_QUIT) { if(::PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) { ::TranslateMessage(&msg); ::DispatchMessage(&msg); } else { float currTime = (float)timeGetTime(); float timeDelta = (currTime - lastTime)*0.001f; ptr_display(timeDelta); lastTime = currTime; } } return msg.wParam; } D3DLIGHT9 d3d::InitDirectionalLight(D3DXVECTOR3* direction, D3DXCOLOR* color) { D3DLIGHT9 light; ::ZeroMemory(&light, sizeof(light)); light.Type = D3DLIGHT_DIRECTIONAL; light.Ambient = *color * 0.4f; light.Diffuse = *color; light.Specular = *color * 0.6f; light.Direction = *direction; return light; } D3DLIGHT9 d3d::InitPointLight(D3DXVECTOR3* position, D3DXCOLOR* color) { D3DLIGHT9 light; ::ZeroMemory(&light, sizeof(light)); light.Type = D3DLIGHT_POINT; light.Ambient = *color * 0.4f; light.Diffuse = *color; light.Specular = *color * 0.6f; light.Position = *position; light.Range = 1000.0f; light.Falloff = 1.0f; light.Attenuation0 = 1.0f; light.Attenuation1 = 0.0f; light.Attenuation2 = 0.0f; return light; } D3DLIGHT9 d3d::InitSpotLight(D3DXVECTOR3* position, D3DXVECTOR3* direction, D3DXCOLOR* color) { D3DLIGHT9 light; ::ZeroMemory(&light, sizeof(light)); light.Type = D3DLIGHT_SPOT; light.Ambient = *color * 0.4f; light.Diffuse = *color; light.Specular = *color * 0.6f; light.Position = *position; light.Direction = *direction; light.Range = 1000.0f; light.Falloff = 1.0f; light.Attenuation0 = 1.0f; light.Attenuation1 = 0.0f; light.Attenuation2 = 0.0f; light.Theta = 0.5f; light.Phi = 0.7f; return light; } 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; } d3d::BoundingBox::BoundingBox() { // infinite small _min.x = d3d::INFINITY; _min.y = d3d::INFINITY; _min.z = d3d::INFINITY; _max.x = -d3d::INFINITY; _max.y = -d3d::INFINITY; _max.z = -d3d::INFINITY; } bool d3d::BoundingBox::isPointInside(D3DXVECTOR3& p) { if( p.x >= _min.x && p.y >= _min.y && p.z >= _min.z && p.x <= _max.x && p.y <= _max.y && p.z <= _max.z ) { return true; } else { return false; } } d3d::BoundingSphere::BoundingSphere() { _radius = 0.0f; } bool d3d::DrawBasicScene(IDirect3DDevice9* device, float scale) { static IDirect3DVertexBuffer9* floor = 0; static IDirect3DTexture9* tex = 0; static ID3DXMesh* pillar = 0; HRESULT hr = 0; if( device == 0 ) { if( floor && tex && pillar ) { // they already exist, destroy them d3d::Release<IDirect3DVertexBuffer9*>(floor); d3d::Release<IDirect3DTexture9*>(tex); d3d::Release<ID3DXMesh*>(pillar); } } else if( !floor && !tex && !pillar ) { // they don't exist, create them 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, 0); D3DXCreateTextureFromFile( device, "desert.bmp", &tex); } else { // // Pre-Render Setup // device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); device->SetSamplerState(0, D3DSAMP_MINFILTER, 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); // // Render // D3DXMATRIX T, R, P, S; D3DXMatrixScaling(&S, scale, scale, scale); // used to rotate cylinders to be parallel with world's y-axis D3DXMatrixRotationX(&R, -D3DX_PI * 0.5f); // draw floor D3DXMatrixIdentity(&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); } } return true; } float d3d::GetRandomFloat(float lowBound, float highBound) { if( lowBound >= highBound ) // bad input return lowBound; // get random float in [0, 1] interval float 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); }
camera.cpp
////////////////////////////////////////////////////////////////////////////////////////////////// // // File: camera.cpp // // Author: Frank Luna (C) All Rights Reserved // // System: AMD Athlon 1800+ XP, 512 DDR, Geforce 3, Windows XP, MSVC++ 7.0 // // Desc: Defines a camera's position and orientation. // ////////////////////////////////////////////////////////////////////////////////////////////////// #include "camera.h" Camera::Camera() { _cameraType = AIRCRAFT; _pos = D3DXVECTOR3(0.0f, 0.0f, 0.0f); _right = D3DXVECTOR3(1.0f, 0.0f, 0.0f); _up = D3DXVECTOR3(0.0f, 1.0f, 0.0f); _look = D3DXVECTOR3(0.0f, 0.0f, 1.0f); } Camera::Camera(CameraType cameraType) { _cameraType = cameraType; _pos = D3DXVECTOR3(0.0f, 0.0f, 0.0f); _right = D3DXVECTOR3(1.0f, 0.0f, 0.0f); _up = D3DXVECTOR3(0.0f, 1.0f, 0.0f); _look = D3DXVECTOR3(0.0f, 0.0f, 1.0f); } Camera::~Camera() { } void Camera::getPosition(D3DXVECTOR3* pos) { *pos = _pos; } void Camera::setPosition(D3DXVECTOR3* pos) { _pos = *pos; } void Camera::getRight(D3DXVECTOR3* right) { *right = _right; } void Camera::getUp(D3DXVECTOR3* up) { *up = _up; } void Camera::getLook(D3DXVECTOR3* look) { *look = _look; } void Camera::walk(float units) { // move only on xz plane for land object if( _cameraType == LANDOBJECT ) _pos += D3DXVECTOR3(_look.x, 0.0f, _look.z) * units; if( _cameraType == AIRCRAFT ) _pos += _look * units; } void Camera::strafe(float units) { // move only on xz plane for land object if( _cameraType == LANDOBJECT ) _pos += D3DXVECTOR3(_right.x, 0.0f, _right.z) * units; if( _cameraType == AIRCRAFT ) _pos += _right * units; } void Camera::fly(float units) { // move only on y-axis for land object if( _cameraType == LANDOBJECT ) _pos.y += units; if( _cameraType == AIRCRAFT ) _pos += _up * units; } void Camera::pitch(float angle) { D3DXMATRIX T; D3DXMatrixRotationAxis(&T, &_right, angle); // rotate _up and _look around _right vector D3DXVec3TransformCoord(&_up,&_up, &T); D3DXVec3TransformCoord(&_look,&_look, &T); } void Camera::yaw(float angle) { D3DXMATRIX T; // rotate around world y (0, 1, 0) always for land object if( _cameraType == LANDOBJECT ) D3DXMatrixRotationY(&T, angle); // rotate around own up vector for aircraft if( _cameraType == AIRCRAFT ) D3DXMatrixRotationAxis(&T, &_up, angle); // rotate _right and _look around _up or y-axis D3DXVec3TransformCoord(&_right,&_right, &T); D3DXVec3TransformCoord(&_look,&_look, &T); } void Camera::roll(float angle) { // only roll for aircraft type if( _cameraType == AIRCRAFT ) { D3DXMATRIX T; D3DXMatrixRotationAxis(&T, &_look, angle); // rotate _up and _right around _look vector D3DXVec3TransformCoord(&_right,&_right, &T); D3DXVec3TransformCoord(&_up,&_up, &T); } } void Camera::getViewMatrix(D3DXMATRIX* V) { // Keep camera's axes orthogonal to eachother D3DXVec3Normalize(&_look, &_look); D3DXVec3Cross(&_up, &_look, &_right); D3DXVec3Normalize(&_up, &_up); D3DXVec3Cross(&_right, &_up, &_look); D3DXVec3Normalize(&_right, &_right); // Build the view matrix: float x = -D3DXVec3Dot(&_right, &_pos); float y = -D3DXVec3Dot(&_up, &_pos); float z = -D3DXVec3Dot(&_look, &_pos); (*V)(0,0) = _right.x; (*V)(0, 1) = _up.x; (*V)(0, 2) = _look.x; (*V)(0, 3) = 0.0f; (*V)(1,0) = _right.y; (*V)(1, 1) = _up.y; (*V)(1, 2) = _look.y; (*V)(1, 3) = 0.0f; (*V)(2,0) = _right.z; (*V)(2, 1) = _up.z; (*V)(2, 2) = _look.z; (*V)(2, 3) = 0.0f; (*V)(3,0) = x; (*V)(3, 1) = y; (*V)(3, 2) = z; (*V)(3, 3) = 1.0f; } void Camera::setCameraType(CameraType cameraType) { _cameraType = cameraType; }
Terrain.cpp
#include "Terrain.h" #include <fstream> 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; } void Terrain::draw(D3DXMATRIX* world) { _device->SetTransform(D3DTS_WORLD, world); _device->SetStreamSource(0,_vb,0,sizeof(TerrainVertex)); _device->SetFVF(TerrainVertex::FVF); _device->SetIndices(_ib); _device->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME); _device->DrawIndexedPrimitive( D3DPT_TRIANGLELIST, 0,0,_numVertices,0,_numTriangles); _device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID); } bool Terrain::computeVertices() { HRESULT hr = 0; hr = _device->CreateVertexBuffer(_numVertices * sizeof(TerrainVertex), D3DUSAGE_WRITEONLY, TerrainVertex::FVF, D3DPOOL_MANAGED, &_vb, 0); int startX = -_width / 2; int startZ = _depth / 2; int endX = _width / 2; int endZ = -_depth / 2; 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) { int index=i*_numVertsPerRow+j; v[index]=TerrainVertex((float)x, (float)_heightmap[index], (float)z, (float)j*uCoordIncrementSize, (float)i*uCoordIncrementSize); } } _vb->Unlock(); return true; } bool Terrain::computeIndices() { HRESULT hr = 0; hr = _device->CreateIndexBuffer( _numTriangles * 3 * sizeof(DWORD), D3DUSAGE_WRITEONLY, D3DFMT_INDEX16, D3DPOOL_MANAGED, &_ib, 0); if(FAILED(hr)) return false; WORD* indices = 0; _ib->Lock(0,0,(void**)&indices,0); int baseIndex = 0; for(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; baseIndex += 6; } } _ib->Unlock(); return true; } bool Terrain::readRawFile(std::string fileName) { std::vector<BYTE> in(_numVertices); std::ifstream inFile(fileName.c_str(), std::ios_base::binary); if(inFile == 0) return false; inFile.read((char*)&in[0], in.size()); inFile.close(); _heightmap.resize(_numVertices); for(int i=0; i<in.size(); i++) _heightmap[i] = in[i]; return true; } Terrain::~Terrain(void) { }
demo.cpp
#include "d3dUtility.h" #include "camera.h" #pragma comment(lib,"winmm.lib") #pragma comment(lib,"d3d9.lib") #pragma comment(lib,"d3dx9.lib") #pragma comment(lib, "dinput8.lib") #pragma comment(lib,"dxguid.lib") //第1步:添加terrain.h头文件 #include "Terrain.h" // // Globals // IDirect3DDevice9* Device = 0; const int Width = 640; const int Height = 480; Camera TheCamera(Camera::LANDOBJECT); //第2步 定义地形对象变量 Terrain* TheTerrain=0; // // Framework Functions // bool Setup() { D3DXVECTOR3 lightDirection(0.0f, 1.0f, 0.0f); //第3步,实例化地形对象 TheTerrain=new Terrain(Device,"coastMountain64.raw",64,64,10,0.5f); // // Set texture filters. // Device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); Device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); Device->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR); // // Set projection matrix. // D3DXMATRIX proj; D3DXMatrixPerspectiveFovLH( &proj, D3DX_PI * 0.25f, // 45 - degree (float)Width / (float)Height, 1.0f, 1000.0f); Device->SetTransform(D3DTS_PROJECTION, &proj); return true; } void Cleanup() { } bool Display(float timeDelta) { // // Update the scene: // if( Device ) { if( ::GetAsyncKeyState(VK_UP) & 0x8000f ) TheCamera.walk(100.0f * timeDelta); if( ::GetAsyncKeyState(VK_DOWN) & 0x8000f ) TheCamera.walk(-100.0f * timeDelta); if( ::GetAsyncKeyState(VK_LEFT) & 0x8000f ) TheCamera.yaw(-1.0f * timeDelta); if( ::GetAsyncKeyState(VK_RIGHT) & 0x8000f ) TheCamera.yaw(1.0f * timeDelta); if( ::GetAsyncKeyState('N') & 0x8000f ) TheCamera.strafe(-100.0f * timeDelta); if( ::GetAsyncKeyState('M') & 0x8000f ) TheCamera.strafe(100.0f * timeDelta); if( ::GetAsyncKeyState('W') & 0x8000f ) TheCamera.pitch(1.0f * timeDelta); if( ::GetAsyncKeyState('S') & 0x8000f ) TheCamera.pitch(-1.0f * timeDelta); D3DXVECTOR3 pos; TheCamera.getPosition(&pos); 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); TheTerrain->draw(&I); Device->EndScene(); Device->Present(0, 0, 0, 0); } return true; } // // WndProc // LRESULT CALLBACK d3d::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch( msg ) { case WM_DESTROY: ::PostQuitMessage(0); break; case WM_KEYDOWN: if( wParam == VK_ESCAPE ) ::DestroyWindow(hwnd); break; } return ::DefWindowProc(hwnd, msg, wParam, lParam); } // // WinMain // int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE prevInstance, PSTR cmdLine, int showCmd) { if(!d3d::InitD3D(hinstance, Width, Height, true, D3DDEVTYPE_HAL, &Device)) { ::MessageBox(0, "InitD3D() - FAILED", 0, 0); return 0; } if(!Setup()) { ::MessageBox(0, "Setup() - FAILED", 0, 0); return 0; } d3d::EnterMsgLoop( Display ); Cleanup(); Device->Release(); return 0; }