學習一樣東西,最好能夠從最基礎做起。學習D3D,筆者並不贊同直接繼承SDK Sample的CD3DApplication,然後override那幾個虛函數,因爲這樣會讓初學者對D3D更感神祕,因此我們需要從頭開始,不用害怕,其實一點都不難:)
一、Win32 SDK框架
看過Petzold的《Windows程序設計》的朋友應該知道創建窗口的固定步驟。而利用Win32 SDK搭建D3D框架只不過是在這些步驟中加入一些調料罷了。具體步驟如下:
1、註冊窗體類;
2、創建窗口;
3、創建消息處理函數;
4、顯示窗口;
5、初始化D3D、初始化資源數據(如:頂點向量、紋理等);
6、進入消息循環,用PeekMessage處理消息,以便在空閒時進行渲染。
2、創建窗口;
3、創建消息處理函數;
4、顯示窗口;
5、初始化D3D、初始化資源數據(如:頂點向量、紋理等);
6、進入消息循環,用PeekMessage處理消息,以便在空閒時進行渲染。
而初始化D3D又分下面四個步驟:
1、創建IDirect3D9[1]對象;
2、檢查硬件性能,判斷硬件是否支持特定的功能;
3、填充D3DPRESENT_PARAMETERS結構;
4、利用第3步中的結構體對象創建D3D設備(由於該步驟需要窗體的句柄,所以初始化D3D必須放在顯示窗口之後)。
2、檢查硬件性能,判斷硬件是否支持特定的功能;
3、填充D3DPRESENT_PARAMETERS結構;
4、利用第3步中的結構體對象創建D3D設備(由於該步驟需要窗體的句柄,所以初始化D3D必須放在顯示窗口之後)。
下面是框架代碼:
000001 //
000002 // 全局變量
000003 //
000004
000005 IDirect3DDevice9* Device = 0;
000006
000007
000008 bool InitD3D(
000009 HINSTANCE hInstance,
000010 int width, int height,
000011 bool windowed,
000012 D3DDEVTYPE deviceType,
000013 IDirect3DDevice9** device)
000014 {
000015 WNDCLASS wc;
000016
000017 wc.style = CS_HREDRAW | CS_VREDRAW;
000018 wc.lpfnWndProc = (WNDPROC)WndProc;
000019 wc.cbClsExtra = 0;
000020 wc.cbWndExtra = 0;
000021 wc.hInstance = hInstance;
000022 wc.hIcon = LoadIcon(0, IDI_APPLICATION);
000023 wc.hCursor = LoadCursor(0, IDC_ARROW);
000024 wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
000025 wc.lpszMenuName = 0;
000026 wc.lpszClassName = "Direct3D9App";
000027 // 註冊窗口類
000028 if( !RegisterClass(&wc) )
000029 {
000030 MessageBox(0, "RegisterClass() - FAILED", 0, 0);
000031 return false;
000032 }
000033
000034 HWND hwnd = 0;
000035 // 創建窗口
000036 hwnd = CreateWindow("Direct3D9App", "Direct3D9App",
000037 WS_EX_TOPMOST,
000038 0, 0, width, height,
000039 0 /*parent hwnd*/, 0 /* menu */, hInstance, 0 /*extra*/);
000040
000041 if( !hwnd )
000042 {
000043 MessageBox(0, "CreateWindow() - FAILED", 0, 0);
000044 return false;
000045 }
000046 // 顯示窗口
000047 ShowWindow(hwnd, SW_SHOW);
000048 UpdateWindow(hwnd);
000049
000050 //
000051 // 初始化D3D
000052 //
000053
000054 HRESULT hr = 0;
000055
000056 // 步驟1:創建IDirect3D9對象。
000057
000058 IDirect3D9* d3d9 = 0;
000059 d3d9 = Direct3DCreate9(D3D_SDK_VERSION);
000060
000061 if( !d3d9 )
000062 {
000063 MessageBox(0, "Direct3DCreate9() - FAILED", 0, 0);
000064 return false;
000065 }
000066
000067 // 步驟2:檢查硬件性能(這裏只檢查了是否支持頂點的硬件處理)
000068
000069 D3DCAPS9 caps;
000070 d3d9->GetDeviceCaps(D3DADAPTER_DEFAULT, deviceType, &caps);
000071
000072 int vp = 0;
000073 if( caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT )
000074 vp = D3DCREATE_HARDWARE_VERTEXPROCESSING;
000075 else
000076 vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
000077
000078 // 步驟3:填充D3DPRESENT_PARAMETERS結構(參數說明請參考MSDN)
000079
000080 D3DPRESENT_PARAMETERS d3dpp;
000081 d3dpp.BackBufferWidth = width;
000082 d3dpp.BackBufferHeight = height;
000083 d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8;
000084 d3dpp.BackBufferCount = 1;
000085 d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
000086 d3dpp.MultiSampleQuality = 0;
000087 d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
000088 d3dpp.hDeviceWindow = hwnd;
000089 d3dpp.Windowed = windowed;
000090 d3dpp.EnableAutoDepthStencil = true;
000091 d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;
000092 d3dpp.Flags = 0;
000093 d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
000094 d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
000095
000096 // 步驟4:創建D3D設備
000097
000098 hr = d3d9->CreateDevice(
000099 D3DADAPTER_DEFAULT, // 主設備
000100 deviceType, // 設備類型
000101 hwnd, // 分配給設備的窗口句柄
000102 vp, // 頂點處理方式
000103 &d3dpp, // 表現參數
000104 device); // 返回創建的設備
000105
000106 if( FAILED(hr) )
000107 {
000108 // 如果創建失敗,採用16爲深度緩存試試
000109 d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
000110
000111 hr = d3d9->CreateDevice(
000112 D3DADAPTER_DEFAULT,
000113 deviceType,
000114 hwnd,
000115 vp,
000116 &d3dpp,
000117 device);
000118
000119 if( FAILED(hr) )
000120 {
000121 d3d9->Release();
000122 MessageBox(0, "CreateDevice() - FAILED", 0, 0);
000123 return false;
000124 }
000125 }
000126
000127 d3d9->Release();
000128
000129 return true;
000130 }
000131
000132 // 消息循環
000133 int MsgLoop()
000134 {
000135 MSG msg;
000136 ZeroMemory(&msg, sizeof(MSG));
000137
000138 while(msg.message != WM_QUIT)
000139 {
000140 if(PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
000141 {
000142 TranslateMessage(&msg);
000143 DispatchMessage(&msg);
000144 }
000145 else
000146 {
000147 Display(); // 渲染
000148 }
000149 }
000150 return msg.wParam;
000151 }
000152
000153
000154 //
000155 // 框架函數
000156 //
000157
000158 bool Setup()
000159 {
000160 // 你可以在此初始化頂點向量、載入紋理等
000161
000162 return true;
000163 }
000164
000165 void Cleanup()
000166 {
000167 // 清除在Setup中載入的資源
000168 }
000169
000170 bool Display()
000171 {
000172 if( Device ) // 只有當設備有效時才能渲染
000173 {
000174 // 在此填入渲染代碼
000175 }
000176 return true;
000177 }
000178
000179 //
000180 // 窗口處理函數
000181 //
000182 LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
000183 {
000184 switch( msg )
000185 {
000186 case WM_DESTROY:
000187 PostQuitMessage(0);
000188 break;
000189
000190 case WM_KEYDOWN:
000191 if( wParam == VK_ESCAPE )
000192 DestroyWindow(hwnd);
000193 break;
000194 }
000195 return DefWindowProc(hwnd, msg, wParam, lParam);
000196 }
000197
000198 //
000199 // 程序入口
000200 //
000201 int WINAPI WinMain(HINSTANCE hinstance,
000202 HINSTANCE prevInstance,
000203 PSTR cmdLine,
000204 int showCmd)
000205 {
000206 if(!InitD3D(hinstance,
000207 640, 480, true, D3DDEVTYPE_HAL, &Device))
000208 {
000209 MessageBox(0, "InitD3D() - FAILED", 0, 0);
000210 return 0;
000211 }
000212
000213 if(!Setup())
000214 {
000215 MessageBox(0, "Setup() - FAILED", 0, 0);
000216 return 0;
000217 }
000218
000219 MsgLoop();
000220
000221 Cleanup();
000222
000223 Device->Release();
000224
000225 return 0;
000226 }
000002 // 全局變量
000003 //
000004
000005 IDirect3DDevice9* Device = 0;
000006
000007
000008 bool InitD3D(
000009 HINSTANCE hInstance,
000010 int width, int height,
000011 bool windowed,
000012 D3DDEVTYPE deviceType,
000013 IDirect3DDevice9** device)
000014 {
000015 WNDCLASS wc;
000016
000017 wc.style = CS_HREDRAW | CS_VREDRAW;
000018 wc.lpfnWndProc = (WNDPROC)WndProc;
000019 wc.cbClsExtra = 0;
000020 wc.cbWndExtra = 0;
000021 wc.hInstance = hInstance;
000022 wc.hIcon = LoadIcon(0, IDI_APPLICATION);
000023 wc.hCursor = LoadCursor(0, IDC_ARROW);
000024 wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
000025 wc.lpszMenuName = 0;
000026 wc.lpszClassName = "Direct3D9App";
000027 // 註冊窗口類
000028 if( !RegisterClass(&wc) )
000029 {
000030 MessageBox(0, "RegisterClass() - FAILED", 0, 0);
000031 return false;
000032 }
000033
000034 HWND hwnd = 0;
000035 // 創建窗口
000036 hwnd = CreateWindow("Direct3D9App", "Direct3D9App",
000037 WS_EX_TOPMOST,
000038 0, 0, width, height,
000039 0 /*parent hwnd*/, 0 /* menu */, hInstance, 0 /*extra*/);
000040
000041 if( !hwnd )
000042 {
000043 MessageBox(0, "CreateWindow() - FAILED", 0, 0);
000044 return false;
000045 }
000046 // 顯示窗口
000047 ShowWindow(hwnd, SW_SHOW);
000048 UpdateWindow(hwnd);
000049
000050 //
000051 // 初始化D3D
000052 //
000053
000054 HRESULT hr = 0;
000055
000056 // 步驟1:創建IDirect3D9對象。
000057
000058 IDirect3D9* d3d9 = 0;
000059 d3d9 = Direct3DCreate9(D3D_SDK_VERSION);
000060
000061 if( !d3d9 )
000062 {
000063 MessageBox(0, "Direct3DCreate9() - FAILED", 0, 0);
000064 return false;
000065 }
000066
000067 // 步驟2:檢查硬件性能(這裏只檢查了是否支持頂點的硬件處理)
000068
000069 D3DCAPS9 caps;
000070 d3d9->GetDeviceCaps(D3DADAPTER_DEFAULT, deviceType, &caps);
000071
000072 int vp = 0;
000073 if( caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT )
000074 vp = D3DCREATE_HARDWARE_VERTEXPROCESSING;
000075 else
000076 vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
000077
000078 // 步驟3:填充D3DPRESENT_PARAMETERS結構(參數說明請參考MSDN)
000079
000080 D3DPRESENT_PARAMETERS d3dpp;
000081 d3dpp.BackBufferWidth = width;
000082 d3dpp.BackBufferHeight = height;
000083 d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8;
000084 d3dpp.BackBufferCount = 1;
000085 d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
000086 d3dpp.MultiSampleQuality = 0;
000087 d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
000088 d3dpp.hDeviceWindow = hwnd;
000089 d3dpp.Windowed = windowed;
000090 d3dpp.EnableAutoDepthStencil = true;
000091 d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;
000092 d3dpp.Flags = 0;
000093 d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
000094 d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
000095
000096 // 步驟4:創建D3D設備
000097
000098 hr = d3d9->CreateDevice(
000099 D3DADAPTER_DEFAULT, // 主設備
000100 deviceType, // 設備類型
000101 hwnd, // 分配給設備的窗口句柄
000102 vp, // 頂點處理方式
000103 &d3dpp, // 表現參數
000104 device); // 返回創建的設備
000105
000106 if( FAILED(hr) )
000107 {
000108 // 如果創建失敗,採用16爲深度緩存試試
000109 d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
000110
000111 hr = d3d9->CreateDevice(
000112 D3DADAPTER_DEFAULT,
000113 deviceType,
000114 hwnd,
000115 vp,
000116 &d3dpp,
000117 device);
000118
000119 if( FAILED(hr) )
000120 {
000121 d3d9->Release();
000122 MessageBox(0, "CreateDevice() - FAILED", 0, 0);
000123 return false;
000124 }
000125 }
000126
000127 d3d9->Release();
000128
000129 return true;
000130 }
000131
000132 // 消息循環
000133 int MsgLoop()
000134 {
000135 MSG msg;
000136 ZeroMemory(&msg, sizeof(MSG));
000137
000138 while(msg.message != WM_QUIT)
000139 {
000140 if(PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
000141 {
000142 TranslateMessage(&msg);
000143 DispatchMessage(&msg);
000144 }
000145 else
000146 {
000147 Display(); // 渲染
000148 }
000149 }
000150 return msg.wParam;
000151 }
000152
000153
000154 //
000155 // 框架函數
000156 //
000157
000158 bool Setup()
000159 {
000160 // 你可以在此初始化頂點向量、載入紋理等
000161
000162 return true;
000163 }
000164
000165 void Cleanup()
000166 {
000167 // 清除在Setup中載入的資源
000168 }
000169
000170 bool Display()
000171 {
000172 if( Device ) // 只有當設備有效時才能渲染
000173 {
000174 // 在此填入渲染代碼
000175 }
000176 return true;
000177 }
000178
000179 //
000180 // 窗口處理函數
000181 //
000182 LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
000183 {
000184 switch( msg )
000185 {
000186 case WM_DESTROY:
000187 PostQuitMessage(0);
000188 break;
000189
000190 case WM_KEYDOWN:
000191 if( wParam == VK_ESCAPE )
000192 DestroyWindow(hwnd);
000193 break;
000194 }
000195 return DefWindowProc(hwnd, msg, wParam, lParam);
000196 }
000197
000198 //
000199 // 程序入口
000200 //
000201 int WINAPI WinMain(HINSTANCE hinstance,
000202 HINSTANCE prevInstance,
000203 PSTR cmdLine,
000204 int showCmd)
000205 {
000206 if(!InitD3D(hinstance,
000207 640, 480, true, D3DDEVTYPE_HAL, &Device))
000208 {
000209 MessageBox(0, "InitD3D() - FAILED", 0, 0);
000210 return 0;
000211 }
000212
000213 if(!Setup())
000214 {
000215 MessageBox(0, "Setup() - FAILED", 0, 0);
000216 return 0;
000217 }
000218
000219 MsgLoop();
000220
000221 Cleanup();
000222
000223 Device->Release();
000224
000225 return 0;
000226 }
二、MFC框架
利用MFC,我們不用寫一行代碼就可以創建一個窗體,這是MFC封裝了那些繁瑣而固定的窗口創建代碼,這樣我們只需要初始化D3D就可以了。下面是通過不帶文檔的SDI 作爲示例來創建D3D的框架,具體步驟如下:
1、將InitD3D、Setup、Cleanup、Display作爲CMainFrame的成員函數,其中InitD3D需被應用程序類調用,應該將其置爲public,其餘爲內部函數;
2、在應用程序類(CWinApp的子類)的InitInstance()中顯示窗口之後,對D3D進行初始化;
3、override Run(),其實,這裏就是消息循環;
2、在應用程序類(CWinApp的子類)的InitInstance()中顯示窗口之後,對D3D進行初始化;
3、override Run(),其實,這裏就是消息循環;
這裏需要注意:
填充D3DPRESENT_PARAMETERS時,BackBufferWidth和BackBufferHeight最好設置爲客戶區大小,hDeviceWindow設置爲視窗口的句柄m_wndView.m_hWnd,最重要的是Windowed[2]一定要置爲true,否則會產生“無效調用”的錯誤。
下面是實際代碼,該代碼渲染了一個帶貼圖的旋轉正方體:
000001 // MFCD3D.cpp : 定義應用程序的類行爲。
000002 //
000003
000004 #include "stdafx.h"
000005 #include "MFCD3D.h"
000006 #include "MainFrm.h"
000007 #include <mmsystem.h>
000008
000009 #ifdef _DEBUG
000010 #define new DEBUG_NEW
000011 #endif
000012
000013
000014 // CMFCD3DApp
000015
000016 BEGIN_MESSAGE_MAP(CMFCD3DApp, CWinApp)
000017 ON_COMMAND(ID_APP_ABOUT, OnAppAbout)
000018 END_MESSAGE_MAP()
000019
000020
000021 // CMFCD3DApp 構造
000022
000023 CMFCD3DApp::CMFCD3DApp()
000024 {
000025 // TODO: 在此處添加構造代碼,
000026 // 將所有重要的初始化放置在 InitInstance 中
000027 }
000028
000029
000030 // 唯一的一個 CMFCD3DApp 對象
000031
000032 CMFCD3DApp theApp;
000033
000034 // CMFCD3DApp 初始化
000035
000036 BOOL CMFCD3DApp::InitInstance()
000037 {
000038 // 如果一個運行在 Windows XP 上的應用程序清單指定要
000039 // 使用 ComCtl32.dll 版本 6 或更高版本來啓用可視化方式,
000040 //則需要 InitCommonControls()。否則,將無法創建窗口。
000041 InitCommonControls();
000042
000043 CWinApp::InitInstance();
000044
000045 // 初始化 OLE 庫
000046 if (!AfxOleInit())
000047 {
000048 AfxMessageBox(IDP_OLE_INIT_FAILED);
000049 return FALSE;
000050 }
000051 AfxEnableControlContainer();
000052 // 標準初始化
000053 // 如果未使用這些功能並希望減小
000054 // 最終可執行文件的大小,則應移除下列
000055 // 不需要的特定初始化例程
000056 // 更改用於存儲設置的註冊表項
000057 // TODO: 應適當修改該字符串,
000058 // 例如修改爲公司或組織名
000059 SetRegistryKey(_T("應用程序嚮導生成的本地應用程序"));
000060 // 若要創建主窗口,此代碼將創建新的框架窗口
000061 // 對象,然後將其設置爲應用程序的主窗口對象
000062 CMainFrame* pFrame = new CMainFrame;
000063 if (!pFrame)
000064 return FALSE;
000065 m_pMainWnd = pFrame;
000066 // 創建並加載帶有其資源的框架
000067 pFrame->LoadFrame(IDR_MAINFRAME,
000068 WS_OVERLAPPEDWINDOW | FWS_ADDTOTITLE, NULL,
000069 NULL);
000070 // 唯一的一個窗口已初始化,因此顯示它並對其進行更新
000071 pFrame->ShowWindow(SW_SHOW);
000072 pFrame->UpdateWindow();
000073 // 僅當存在後綴時才調用 DragAcceptFiles,
000074 // 在 SDI 應用程序中,這應在 ProcessShellCommand 之後發生
000075 // D3D初始化
000076 return pFrame->InitD3D();
000077 }
000078
000079
000080 // CMFCD3DApp 消息處理程序
000081
000082
000083
000084 // 用於應用程序“關於”菜單項的 CAboutDlg 對話框
000085
000086 class CAboutDlg : public CDialog
000087 {
000088 public:
000089 CAboutDlg();
000090
000091 // 對話框數據
000092 enum { IDD = IDD_ABOUTBOX };
000093
000094 protected:
000095 virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
000096
000097 // 實現
000098 protected:
000099 DECLARE_MESSAGE_MAP()
000100 };
000101
000102 CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
000103 {
000104 }
000105
000106 void CAboutDlg::DoDataExchange(CDataExchange* pDX)
000107 {
000108 CDialog::DoDataExchange(pDX);
000109 }
000110
000111 BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
000112 END_MESSAGE_MAP()
000113
000114 // 用於運行對話框的應用程序命令
000115 void CMFCD3DApp::OnAppAbout()
000116 {
000117 CAboutDlg aboutDlg;
000118 aboutDlg.DoModal();
000119 }
000120
000121
000122 // CMFCD3DApp 消息處理程序
000123
000124
000125 int CMFCD3DApp::Run()
000126 {
000127 MSG msg;
000128 ::ZeroMemory(&msg, sizeof(MSG));
000129
000130 static float lastTime = (float)timeGetTime();
000131
000132 while(msg.message != WM_QUIT)
000133 {
000134 if(::PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
000135 {
000136 ::TranslateMessage(&msg);
000137 ::DispatchMessage(&msg);
000138 }
000139 else
000140 {
000141 float currTime = (float)timeGetTime();
000142 float timeDelta = (currTime - lastTime)*0.001f;
000143 lastTime = currTime;
000144
000145 ((CMainFrame*)m_pMainWnd)->Render(timeDelta);
000146 }
000147 }
000148 return CWinApp::Run();
000149 }
000002 //
000003
000004 #include "stdafx.h"
000005 #include "MFCD3D.h"
000006 #include "MainFrm.h"
000007 #include <mmsystem.h>
000008
000009 #ifdef _DEBUG
000010 #define new DEBUG_NEW
000011 #endif
000012
000013
000014 // CMFCD3DApp
000015
000016 BEGIN_MESSAGE_MAP(CMFCD3DApp, CWinApp)
000017 ON_COMMAND(ID_APP_ABOUT, OnAppAbout)
000018 END_MESSAGE_MAP()
000019
000020
000021 // CMFCD3DApp 構造
000022
000023 CMFCD3DApp::CMFCD3DApp()
000024 {
000025 // TODO: 在此處添加構造代碼,
000026 // 將所有重要的初始化放置在 InitInstance 中
000027 }
000028
000029
000030 // 唯一的一個 CMFCD3DApp 對象
000031
000032 CMFCD3DApp theApp;
000033
000034 // CMFCD3DApp 初始化
000035
000036 BOOL CMFCD3DApp::InitInstance()
000037 {
000038 // 如果一個運行在 Windows XP 上的應用程序清單指定要
000039 // 使用 ComCtl32.dll 版本 6 或更高版本來啓用可視化方式,
000040 //則需要 InitCommonControls()。否則,將無法創建窗口。
000041 InitCommonControls();
000042
000043 CWinApp::InitInstance();
000044
000045 // 初始化 OLE 庫
000046 if (!AfxOleInit())
000047 {
000048 AfxMessageBox(IDP_OLE_INIT_FAILED);
000049 return FALSE;
000050 }
000051 AfxEnableControlContainer();
000052 // 標準初始化
000053 // 如果未使用這些功能並希望減小
000054 // 最終可執行文件的大小,則應移除下列
000055 // 不需要的特定初始化例程
000056 // 更改用於存儲設置的註冊表項
000057 // TODO: 應適當修改該字符串,
000058 // 例如修改爲公司或組織名
000059 SetRegistryKey(_T("應用程序嚮導生成的本地應用程序"));
000060 // 若要創建主窗口,此代碼將創建新的框架窗口
000061 // 對象,然後將其設置爲應用程序的主窗口對象
000062 CMainFrame* pFrame = new CMainFrame;
000063 if (!pFrame)
000064 return FALSE;
000065 m_pMainWnd = pFrame;
000066 // 創建並加載帶有其資源的框架
000067 pFrame->LoadFrame(IDR_MAINFRAME,
000068 WS_OVERLAPPEDWINDOW | FWS_ADDTOTITLE, NULL,
000069 NULL);
000070 // 唯一的一個窗口已初始化,因此顯示它並對其進行更新
000071 pFrame->ShowWindow(SW_SHOW);
000072 pFrame->UpdateWindow();
000073 // 僅當存在後綴時才調用 DragAcceptFiles,
000074 // 在 SDI 應用程序中,這應在 ProcessShellCommand 之後發生
000075 // D3D初始化
000076 return pFrame->InitD3D();
000077 }
000078
000079
000080 // CMFCD3DApp 消息處理程序
000081
000082
000083
000084 // 用於應用程序“關於”菜單項的 CAboutDlg 對話框
000085
000086 class CAboutDlg : public CDialog
000087 {
000088 public:
000089 CAboutDlg();
000090
000091 // 對話框數據
000092 enum { IDD = IDD_ABOUTBOX };
000093
000094 protected:
000095 virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
000096
000097 // 實現
000098 protected:
000099 DECLARE_MESSAGE_MAP()
000100 };
000101
000102 CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
000103 {
000104 }
000105
000106 void CAboutDlg::DoDataExchange(CDataExchange* pDX)
000107 {
000108 CDialog::DoDataExchange(pDX);
000109 }
000110
000111 BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
000112 END_MESSAGE_MAP()
000113
000114 // 用於運行對話框的應用程序命令
000115 void CMFCD3DApp::OnAppAbout()
000116 {
000117 CAboutDlg aboutDlg;
000118 aboutDlg.DoModal();
000119 }
000120
000121
000122 // CMFCD3DApp 消息處理程序
000123
000124
000125 int CMFCD3DApp::Run()
000126 {
000127 MSG msg;
000128 ::ZeroMemory(&msg, sizeof(MSG));
000129
000130 static float lastTime = (float)timeGetTime();
000131
000132 while(msg.message != WM_QUIT)
000133 {
000134 if(::PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
000135 {
000136 ::TranslateMessage(&msg);
000137 ::DispatchMessage(&msg);
000138 }
000139 else
000140 {
000141 float currTime = (float)timeGetTime();
000142 float timeDelta = (currTime - lastTime)*0.001f;
000143 lastTime = currTime;
000144
000145 ((CMainFrame*)m_pMainWnd)->Render(timeDelta);
000146 }
000147 }
000148 return CWinApp::Run();
000149 }
000001 // MainFrm.cpp : CMainFrame 類的實現
000002 //
000003
000004 #include "stdafx.h"
000005 #include "MFCD3D.h"
000006
000007 #include "MainFrm.h"
000008
000009 #ifdef _DEBUG
000010 #define new DEBUG_NEW
000011 #endif
000012
000013 const DWORD Vertex::FVF = D3DFVF_XYZ | D3DFVF_TEX1;
000014
000015 // CMainFrame
000016
000017 IMPLEMENT_DYNAMIC(CMainFrame, CFrameWnd)
000018
000019 BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
000020 ON_WM_CREATE()
000021 ON_WM_SETFOCUS()
000022 ON_WM_DESTROY()
000023 END_MESSAGE_MAP()
000024
000025
000026 // CMainFrame 構造/析構
000027
000028 CMainFrame::CMainFrame()
000029 : m_d3dDevice(NULL)
000030 , m_pVB(NULL)
000031 , m_pIB(NULL)
000032 , m_pTex(NULL)
000033 {
000034 // TODO: 在此添加成員初始化代碼
000035 }
000036
000037 CMainFrame::~CMainFrame()
000038 {
000039 }
000040
000041
000042 int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
000043 {
000044 if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
000045 return -1;
000046 // 創建一個視圖以佔用框架的工作區
000047 if (!m_wndView.Create(NULL, NULL, AFX_WS_DEFAULT_VIEW,
000048 CRect(0, 0, 0, 0), this, AFX_IDW_PANE_FIRST, NULL))
000049 {
000050 TRACE0("未能創建視圖窗口/n");
000051 return -1;
000052 }
000053
000054 if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP
000055 | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||
000056 !m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
000057 {
000058 TRACE0("未能創建工具欄/n");
000059 return -1; // 未能創建
000060 }
000061 // TODO: 如果不需要工具欄可停靠,則刪除這三行
000062 m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
000063 EnableDocking(CBRS_ALIGN_ANY);
000064 DockControlBar(&m_wndToolBar);
000065
000066 return 0;
000067 }
000068
000069 BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
000070 {
000071 if( !CFrameWnd::PreCreateWindow(cs) )
000072 return FALSE;
000073 // TODO: 在此處通過修改 CREATESTRUCT cs 來修改窗口類或
000074 // 樣式
000075
000076 cs.style = WS_OVERLAPPED | WS_CAPTION | FWS_ADDTOTITLE
000077 | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
000078
000079 cs.dwExStyle &= ~WS_EX_CLIENTEDGE;
000080 cs.lpszClass = AfxRegisterWndClass(0);
000081 return TRUE;
000082 }
000083
000084
000085 // CMainFrame 診斷
000086
000087 #ifdef _DEBUG
000088 void CMainFrame::AssertValid() const
000089 {
000090 CFrameWnd::AssertValid();
000091 }
000092
000093 void CMainFrame::Dump(CDumpContext& dc) const
000094 {
000095 CFrameWnd::Dump(dc);
000096 }
000097
000098 #endif //_DEBUG
000099
000100
000101 // CMainFrame 消息處理程序
000102
000103 void CMainFrame::OnSetFocus(CWnd* /*pOldWnd*/)
000104 {
000105 // 將焦點前移到視圖窗口
000106 m_wndView.SetFocus();
000107 }
000108
000109 BOOL CMainFrame::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo)
000110 {
000111 // 讓視圖第一次嘗試該命令
000112 if (m_wndView.OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
000113 return TRUE;
000114
000115 // 否則,執行默認處理
000116 return CFrameWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
000117 }
000118
000119 // 初始化D3D
000120 BOOL CMainFrame::InitD3D(void)
000121 {
000122 ASSERT(IsWindow(m_wndView.m_hWnd));
000123 // 初始化Direct3D9
000124 // Step1.獲得IDirect3D9接口
000125 IDirect3D9* _d3d9;
000126 _d3d9 = Direct3DCreate9(D3D_SDK_VERSION);
000127 if(!_d3d9)
000128 {
000129 ::AfxMessageBox(_T("Get Interface of Direct3D Failed!") , MB_ICONSTOP);
000130 return FALSE;
000131 }
000132 // Step2.檢查顯卡能力
000133 D3DCAPS9 caps;
000134 _d3d9->GetDeviceCaps(D3DADAPTER_DEFAULT ,
000135 D3DDEVTYPE_HAL ,
000136 &caps);
000137 int vp = 0;
000138 if(caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT)
000139 vp = D3DCREATE_HARDWARE_VERTEXPROCESSING;
000140 else
000141 vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
000142 // Step3.填充D3DPRESENT_PARAMETERS
000143 D3DPRESENT_PARAMETERS d3dpp;
000144 CRect rect;
000145 GetClientRect(&rect);
000146 ZeroMemory(&d3dpp,sizeof(D3DPRESENT_PARAMETERS));
000147 d3dpp.BackBufferWidth = rect.Width();
000148 d3dpp.BackBufferHeight = rect.Height();
000149 d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8;
000150 d3dpp.BackBufferCount = 1;
000151 d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
000152 d3dpp.MultiSampleQuality = 0;
000153 d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
000154 d3dpp.hDeviceWindow = m_wndView.m_hWnd;
000155 d3dpp.Windowed = true; // 一定要爲true
000156 d3dpp.EnableAutoDepthStencil = true;
000157 d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;
000158 d3dpp.Flags = 0;
000159 d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
000160 d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
000161
000162 // Step4.創建Direct3D設備
000163 HRESULT hr;
000164 hr = _d3d9->CreateDevice(D3DADAPTER_DEFAULT ,
000165 D3DDEVTYPE_HAL ,
000166 m_wndView.m_hWnd ,
000167 vp ,
000168 &d3dpp ,
000169 &m_d3dDevice);
000170 if(FAILED(hr))
000171 {
000172 switch(hr)
000173 {
000174 case D3DERR_DEVICELOST:
000175 AfxMessageBox(_T("Create D3D Device Failed!<Error:D3DERR_DEVICELOST>") , MB_ICONSTOP);
000176 break;
000177 case D3DERR_INVALIDCALL:
000178 AfxMessageBox(_T("Create D3D Device Failed!<Error:D3DERR_INVALIDCALL>") , MB_ICONSTOP);
000179 break;
000180 case D3DERR_NOTAVAILABLE:
000181 AfxMessageBox(_T("Create D3D Device Failed!<Error:D3DERR_NOTAVAILABLE>") , MB_ICONSTOP);
000182 break;
000183 case D3DERR_OUTOFVIDEOMEMORY:
000184 AfxMessageBox(_T("Create D3D Device Failed!<Error:D3DERR_OUTOFVIDEOMEMORY>") , MB_ICONSTOP);
000185 break;
000186 }
000187 _d3d9->Release();
000188 return FALSE;
000189 }
000190 _d3d9->Release();
000191 // Direct3D9初始化完成
000192 // 裝載資源
000193 Setup();
000194 return TRUE;
000195 }
000196
000197 // 裝載資源
000198 BOOL CMainFrame::Setup(void)
000199 {
000200 // 創建頂點緩衝區和索引緩衝
000201 m_d3dDevice->CreateVertexBuffer(36 * sizeof(Vertex) ,
000202 D3DUSAGE_WRITEONLY ,
000203 Vertex::FVF ,
000204 D3DPOOL_MANAGED ,
000205 &m_pVB ,
000206 0);
000207 // 填充頂點緩衝區
000208 Vertex* pVertices;
000209 m_pVB->Lock(0 , 0 , (void**)&pVertices , 0);
000210
000211 // 前面
000212 pVertices[0] = Vertex(-1.0f , 1.0f , -1.0f , 0.0f , 0.0f);
000213 pVertices[1] = Vertex(1.0f , 1.0f , -1.0f , 1.0f , 0.0f);
000214 pVertices[2] = Vertex(1.0f , -1.0f , -1.0f , 1.0f , 1.0f);
000215 pVertices[3] = Vertex(-1.0f , 1.0f , -1.0f , 0.0f , 0.0f);
000216 pVertices[4] = Vertex(1.0f , -1.0f , -1.0f , 1.0f , 1.0f);
000217 pVertices[5] = Vertex(-1.0f , -1.0f , -1.0f , 0.0f , 1.0f);
000218 // 後面
000219 pVertices[6] = Vertex(-1.0f , 1.0f , 1.0f , 0.0f , 0.0f);
000220 pVertices[7] = Vertex(1.0f , 1.0f , 1.0f , 1.0f , 0.0f);
000221 pVertices[8] = Vertex(1.0f , -1.0f , 1.0f , 1.0f , 1.0f);
000222 pVertices[9] = Vertex(-1.0f , 1.0f , 1.0f , 0.0f , 0.0f);
000223 pVertices[10] = Vertex(1.0f , -1.0f , 1.0f , 1.0f , 1.0f);
000224 pVertices[11] = Vertex(-1.0f , -1.0f , 1.0f , 0.0f , 1.0f);
000225 // 上面
000226 pVertices[12] = Vertex(-1.0f , 1.0f , 1.0f , 0.0f , 0.0f);
000227 pVertices[13] = Vertex(1.0f , 1.0f , 1.0f , 1.0f , 0.0f);
000228 pVertices[14] = Vertex(-1.0f , 1.0f , -1.0f , 0.0f , 1.0f);
000229 pVertices[15] = Vertex(1.0f , 1.0f , 1.0f , 1.0f , 0.0f);
000230 pVertices[16] = Vertex(1.0f , 1.0f , -1.0f , 1.0f , 1.0f);
000231 pVertices[17] = Vertex(-1.0f , 1.0f , -1.0f , 0.0f , 1.0f);
000232 // 下面
000233 pVertices[18] = Vertex(-1.0f , -1.0f , 1.0f , 0.0f , 0.0f);
000234 pVertices[19] = Vertex(1.0f , -1.0f , 1.0f , 1.0f , 0.0f);
000235 pVertices[20] = Vertex(-1.0f , -1.0f , -1.0f , 0.0f , 1.0f);
000236 pVertices[21] = Vertex(1.0f , -1.0f , 1.0f , 1.0f , 0.0f);
000237 pVertices[22] = Vertex(1.0f , -1.0f , -1.0f , 1.0f , 1.0f);
000238 pVertices[23] = Vertex(-1.0f , -1.0f , -1.0f , 0.0f , 1.0f);
000239 // 左面
000240 pVertices[24] = Vertex(-1.0f , 1.0f , 1.0f , 0.0f , 0.0f);
000241 pVertices[25] = Vertex(-1.0f , 1.0f , -1.0f , 1.0f , 0.0f);
000242 pVertices[26] = Vertex(-1.0f , -1.0f , -1.0f , 1.0f , 1.0f);
000243 pVertices[27] = Vertex(-1.0f , 1.0f , 1.0f , 0.0f , 0.0f);
000244 pVertices[28] = Vertex(-1.0f , -1.0f , -1.0f , 1.0f , 1.0f);
000245 pVertices[29] = Vertex(-1.0f , -1.0f , 1.0f , 0.0f , 1.0f);
000246 // 右面
000247 pVertices[30] = Vertex(1.0f , 1.0f , 1.0f , 0.0f , 0.0f);
000248 pVertices[31] = Vertex(1.0f , 1.0f , -1.0f , 1.0f , 0.0f);
000249 pVertices[32] = Vertex(1.0f , -1.0f , -1.0f , 1.0f , 1.0f);
000250 pVertices[33] = Vertex(1.0f , 1.0f , 1.0f , 0.0f , 0.0f);
000251 pVertices[34] = Vertex(1.0f , -1.0f , -1.0f , 1.0f , 1.0f);
000252 pVertices[35] = Vertex(1.0f , -1.0f , 1.0f , 0.0f , 1.0f);
000253
000254
000255 m_pVB->Unlock();
000256
000257 // 創建紋理
000258 D3DXCreateTextureFromFile(m_d3dDevice , _T("bbq.jpg") , &m_pTex);
000259 m_d3dDevice->SetTexture(0 , m_pTex);
000260
000261 m_d3dDevice->SetSamplerState(0 , D3DSAMP_MAGFILTER , D3DTEXF_LINEAR);
000262 m_d3dDevice->SetSamplerState(0 , D3DSAMP_MINFILTER , D3DTEXF_LINEAR);
000263 m_d3dDevice->SetSamplerState(0 , D3DSAMP_MIPFILTER , D3DTEXF_POINT);
000264 // 攝像機位置
000265 D3DXVECTOR3 pos(0.0f , 0.0f , -5.0f);
000266 D3DXVECTOR3 tag(0.0f , 0.0f , 0.0f);
000267 D3DXVECTOR3 up(0.0f , 1.0f , 0.0f);
000268 D3DXMATRIX v;
000269 D3DXMatrixLookAtLH(&v , &pos , &tag , &up);
000270 m_d3dDevice->SetTransform(D3DTS_VIEW , &v);
000271
000272 // 設置投影矩陣
000273 D3DXMATRIX proj;
000274 CRect rect;
000275 GetClientRect(&rect);
000276 D3DXMatrixPerspectiveFovLH(&proj , D3DX_PI * 0.5f ,
000277 (float)rect.Width()/(float)rect.Height() ,
000278 1.0f ,
000279 1000.0f);
000280 m_d3dDevice->SetTransform(D3DTS_PROJECTION , &proj);
000281
000282 // 設置渲染狀態
000283 m_d3dDevice->SetRenderState(D3DRS_LIGHTING , false);
000284 m_d3dDevice->SetRenderState(D3DRS_CULLMODE , D3DCULL_NONE);
000285
000286 return TRUE;
000287 }
000288
000289 // 渲染
000290 void CMainFrame::Render(float timeDelta)
000291 {
000292 if(m_d3dDevice) // Only use Device methods if we have a valid device.
000293 {
000294 // 旋轉正方體
000295 D3DXMATRIX Rx , Ry;
000296 // 在x方向旋轉45度
000297 D3DXMatrixRotationX(&Rx , 3.14f / 4.0f);
000298 // 每一幀增加y
000299 static float y = 0.0f;
000300 D3DXMatrixRotationY(&Ry , y);
000301 y += timeDelta;
000302 // 當繞y軸旋轉的角度達到360度時,置y爲0
000303 if(y >= 6.28f) y = 0.0f;
000304 // 組合兩個方向上的旋轉
000305 D3DXMATRIX p = Rx * Ry;
000306 m_d3dDevice->SetTransform(D3DTS_WORLD , &p);
000307
000308 // 繪製場景
000309 m_d3dDevice->Clear(0 , 0 , D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER , 0x000000ff , 1.0f , 0);
000310 // 開始
000311 m_d3dDevice->BeginScene();
000312 {
000313 m_d3dDevice->SetStreamSource(0 , m_pVB , 0 , sizeof(Vertex));
000314 m_d3dDevice->SetFVF(Vertex::FVF);
000315 m_d3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST , 0 , 12);
000316 }
000317 m_d3dDevice->EndScene();
000318 // 結束
000319 m_d3dDevice->Present(0 , 0 , 0 , 0);
000320 }
000321 }
000322
000323 // 清除資源
000324 void CMainFrame::CleanUp(void)
000325 {
000326 m_pVB->Release();
000327 m_pTex->Release();
000328 }
000329
000330 void CMainFrame::OnDestroy()
000331 {
000332 CFrameWnd::OnDestroy();
000333
000334 CleanUp();
000335
000336 m_d3dDevice->Release();
000337 }
000002 //
000003
000004 #include "stdafx.h"
000005 #include "MFCD3D.h"
000006
000007 #include "MainFrm.h"
000008
000009 #ifdef _DEBUG
000010 #define new DEBUG_NEW
000011 #endif
000012
000013 const DWORD Vertex::FVF = D3DFVF_XYZ | D3DFVF_TEX1;
000014
000015 // CMainFrame
000016
000017 IMPLEMENT_DYNAMIC(CMainFrame, CFrameWnd)
000018
000019 BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
000020 ON_WM_CREATE()
000021 ON_WM_SETFOCUS()
000022 ON_WM_DESTROY()
000023 END_MESSAGE_MAP()
000024
000025
000026 // CMainFrame 構造/析構
000027
000028 CMainFrame::CMainFrame()
000029 : m_d3dDevice(NULL)
000030 , m_pVB(NULL)
000031 , m_pIB(NULL)
000032 , m_pTex(NULL)
000033 {
000034 // TODO: 在此添加成員初始化代碼
000035 }
000036
000037 CMainFrame::~CMainFrame()
000038 {
000039 }
000040
000041
000042 int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
000043 {
000044 if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
000045 return -1;
000046 // 創建一個視圖以佔用框架的工作區
000047 if (!m_wndView.Create(NULL, NULL, AFX_WS_DEFAULT_VIEW,
000048 CRect(0, 0, 0, 0), this, AFX_IDW_PANE_FIRST, NULL))
000049 {
000050 TRACE0("未能創建視圖窗口/n");
000051 return -1;
000052 }
000053
000054 if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP
000055 | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||
000056 !m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
000057 {
000058 TRACE0("未能創建工具欄/n");
000059 return -1; // 未能創建
000060 }
000061 // TODO: 如果不需要工具欄可停靠,則刪除這三行
000062 m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
000063 EnableDocking(CBRS_ALIGN_ANY);
000064 DockControlBar(&m_wndToolBar);
000065
000066 return 0;
000067 }
000068
000069 BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
000070 {
000071 if( !CFrameWnd::PreCreateWindow(cs) )
000072 return FALSE;
000073 // TODO: 在此處通過修改 CREATESTRUCT cs 來修改窗口類或
000074 // 樣式
000075
000076 cs.style = WS_OVERLAPPED | WS_CAPTION | FWS_ADDTOTITLE
000077 | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
000078
000079 cs.dwExStyle &= ~WS_EX_CLIENTEDGE;
000080 cs.lpszClass = AfxRegisterWndClass(0);
000081 return TRUE;
000082 }
000083
000084
000085 // CMainFrame 診斷
000086
000087 #ifdef _DEBUG
000088 void CMainFrame::AssertValid() const
000089 {
000090 CFrameWnd::AssertValid();
000091 }
000092
000093 void CMainFrame::Dump(CDumpContext& dc) const
000094 {
000095 CFrameWnd::Dump(dc);
000096 }
000097
000098 #endif //_DEBUG
000099
000100
000101 // CMainFrame 消息處理程序
000102
000103 void CMainFrame::OnSetFocus(CWnd* /*pOldWnd*/)
000104 {
000105 // 將焦點前移到視圖窗口
000106 m_wndView.SetFocus();
000107 }
000108
000109 BOOL CMainFrame::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo)
000110 {
000111 // 讓視圖第一次嘗試該命令
000112 if (m_wndView.OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
000113 return TRUE;
000114
000115 // 否則,執行默認處理
000116 return CFrameWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
000117 }
000118
000119 // 初始化D3D
000120 BOOL CMainFrame::InitD3D(void)
000121 {
000122 ASSERT(IsWindow(m_wndView.m_hWnd));
000123 // 初始化Direct3D9
000124 // Step1.獲得IDirect3D9接口
000125 IDirect3D9* _d3d9;
000126 _d3d9 = Direct3DCreate9(D3D_SDK_VERSION);
000127 if(!_d3d9)
000128 {
000129 ::AfxMessageBox(_T("Get Interface of Direct3D Failed!") , MB_ICONSTOP);
000130 return FALSE;
000131 }
000132 // Step2.檢查顯卡能力
000133 D3DCAPS9 caps;
000134 _d3d9->GetDeviceCaps(D3DADAPTER_DEFAULT ,
000135 D3DDEVTYPE_HAL ,
000136 &caps);
000137 int vp = 0;
000138 if(caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT)
000139 vp = D3DCREATE_HARDWARE_VERTEXPROCESSING;
000140 else
000141 vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
000142 // Step3.填充D3DPRESENT_PARAMETERS
000143 D3DPRESENT_PARAMETERS d3dpp;
000144 CRect rect;
000145 GetClientRect(&rect);
000146 ZeroMemory(&d3dpp,sizeof(D3DPRESENT_PARAMETERS));
000147 d3dpp.BackBufferWidth = rect.Width();
000148 d3dpp.BackBufferHeight = rect.Height();
000149 d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8;
000150 d3dpp.BackBufferCount = 1;
000151 d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
000152 d3dpp.MultiSampleQuality = 0;
000153 d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
000154 d3dpp.hDeviceWindow = m_wndView.m_hWnd;
000155 d3dpp.Windowed = true; // 一定要爲true
000156 d3dpp.EnableAutoDepthStencil = true;
000157 d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;
000158 d3dpp.Flags = 0;
000159 d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
000160 d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
000161
000162 // Step4.創建Direct3D設備
000163 HRESULT hr;
000164 hr = _d3d9->CreateDevice(D3DADAPTER_DEFAULT ,
000165 D3DDEVTYPE_HAL ,
000166 m_wndView.m_hWnd ,
000167 vp ,
000168 &d3dpp ,
000169 &m_d3dDevice);
000170 if(FAILED(hr))
000171 {
000172 switch(hr)
000173 {
000174 case D3DERR_DEVICELOST:
000175 AfxMessageBox(_T("Create D3D Device Failed!<Error:D3DERR_DEVICELOST>") , MB_ICONSTOP);
000176 break;
000177 case D3DERR_INVALIDCALL:
000178 AfxMessageBox(_T("Create D3D Device Failed!<Error:D3DERR_INVALIDCALL>") , MB_ICONSTOP);
000179 break;
000180 case D3DERR_NOTAVAILABLE:
000181 AfxMessageBox(_T("Create D3D Device Failed!<Error:D3DERR_NOTAVAILABLE>") , MB_ICONSTOP);
000182 break;
000183 case D3DERR_OUTOFVIDEOMEMORY:
000184 AfxMessageBox(_T("Create D3D Device Failed!<Error:D3DERR_OUTOFVIDEOMEMORY>") , MB_ICONSTOP);
000185 break;
000186 }
000187 _d3d9->Release();
000188 return FALSE;
000189 }
000190 _d3d9->Release();
000191 // Direct3D9初始化完成
000192 // 裝載資源
000193 Setup();
000194 return TRUE;
000195 }
000196
000197 // 裝載資源
000198 BOOL CMainFrame::Setup(void)
000199 {
000200 // 創建頂點緩衝區和索引緩衝
000201 m_d3dDevice->CreateVertexBuffer(36 * sizeof(Vertex) ,
000202 D3DUSAGE_WRITEONLY ,
000203 Vertex::FVF ,
000204 D3DPOOL_MANAGED ,
000205 &m_pVB ,
000206 0);
000207 // 填充頂點緩衝區
000208 Vertex* pVertices;
000209 m_pVB->Lock(0 , 0 , (void**)&pVertices , 0);
000210
000211 // 前面
000212 pVertices[0] = Vertex(-1.0f , 1.0f , -1.0f , 0.0f , 0.0f);
000213 pVertices[1] = Vertex(1.0f , 1.0f , -1.0f , 1.0f , 0.0f);
000214 pVertices[2] = Vertex(1.0f , -1.0f , -1.0f , 1.0f , 1.0f);
000215 pVertices[3] = Vertex(-1.0f , 1.0f , -1.0f , 0.0f , 0.0f);
000216 pVertices[4] = Vertex(1.0f , -1.0f , -1.0f , 1.0f , 1.0f);
000217 pVertices[5] = Vertex(-1.0f , -1.0f , -1.0f , 0.0f , 1.0f);
000218 // 後面
000219 pVertices[6] = Vertex(-1.0f , 1.0f , 1.0f , 0.0f , 0.0f);
000220 pVertices[7] = Vertex(1.0f , 1.0f , 1.0f , 1.0f , 0.0f);
000221 pVertices[8] = Vertex(1.0f , -1.0f , 1.0f , 1.0f , 1.0f);
000222 pVertices[9] = Vertex(-1.0f , 1.0f , 1.0f , 0.0f , 0.0f);
000223 pVertices[10] = Vertex(1.0f , -1.0f , 1.0f , 1.0f , 1.0f);
000224 pVertices[11] = Vertex(-1.0f , -1.0f , 1.0f , 0.0f , 1.0f);
000225 // 上面
000226 pVertices[12] = Vertex(-1.0f , 1.0f , 1.0f , 0.0f , 0.0f);
000227 pVertices[13] = Vertex(1.0f , 1.0f , 1.0f , 1.0f , 0.0f);
000228 pVertices[14] = Vertex(-1.0f , 1.0f , -1.0f , 0.0f , 1.0f);
000229 pVertices[15] = Vertex(1.0f , 1.0f , 1.0f , 1.0f , 0.0f);
000230 pVertices[16] = Vertex(1.0f , 1.0f , -1.0f , 1.0f , 1.0f);
000231 pVertices[17] = Vertex(-1.0f , 1.0f , -1.0f , 0.0f , 1.0f);
000232 // 下面
000233 pVertices[18] = Vertex(-1.0f , -1.0f , 1.0f , 0.0f , 0.0f);
000234 pVertices[19] = Vertex(1.0f , -1.0f , 1.0f , 1.0f , 0.0f);
000235 pVertices[20] = Vertex(-1.0f , -1.0f , -1.0f , 0.0f , 1.0f);
000236 pVertices[21] = Vertex(1.0f , -1.0f , 1.0f , 1.0f , 0.0f);
000237 pVertices[22] = Vertex(1.0f , -1.0f , -1.0f , 1.0f , 1.0f);
000238 pVertices[23] = Vertex(-1.0f , -1.0f , -1.0f , 0.0f , 1.0f);
000239 // 左面
000240 pVertices[24] = Vertex(-1.0f , 1.0f , 1.0f , 0.0f , 0.0f);
000241 pVertices[25] = Vertex(-1.0f , 1.0f , -1.0f , 1.0f , 0.0f);
000242 pVertices[26] = Vertex(-1.0f , -1.0f , -1.0f , 1.0f , 1.0f);
000243 pVertices[27] = Vertex(-1.0f , 1.0f , 1.0f , 0.0f , 0.0f);
000244 pVertices[28] = Vertex(-1.0f , -1.0f , -1.0f , 1.0f , 1.0f);
000245 pVertices[29] = Vertex(-1.0f , -1.0f , 1.0f , 0.0f , 1.0f);
000246 // 右面
000247 pVertices[30] = Vertex(1.0f , 1.0f , 1.0f , 0.0f , 0.0f);
000248 pVertices[31] = Vertex(1.0f , 1.0f , -1.0f , 1.0f , 0.0f);
000249 pVertices[32] = Vertex(1.0f , -1.0f , -1.0f , 1.0f , 1.0f);
000250 pVertices[33] = Vertex(1.0f , 1.0f , 1.0f , 0.0f , 0.0f);
000251 pVertices[34] = Vertex(1.0f , -1.0f , -1.0f , 1.0f , 1.0f);
000252 pVertices[35] = Vertex(1.0f , -1.0f , 1.0f , 0.0f , 1.0f);
000253
000254
000255 m_pVB->Unlock();
000256
000257 // 創建紋理
000258 D3DXCreateTextureFromFile(m_d3dDevice , _T("bbq.jpg") , &m_pTex);
000259 m_d3dDevice->SetTexture(0 , m_pTex);
000260
000261 m_d3dDevice->SetSamplerState(0 , D3DSAMP_MAGFILTER , D3DTEXF_LINEAR);
000262 m_d3dDevice->SetSamplerState(0 , D3DSAMP_MINFILTER , D3DTEXF_LINEAR);
000263 m_d3dDevice->SetSamplerState(0 , D3DSAMP_MIPFILTER , D3DTEXF_POINT);
000264 // 攝像機位置
000265 D3DXVECTOR3 pos(0.0f , 0.0f , -5.0f);
000266 D3DXVECTOR3 tag(0.0f , 0.0f , 0.0f);
000267 D3DXVECTOR3 up(0.0f , 1.0f , 0.0f);
000268 D3DXMATRIX v;
000269 D3DXMatrixLookAtLH(&v , &pos , &tag , &up);
000270 m_d3dDevice->SetTransform(D3DTS_VIEW , &v);
000271
000272 // 設置投影矩陣
000273 D3DXMATRIX proj;
000274 CRect rect;
000275 GetClientRect(&rect);
000276 D3DXMatrixPerspectiveFovLH(&proj , D3DX_PI * 0.5f ,
000277 (float)rect.Width()/(float)rect.Height() ,
000278 1.0f ,
000279 1000.0f);
000280 m_d3dDevice->SetTransform(D3DTS_PROJECTION , &proj);
000281
000282 // 設置渲染狀態
000283 m_d3dDevice->SetRenderState(D3DRS_LIGHTING , false);
000284 m_d3dDevice->SetRenderState(D3DRS_CULLMODE , D3DCULL_NONE);
000285
000286 return TRUE;
000287 }
000288
000289 // 渲染
000290 void CMainFrame::Render(float timeDelta)
000291 {
000292 if(m_d3dDevice) // Only use Device methods if we have a valid device.
000293 {
000294 // 旋轉正方體
000295 D3DXMATRIX Rx , Ry;
000296 // 在x方向旋轉45度
000297 D3DXMatrixRotationX(&Rx , 3.14f / 4.0f);
000298 // 每一幀增加y
000299 static float y = 0.0f;
000300 D3DXMatrixRotationY(&Ry , y);
000301 y += timeDelta;
000302 // 當繞y軸旋轉的角度達到360度時,置y爲0
000303 if(y >= 6.28f) y = 0.0f;
000304 // 組合兩個方向上的旋轉
000305 D3DXMATRIX p = Rx * Ry;
000306 m_d3dDevice->SetTransform(D3DTS_WORLD , &p);
000307
000308 // 繪製場景
000309 m_d3dDevice->Clear(0 , 0 , D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER , 0x000000ff , 1.0f , 0);
000310 // 開始
000311 m_d3dDevice->BeginScene();
000312 {
000313 m_d3dDevice->SetStreamSource(0 , m_pVB , 0 , sizeof(Vertex));
000314 m_d3dDevice->SetFVF(Vertex::FVF);
000315 m_d3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST , 0 , 12);
000316 }
000317 m_d3dDevice->EndScene();
000318 // 結束
000319 m_d3dDevice->Present(0 , 0 , 0 , 0);
000320 }
000321 }
000322
000323 // 清除資源
000324 void CMainFrame::CleanUp(void)
000325 {
000326 m_pVB->Release();
000327 m_pTex->Release();
000328 }
000329
000330 void CMainFrame::OnDestroy()
000331 {
000332 CFrameWnd::OnDestroy();
000333
000334 CleanUp();
000335
000336 m_d3dDevice->Release();
000337 }
效果圖:
[Groov0V]
__________________________
[1] 這裏以Direct3D 9.0爲例。
[2]該參數表示是否全屏(僅在Win32 SDK框架中有效)。
[2]該參數表示是否全屏(僅在Win32 SDK框架中有效)。