地形

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__
View Code

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
View Code

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
View Code

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);
}
View Code

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;
}
View Code

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)
{
}
View Code

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;
}
View Code

 

posted @ 2022-05-24 11:45  szmtjs10  阅读(142)  评论(0编辑  收藏  举报