vc.net 游戏开发 第四章 创建Direct3D渲染和显示3D三角形

来源:互联网 发布:淘宝的会员名可以改吗 编辑:程序博客网 时间:2024/05/01 14:27
//*********************************************
//功能:创建Direct3D渲染和显示3D三角形
//作者:张小斌
//时间:2005.4.1
//*********************************************
//防止链接出错
#pragma comment(lib,"d3d9.lib")
#pragma comment(lib,"d3dx9.lib")
#pragma comment(lib,"dinput8.lib")
#pragma comment(lib,"dxguid.lib")

#include<windows.h>//windows程序你不包含着是不可能的
#include<d3d9.h>//即然是DX9程序那肯定是需要包含着个头文件的

//接下来定义一个Windows类的宏名称
#define MY_WINCLASS_NAME "Direct3d"
//定义定点的类型格式
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE)
//创建一个顶点缓冲区结构,用于创建定点缓冲区
LPDIRECT3DVERTEXBUFFER9 g_pVB = NULL;

HWND hWnd;

//养成好习惯先声明一下
HRESULT InitMy3D(HWND hWnd);
void Cleanup();
LRESULT WINAPI MsgProc(HWND hWnd,UINT msg ,WPARAM wParam,LPARAM lParam);
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrecInstance, LPSTR lpCmdLine, int nCmdShow);
void RenderSene();
HRESULT InitVB();

//记着程序是Direct3d编程时,我们必须先创建Direct3D对象,在程序结束的时候,也必须最后释放该对象。
//为了保存创建的Direct3D对象和设备,那我们就需要以下的两个全局变量

//在这碰到点问题编译的时候到这不能正常编译,再把下面这两个在手工的重写一边,别偷懒,一个字一个字的敲。
LPDIRECT3D9      pD3D = NULL;
LPDIRECT3DDEVICE9 pDev = NULL;
//顶点结构
struct CUSTOMVERTEX
{
FLOAT x, y, z; // x,y,z表示点的三维坐标值,
    DWORD color;        // 顶点颜色
};

HRESULT InitVB()
{
//初始化3个顶点
CUSTOMVERTEX g_Vertices[] =
{
        //需要注意绘制的顺序
 {  0.0f,  1.0f, 0.0f, D3DCOLOR_XRGB(255, 0 , 0 ), }, // x, y, z, color
         {  1.0f, -1.0f, 0.0f, D3DCOLOR_XRGB( 0 ,255,255), },
         { -1.0f, -1.0f, 0.0f, D3DCOLOR_XRGB(255,255,255), }

};
//定义一个指针,用于复制顶点数据是指向定点缓冲区的内存结构
    VOID* pVertices;
//创建顶点缓冲区
if( FAILED( pDev->CreateVertexBuffer( 3*sizeof(CUSTOMVERTEX), 0, D3DFVF_CUSTOMVERTEX,D3DPOOL_DEFAULT, &g_pVB, NULL ) ) )
    {
        return E_FAIL;
    }
//把顶点数据从顶点数组中复制到顶点缓冲区中
    if( FAILED( g_pVB->Lock( 0, sizeof(g_Vertices), (void**)&pVertices, 0 ) ) )
        return E_FAIL;
    memcpy( pVertices, g_Vertices, sizeof(g_Vertices) );
    g_pVB->Unlock();

    return S_OK;
}

