#include<d3d9.h> //Direct3D程式不需的標頭檔
#include<d3dx9.h>//如果要使用D3DX庫就必須加入這個標頭檔
#include<mmsystem.h>
#include<windows.h>
#pragma comment(lib,"d3d9.lib")
#pragma comment(lib,"d3dx9.lib")
#pragma comment(lib,"winmm.lib")
//4個本程式用到的全域變數
LPDIRECT3D9 g_pD3D = NULL; //Direct3D指標
LPDIRECT3DDEVICE9 g_pD3DDevice = NULL;//Direct3D裝置
LPDIRECT3DVERTEXBUFFER9 g_pVB = NULL;//頂點緩衝區指標
LPDIRECT3DINDEXBUFFER9 g_pIB = NULL;//索引緩衝指標
//定義使用到的頂點結構
struct CUSTOMVERTEX
{
FLOAT x,y,z;
DWORD color;
};
//定義上述頂點的FVF結構
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE)
//初始化Direct3D裝置過程函數
HRESULT InitD3D(HWND hWnd)
{
//建立Direct3D對象
if(NULL == (g_pD3D = Direct3DCreate9(D3D_SDK_VERSION)))
{
return E_FAIL;
}
//填寫建立Direct3D裝置結構體
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory(&d3dpp,sizeof(d3dpp));
d3dpp.Windowed = false;//運行在視窗模式
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;//最高效的工作方式
d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;//螢幕緩衝區資料像素格式
//建立Direct3D裝置
if(FAILED(g_pD3D->CreateDevice(D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL,hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,&d3dpp,&g_pD3DDevice)))
{
return E_FAIL;
}
return S_OK;
}
//初始化與本程式繪圖相關的資料函數
HRESULT InitDraw()
{
//建立頂點緩衝區
g_pD3DDevice->CreateVertexBuffer( 8 * sizeof(CUSTOMVERTEX),
D3DUSAGE_WRITEONLY,
D3DFVF_CUSTOMVERTEX,
D3DPOOL_MANAGED,
&g_pVB,
0);
//建立索引緩衝
g_pD3DDevice->CreateIndexBuffer(36 * sizeof(WORD),
D3DUSAGE_WRITEONLY,
D3DFMT_INDEX16,
D3DPOOL_MANAGED,
&g_pIB,
0);
//建立立方體的8個頂點,注意每個頂點的顏色都不同
//在繪製時,Direct3D會根據頂點顏色對三角形內部像素進行插值,所以立方體看起來是彩色的
CUSTOMVERTEX source_vertices[] = {
{-1.0f,-1.0f,-1.0f,D3DCOLOR_XRGB(255,0,0)},
{-1.0f,1.0f,-1.0f,D3DCOLOR_XRGB(0,255,0)},
{1.0f,1.0f,-1.0f,D3DCOLOR_XRGB(0,0,255)},
{1.0f,-1.0f,-1.0f,D3DCOLOR_XRGB(255,255,0)},
{-1.0f,-1.0f,1.0f,D3DCOLOR_XRGB(255,0,255)},
{-1.0f,1.0f,1.0f,D3DCOLOR_XRGB(0,255,255)},
{1.0f,1.0f,1.0f,D3DCOLOR_XRGB(0,0,0)},
{1.0f,-1.0f,1.0f,D3DCOLOR_XRGB(255,255,255)},
};
// 把上面的頂點資料複製到建立的緩衝區內
CUSTOMVERTEX * pVertices;
if(FAILED(g_pVB->Lock(0,8*sizeof(CUSTOMVERTEX),(VOID **)&pVertices,0)))
{
return E_FAIL;
}
memcpy(pVertices,source_vertices,8 * sizeof(CUSTOMVERTEX));
g_pVB->Unlock();
//定義索引緩衝內容,這裡可以手動定義,也可以用數組設定好,然後內容複寫,向上面頂點緩衝區一樣
WORD *indices = 0;
g_pIB->Lock(0,0,(void **) & indices,0);
//正面
indices[0]=0;indices[1]=1;indices[2]=2;
indices[3]=0;indices[4]=2;indices[5]=3;
//背面
indices[6]=4;indices[7]=6;indices[8]=5;
indices[9]=4;indices[10]=7;indices[11]=6;
//左面
indices[12]=4;indices[13]=5;indices[14]=1;
indices[15]=4;indices[16]=1;indices[17]=0;
//右面
indices[18]=3;indices[19]=2;indices[20]=6;
indices[21]=3;indices[22]=6;indices[23]=7;
//頂面
indices[24]=1;indices[25]=5;indices[26]=6;
indices[27]=1;indices[28]=6;indices[29]=2;
//底面
indices[30]=4;indices[31]=0;indices[32]=3;
indices[33]=4;indices[34]=3;indices[35]=7;
g_pIB->Unlock();
//設定攝像機
D3DXVECTOR3 position(0.0f,0.0f,-3.0f);
D3DXVECTOR3 target(0.0f,0.0f,0.0f);
D3DXVECTOR3 up(0.0f,1.0f,0.0f);
D3DXMATRIX V;
D3DXMatrixLookAtLH(&V,&position,&target,&up);
g_pD3DDevice->SetTransform(D3DTS_VIEW,&V);
//設定投影矩陣
D3DXMATRIX proj;
D3DXMatrixPerspectiveFovLH(& proj,
D3DX_PI * 0.5f,
(float)800/(float) 600,
1.0f,
1000.0f);
g_pD3DDevice->SetTransform(D3DTS_PROJECTION,&proj);
//因為沒有使用材質,紋理資訊,所以關閉燈光顯示出本身色彩
g_pD3DDevice->SetRenderState(D3DRS_LIGHTING,FALSE);
return S_OK;
}
void Cleanup()
{
if(g_pVB != NULL)
{
g_pVB->Release();
}
if(g_pIB != NULL)
{
g_pIB->Release();
}
if(g_pD3DDevice != NULL)
{
g_pD3DDevice->Release();
}
if(g_pD3D != NULL)
{
g_pD3D ->Release();
}
}
//渲染函數
void Render()
{
//清除螢幕緩衝區到藍色螢幕
g_pD3DDevice->Clear(0,NULL,D3DCLEAR_TARGET,D3DCOLOR_XRGB(0,0,255),1.0f,0);
//開始繪製
if(SUCCEEDED(g_pD3DDevice->BeginScene()))
{
//建立沿3個軸渲染的矩陣
D3DXMATRIXA16 matWorld_X;
D3DXMatrixIdentity(&matWorld_X);
D3DXMatrixRotationX(&matWorld_X,timeGetTime()/500.0f);
D3DXMATRIXA16 matWorld_Y;
D3DXMatrixIdentity(&matWorld_Y);
D3DXMatrixRotationY(&matWorld_Y,timeGetTime()/500.0f);
D3DXMATRIXA16 matWorld_Z;
D3DXMatrixIdentity(&matWorld_Z);
D3DXMatrixRotationZ(&matWorld_Z,timeGetTime()/500.0f);
//設定物體的世界矩陣
g_pD3DDevice->SetTransform(D3DTS_WORLD,&(matWorld_X*matWorld_Y*matWorld_Z));
//掛接渲染流水線,設定FVF值,設定索引,渲染
g_pD3DDevice->SetStreamSource(0,g_pVB,0,sizeof( CUSTOMVERTEX));
g_pD3DDevice->SetFVF(D3DFVF_CUSTOMVERTEX);
g_pD3DDevice->SetIndices(g_pIB);
g_pD3DDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,0,0,8,0,12);
//結束繪製
g_pD3DDevice->EndScene();
}
//顯示到螢幕
g_pD3DDevice->Present(NULL,NULL,NULL,NULL);
}
//訊息回呼函數。只處理退出訊息,所以滑鼠一直顯示忙狀態
LRESULT WINAPI MsgProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
switch(msg)
{
case WM_DESTROY:
Cleanup();
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd,msg,wParam,lParam);
}
INT WINAPI WinMain(HINSTANCE hInst,HINSTANCE , LPSTR,INT)
{
//註冊視窗
WNDCLASSEX wc = {sizeof(WNDCLASSEX),CS_CLASSDC,MsgProc,0L,0L,
GetModuleHandle(NULL),NULL,NULL,NULL,NULL,"D3D Tutorical",NULL
};
RegisterClassEx(&wc);
//建立視窗
HWND hWnd = CreateWindow("D3D Tutorical",
"3D立方體",
WS_OVERLAPPEDWINDOW,
100,
100,
800,
600,
GetDesktopWindow(),
NULL,
wc.hInstance,
NULL);
//嵌套if保證全部初始化成功才可以進入迴圈運行
if(SUCCEEDED (InitD3D(hWnd)))
{
if(SUCCEEDED(InitDraw()))
{
//顯示視窗
ShowWindow(hWnd,SW_SHOWDEFAULT);
UpdateWindow(hWnd);
//最佳化的訊息迴圈
MSG msg;
ZeroMemory(&msg,sizeof(msg));
while(msg.message != WM_QUIT)
{
if(PeekMessage(&msg,NULL,0U,0U,PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
Render();
}
}
}
}
UnregisterClass("D3D Tutorical",wc.hInstance);
return 0;
}