//----------------------------------------------------------------------------------------------
//方法名:RenderSene()
//功  能:定义了一个渲染函数,这个函数完成渲染开关的打开,关闭操作以及展现后台表面到客户区域中
//注  意:
//----------------------------------------------------------------------------------------------
void RenderSene()
{
//检查Direct3D设备是否创建,如果没有创建就直接返回
if(NULL == pDev)
return;
//清除Direct3D设备的后台表面,背景颜色RGB(0,0,0)
pDev->Clear(0,NULL,D3DCLEAR_TARGET,D3DCOLOR_XRGB(255,0,255),1.0f,0);
//大开3D渲染开关
if( SUCCEEDED( pDev->BeginScene() ) )
{
//进行3D渲染,在这里设置渲染的定点格式,并调用DrawPrimitive完成顶点渲染的处理
//设置泫然的顶点来源
pDev->SetStreamSource( 0, g_pVB, 0, sizeof(CUSTOMVERTEX) );
//设置代渲染顶点的定点格式
pDev->SetFVF(D3DFVF_CUSTOMVERTEX);
//渲染指定了缓冲区来源的顶点
pDev->DrawPrimitive(D3DPT_TRIANGLELIST,0,1);
//关闭3D渲染开关
pDev->EndScene();
}
else
{
MessageBox(hWnd,"3D渲染开关未打开!","出错!",MB_OK);

}
//展现后台表面带窗口的客户区域中,即把渲染后的图象显示到窗口中
pDev->Present(NULL,NULL,NULL,NULL);

}

//到这就要开始写方法了既然是DX9程序那就要初始化D3D的环境
//---------------------------------------------------------
//方法名:InitD3D()
//功 能:初始化D3D环境,函数创建了Direct3D对象和Direct3D设备。
//注 意:函数返回E_FAIL表示失败,返回E_OK表示成功
//    说到这了就需要提到一些额外的知识
//  在Direct3D中,提供了两个宏专门用于测试函数是否调用成功。
//        1. FAILED()----对该函数返回的错误进行测试,如果函数返回任何错误信息,该测试之为真。
//    2.SUCCEEDED()--对函数执行是否成功进行测试,如函数执行成功,值为真.
//---------------------------------------------------------

HRESULT InitMy3D(HWND hWnd)
{
if( NULL == ( pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) )
        return E_FAIL;
//创建Direct3D对象,这是使用Direct3D的第一步操作
if(NULL == ( pD3D = Direct3DCreate9( D3D_SDK_VERSION )))
return E_FAIL;

//获取当前Windows桌面的显示模式,保存到定义的d3ddm结构中
D3DDISPLAYMODE d3ddm;
//到这用到了上面“注意”中提到的宏。
//看好了当写到pD3D->时输入了">"这个符号而没有出现下拉列表那就是前面你写错了,赶快去查错。
if( FAILED( pD3D->GetAdapterDisplayMode( D3DADAPTER_DEFAULT,&d3ddm)))
return E_FAIL;

//定义Presend结构
D3DPRESENT_PARAMETERS d3dpp;

//把结构清零,创建设备时,结构成员值为0表示使用缺省值
ZeroMemory(&d3dpp,sizeof(d3dpp));

//制定创建的Direct3D是支持窗口的设备
d3dpp.Windowed = TRUE;

//指定交换效果为D3DSWAPEFFECT_DISCARD,即把后台表面显示到前台表面以后
//原来的后台表面包含的信息自动丢失
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;

//后台缓冲区的点格式与当前显示模式的点格式一致
d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;

//D3D对象都创建了那就该创建Direct3D设备了
//1。使用主显卡创建设备,参数D3DADAPTER_DEFAULT.(如果你的计算机里插了两块显卡那你就的指定清楚,看来微软早遇见了PCI_E的出现)
//2。设备类型为硬件抽象设备,使用硬件加速能,参数D3DDEVTYPE_HAL
//3。使用前面创建的窗口用于目标表面的显示,参数hWnd
//4。指定设备对于顶点的处理能力为软件处理顶点,这是为了让所有的显卡制持,参数
// D3DCREATE_SOFTWARE_VERTEXPROCESSING

if(FAILED(pD3D->CreateDevice(D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL,hWnd,D3DCREATE_SOFTWARE_VERTEXPROCESSING,&d3dpp,&pDev)))
{
return E_FAIL;
}
return S_OK;
//把上面的看明白了最后的三行你就知道是干吗的了
}

//-----------------------------------------------------------------------------------------------
//方法名:Cleanup()
//功  能:释放创建过的Direct3D对象和设备
//注  意:C++可不是JAVA有垃圾回收机制,你得把你申请的资源在用完后还给电脑
//-----------------------------------------------------------------------------------------------
void Cleanup()
{
//在上次建立D3D设备中我们没有建立顶点缓冲区,这次用到了,用完了就的释放
if( g_pVB != NULL )        
        g_pVB->Release();
//释放时的顺序为先释放创建的设备后释放对象
if(pDev !=NULL)
pDev->Release();
//Direct3D对象最先创建,但需要最后释放
if(pD3D != NULL)
pD3D->Release();
return;
//如果你不明白为何这样释放,去把你的C++在复习一下
}
//-------------------------------------------------------------------------------------------------------------------
//方法名:MsgProc()
//功  能:Windows的详细处理函数
//注  意:消息是游戏程序的另一个重点,它用于处理键盘,鼠标,遥杆的响应以及触发的事件
//        如:主角挥剑砍怪物会发生剑和怪物的碰撞,就需要把这一消息处理是打怪物没打上还是打上,打伤了如何计算伤害等等。
//-------------------------------------------------------------------------------------------------------------------
LRESULT WINAPI MsgProc(HWND hWnd,UINT msg ,WPARAM wParam,LPARAM lParam)
{
switch(msg)
{
case WM_DESTROY:
//调用Cleanup函数清除3D对象和设备
Cleanup();
PostQuitMessage(0);
return 0;
case WM_RBUTTONDOWN:
RenderSene();
return 0;
}
return DefWindowProc(hWnd,msg,wParam,lParam);
}
//--------------------------------------------------------------------------------------------------------------------
//方法名:WinMain()
//功  能:Windows主函数,程序启动时,从这里开始
//注  意:你要是不写他,你就完了
//--------------------------------------------------------------------------------------------------------------------
int APIENTRY WinMain(HINSTANCE hInstance,    //hInstance:表示该应用程序的句柄
 HINSTANCE hPrecInstance,//hPrevInstance:为了保持与16位windows应用程序的兼容性
 LPSTR lpCmdLine,        //lpCmdLine:指向命令行参数字符串的指针
 int nCmdShow)           //nCmdShow:指定应用程序窗口显示方式的整数

{
//定义一个类,指定消息的处理函数为MsgProc
WNDCLASSEX wc = {sizeof(WNDCLASSEX),CS_CLASSDC,MsgProc,0l,0l,
 GetModuleHandle(NULL),NULL,NULL,NULL,NULL,
 MY_WINCLASS_NAME,NULL};
//注册这个窗口类
RegisterClassEx(&wc);

//创建应用程序窗口
hWnd = CreateWindow(MY_WINCLASS_NAME,"3D游戏编程--渲染和显示3D三角形",
WS_OVERLAPPEDWINDOW,100,100,400,300,
GetDesktopWindow(),NULL,wc.hInstance,NULL);
//调用InitMy3D函数对3D对象和设备初始化,传入的参数为窗口的句柄hWnd
if(SUCCEEDED(InitMy3D( hWnd)))
{
//调用InitVB函数初始化顶点结构
if(SUCCEEDED(InitVB()))
{
//显示窗口
ShowWindow(hWnd,SW_SHOWDEFAULT);
UpdateWindow(hWnd);

//程序主循环,进行窗口消息的分发,消息的处理在MsgProc函数中完成
MSG msg;
ZeroMemory( &msg, sizeof(msg) );
while( msg.message!=WM_QUIT )
            {
                if( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) )
                {
                    TranslateMessage( &msg );
                    DispatchMessage( &msg );
                }
else
{
RenderSene();
}
}
}
}


//注销窗口类
UnregisterClass(MY_WINCLASS_NAME,wc.hInstance);

return 0;
}