/* Win32 Direct3D9 SDK框架 1、注册窗体类; 2、创建窗口; 3、创建消息处理函数; 4、显示窗口; 5、初始化D3D、初始化资源数据(如:顶点向量、纹理等); 6、进入消息循环,用PeekMessage处理消息,以便在空闲时进行渲染。 而初始化D3D又分下面四个步骤: 1、创建IDirect3D9[1]对象; 2、检查硬件性能,判断硬件是否支持特定的功能; 3、填充D3DPRESENT_PARAMETERS结构; 4、利用第3步中的结构体对象创建D3D设备(由于该步骤需要窗体的句柄,所以初始化D3D必须放在显示窗口之后)。 */ //====================================================== //Direct3D程序框架 //====================================================== #include <d3d9.h> //------------------------------------------------------ //全局变量 //------------------------------------------------------ IDirect3DDevice9* Device = 0; //------------------------------------------------------ //函数声明 //------------------------------------------------------ bool InitD3D( HINSTANCE hInstance, int width, int height,bool windowed, D3DDEVTYPE deviceType,IDirect3DDevice9** device); int MsgLoop(); bool Setup(); void Cleanup(); bool Display(); LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); //------------------------------------------------------ //Desc:程序入口 //------------------------------------------------------ int WINAPI WinMain(HINSTANCE hinstance, // 应用程序当前实例句柄 HINSTANCE prevInstance, // 应用程序的先实例的句柄。对于同一个程序打开两次,出现两个窗口第一次打开的窗口就是先前实例的窗口。对于一个32的位程序,该参数总为NULL PSTR cmdLine, // 指向应用程序命令行的空字符串的指针,不包括函数名,获得整个命令行 int showCmd) /* 指明窗口如何显示。该参数可以是下列值之一: SW_HIDE:隐藏窗口并且激活另外一个窗口。 SW_MINIMIZE:最小化指定的窗口,并且激活在系统表中的顶层窗口。 SW_RESTORE:激活并显示窗口。如果窗口已经最小化或最大化,系统将以恢复到原来的尺寸和位置显示窗口(与SW_SHOWNORMAL相同)。 SW_SHOW:激活一个窗口并以原来的尺寸和位置显示窗口。 SW_SHOWMAXIMIZED:激活窗口并且将其最大化。 SW_SHOWMINIMIZED:激活窗口并将其目标化。 SW_SHOWMINNOACTIVE:将一个窗口显示为图标。激活窗口维持活动状态。 SW_SHOWNA:以窗口的当前状态显示窗口。激活窗口保持活动状态。 SW_SHOWNOACTIVATE:以窗口的最近一次的尺寸和位置显示窗口。激活窗口维持激活状态。 SW_SHOWNORMAL:激活并显示窗口。如果窗口最大化或最小化,系统将其恢复到原来的尺寸和位置(与SW_RESTORE相同)。 返回值:如果函数成功,当它接收到一个WM_QUIT消息时就中止,函数应该返回在该消息的wParam参数的退出值。如果函数在进入消息循环时退出,应该返回零。 */ { if(!InitD3D(hinstance, 800, 600, true, D3DDEVTYPE_HAL, &Device)) { MessageBox(0, L"InitD3D() - FAILED", 0, 0); return 0; } if(!Setup()) { MessageBox(0, L"Setup() - FAILED", 0, 0); return 0; } MsgLoop(); Cleanup(); Device->Release(); return 0; } //------------------------------------------------------ //Desc:创建窗口和初始化Direct3D //------------------------------------------------------ bool InitD3D( HINSTANCE hInstance, // 应用程序当前实例句柄 int width, int height, // 窗口大小 bool windowed, // 窗口还是全屏幕 D3DDEVTYPE deviceType, IDirect3DDevice9** device) { WNDCLASS wc;// 窗口对象 // 填充窗口对象 wc.style = CS_HREDRAW | CS_VREDRAW; // 描述类风格。该成员可以是“Class Styles”的任意组合。 wc.lpfnWndProc = (WNDPROC)WndProc; // 指向窗口过程的指针。必须使用CallWindowProc函数调用窗口过程。 wc.cbClsExtra = 0; // 表示窗口类结构之后分配的额外的字节数。系统将该值初始化为0。 wc.cbWndExtra = 0; // 表示窗口实例之后分配的额外的字节数。系统将该值初始化为0。如果使用资源文件里的CLASS指令创建对话框,并用WNDCLASS注册该对话框时,cbWndExtra必须设置成DLGWNDOWEXTRA。 wc.hInstance = hInstance; //包含该类实例的句柄,该实例包含了窗口过程。 wc.hIcon = LoadIcon(0, IDI_APPLICATION); // 类图标的句柄。该成员必须为一个图标资源的句柄。如果hIcon为NULL,系统将提供默认图标。 wc.hCursor = LoadCursor(0, IDC_ARROW); // 鼠标指针的句柄。改成员必须为一个指针资源的句柄。如果hCursor为NULL,应用程序必须在指针移入应用程序窗口时显式设置指针类型。 wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); /* 背景画刷的句柄。该成员或者是用于绘制背景的物理画刷的句柄,或者是一个颜色值。颜色值必须为如下标准系统颜色值(值1必须加到选定颜色中)。如果颜色值给定后,必须将该值转换成如下HBRUSH类型。 COLOR_ACTIVEBORDER COLOR_ACTIVECAPTION COLOR_APPWORKSPACE COLOR_BACKGROUND COLOR_BTNFACE COLOR_BTNSHADOW COLOR_BTNTEXT COLOR_CAPTIONTEXT COLOR_GRAYTEXT COLOR_HIGHLIGHT COLOR_HIGHLIGHTTEXT COLOR_INACTIVEBORDER COLOR_INACTIVECAPTION COLOR_MENU COLOR_MENUTEXT COLOR_SCROLLBAR COLOR_WINDOW COLOR_WINDOWFRAME COLOR_WINDOWTEXT 当调用UnregisterClass时,系统自动删除背景画刷。应用程序不应删除这些画刷。 当hbrBackground为NULL时,应用程序必须在绘制客户区域时绘制它自己的背景。为了确定背景是否一定要绘制,应用程序或者可以处理 WM_ERASEBKGND消息,或者测试PAINTSTRUCT的fErase成员。PAINTSTRUCT是由BeginPaint函数填充的。 */ wc.lpszMenuName = 0; //指向NULL结束的字符串,该字符串描述菜单的资源名,如同在资源文件里显示的名字一样。若使用一个整数标识菜单,可以使用MAKEINTRESOURCE宏。如果lpszMenuName为NULL,那么该窗口类的窗口将没有默认菜单。 wc.lpszClassName = L"Direct3D9App"; /* 指 向NULL结束的字符串,或者是一个原型(atom)。若该参数是一个原型,它必须是一个有先前调用RegisterClass或者 RegisterClassEx函数产生的类原型。类原型必须作为lpszClassName的低字,高字必须为0.若lpszClassName是一个 字符串,它描述了窗口类名。这个类名可以是由RegisterClass或者RegisterClassEx注册的名字,或者是任何预定义的控件类名。 结构信息 Header 在winuser.h声明,包含windows.h */ // 注册窗口类 if( !RegisterClass(&wc) ) { MessageBox(0, L"RegisterClass() - FAILED", 0, 0); return false; } HWND hwnd = 0; // 创建窗口 hwnd = CreateWindow(L"Direct3D9App", L"Direct3D9App", WS_EX_TOPMOST, /* 指定创建窗口的风格。该参数可以是下列窗口风格的组合再加上说明部分的控制风格。风格意义: WS_BORDER:创建一个单边框的窗口。 WS_CAPTION:创建一个有标题框的窗口(包括WS_BODER风格)。 WS_CHILD:创建一个子窗口。这个风格不能与WS_POPUP风格合用。 WS_CHLDWINDOW:与WS_CHILD相同。 WS_CLIPCHILDREN:当在父窗口内绘图时,排除子窗口区域。在创建父窗口时使用这个风格。 WS_CLlPBLINGS;排除子窗口之间的相对区域,也就是,当一个特定的窗口接收到WM_PAINT消息时,WS_CLIPSIBLINGS 风格将所有层叠窗口排除在绘图之外,只重绘指定的子窗口。如果未指定WS_CLIPSIBLINGS风格,并且子窗口是层叠的,则在重绘子窗口的客户区时,就会重绘邻近的子窗口。 WS_DISABLED:创建一个初始状态为禁止的子窗口。一个禁止状态的窗日不能接受来自用户的输入信息。 WS_DLGFRAME:创建一个带对话框边框风格的窗口。这种风格的窗口不能带标题条。 WS_GROUP:指定一组控制的第一个控制。这个控制组由第一个控制和随后定义的控制组成,自第二个控制开始每个控制,具有WS_GROUP风格,每个组的第一个控制带有WS_TABSTOP风格,从而使用户可以在组间移动。用户随后可以使用光标在组内的控制间改变键盘焦点。 WS_HSCROLL:创建一个有水平滚动条的窗口。 WS_ICONIC:创建一个初始状态为最小化状态的窗口。与WS_MINIMIZE风格相同。 WS_MAXIMIZE:创建一个具有最大化按钮的窗口。该风格不能与WS_EX_CONTEXTHELP风格同时出现,同时必须指定WS_SYSMENU风格。 WS_OVERLAPPED:产生一个层叠的窗口。一个层叠的窗口有一个标题条和一个边框。与WS_TILED风格相同。 WS_OVERLAPPEDWINDOW:创建一个具有WS_OVERLAPPED,WS_CAPTION,WS_SYSMENU WS_THICKFRAME,WS_MINIMIZEBOX,WS_MAXMIZEBOX风格的层叠窗口,与WS_TILEDWINDOW风格相同。 WS_POPUP;创建一个弹出式窗口。该风格不能与WS_CHLD风格同时使用。 WS_POPUWINDOW:创建一个具有WS_BORDER,WS_POPUP,WS_SYSMENU风格的窗口,WS_CAPTION和WS_POPUPWINDOW必须同时设定才能使窗口某单可见。 WS_SIZEBOX:创建一个可调边框的窗口,与WS_THICKFRAME风格相同。 WS_SYSMENU:创建一个在标题条上带有窗口菜单的窗口,必须同时设定WS_CAPTION风格。 WS_TABSTOP:创建一个控制,这个控制在用户按下Tab键时可以获得键盘焦点。按下Tab键后使键盘焦点转移到下一具有WS_TABSTOP风格的控制。 WS_THICKFRAME:创建一个具有可调边框的窗口,与WS_SIZEBOX风格相同。 WS_TILED:产生一个层叠的窗口。一个层叠的窗口有一个标题和一个边框。与WS_OVERLAPPED风格相同。 WS_TILEDWINDOW:创建一个具有WS_OVERLAPPED,WS_CAPTION,WS_SYSMENU MS_THICKFRAME. WS_MINIMIZEBOX,WS_MAXMIZEBOX风格的层叠窗口。与WS_OVERLAPPEDWINDOW风格相同。 WS_VISIBLE:创建一个初始状态为可见的窗口。WS_VSCROLL:创建一个有垂直滚动条的窗口。 */ 0, 0, // 指定窗口的初始水平位置。对一个层叠或弹出式窗口,X参数是屏幕坐标系的窗口的左上角的初始X坐标。对于子富口,x是子窗口左上角相对父窗口客户区左上角的初始X坐标。如果该参数被设为CW_UCEDEFAULT则系统为窗口选择缺省的左上角坐标并忽略Y参数。CW_USEDEFAULT只对层叠窗口有效,如果为弹出式窗口或子窗口设定,则X和y参数被设为零 width, height, // nWidth:以设备单元指明窗口的宽度。对于层叠窗口,nWidth或是屏幕坐标的窗口宽度或是CW_USEDEFAULT。若nWidth是CW_USEDEFAULT,则系统为窗口选择一个缺省的高度和宽度:缺省宽度为从初始X坐标开始到屏幕的右边界,缺省高度为从初始X坐标开始到目标区域的顶部。CW_USEDFEAULT只参层叠窗口有效;如果为弹出式窗口和子窗口设定CW_USEDEFAULT标志则nWidth和nHeight被设为零。nHelght:以设备单元指明窗口的高度。对于层叠窗口,nHeight是屏幕坐标的窗口宽度。若nWidth被设为CW_USEDEFAULT,则系统忽略nHeight参数。 0 /*parent hwnd*/, 0 /* menu */, hInstance, 0 /*extra*/); if( !hwnd ) { MessageBox(0, L"CreateWindow() - FAILED", 0, 0); return false; } // 显示窗口 ShowWindow(hwnd, SW_SHOW); /* hWnd:窗口句柄。 nCmdShow:指定窗口如何显示。如果发送应用程序的程序提供了STARTUPINFO结构,则应用程序第一次调用ShowWindow时该参数被忽略。否则,在第一次调用ShowWindow函数时,该值应为在函数WinMain中nCmdShow参数。在随后的调用中,该参数可以为下列值之一: SW_FORCEMINIMIZE:在WindowNT5.0中最小化窗口,即使拥有窗口的线程被挂起也会最小化。在从其他线程最小化窗口时才使用这个参数。 SW_MIOE:隐藏窗口并激活其他窗口。 SW_MAXIMIZE:最大化指定的窗口。 SW_MINIMIZE:最小化指定的窗口并且激活在Z序中的下一个顶层窗口。 SW_RESTORE:激活并显示窗口。如果窗口最小化或最大化,则系统将窗口恢复到原来的尺寸和位置。在恢复最小化窗口时,应用程序应该指定这个标志。 SW_SHOW:在窗口原来的位置以原来的尺寸激活和显示窗口。 SW_SHOWDEFAULT:依据在STARTUPINFO结构中指定的SW_FLAG标志设定显示状态,STARTUPINFO 结构是由启动应用程序的程序传递给CreateProcess函数的。 SW_SHOWMAXIMIZED:激活窗口并将其最大化。 SW_SHOWMINIMIZED:激活窗口并将其最小化。 SW_SHOWMINNOACTIVATE:窗口最小化,激活窗口仍然维持激活状态。 SW_SHOWNA:以窗口原来的状态显示窗口。激活窗口仍然维持激活状态。 SW_SHOWNOACTIVATE:以窗口最近一次的大小和状态显示窗口。激活窗口仍然维持激活状态。 SW_SHOWNOMAL:激活并显示一个窗口。如果窗口被最小化或最大化,系统将其恢复到原来的尺寸和大小。应用程序在第一次显示窗口的时候应该指定此标志。 */ UpdateWindow(hwnd); // // 初始化D3D // HRESULT hr = 0; // 步骤1:创建IDirect3D9对象。 IDirect3D9* d3d9 = 0; d3d9 = Direct3DCreate9(D3D_SDK_VERSION); // 创建Direct3D对象,该对象用来创建Direct3D设备对象 if( !d3d9 ) { MessageBox(0, L"Direct3DCreate9() - FAILED", 0, 0); return false; } // 步骤2:检查硬件性能(这里只检查了是否支持顶点的3D硬件加速处理) 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; // 步骤3:填充D3DPRESENT_PARAMETERS结构(参数说明请参考MSDN) 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; // 图像最大刷新速度 /* //下面这两个要一起使用 d3dpp.EnableAutoDepthStencil = TRUE; d3dpp.AutoDepthStencilFormat = D3DFMT_D16; */ // 步骤4:创建D3D设备 hr = d3d9->CreateDevice( D3DADAPTER_DEFAULT, // 主设备 deviceType, // 设备类型 hwnd, // 分配给设备的窗口句柄 vp, // 顶点处理方式 &d3dpp, // 表现参数 device); // 返回创建的设备 if( FAILED(hr) ) { // 如果创建失败,采用16为深度缓存试试 d3dpp.AutoDepthStencilFormat = D3DFMT_D16; hr = d3d9->CreateDevice( D3DADAPTER_DEFAULT, deviceType, hwnd, vp, &d3dpp, device); if( FAILED(hr) ) { d3d9->Release(); MessageBox(0, L"CreateDevice() - FAILED", 0, 0); return false; } } d3d9->Release(); return true; } //------------------------------------------------------ //Desc:消息循环 //------------------------------------------------------ int MsgLoop() { MSG msg; ZeroMemory(&msg, sizeof(MSG)); while(msg.message != WM_QUIT) { if(PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } else { Display(); // 渲染 } } return msg.wParam; } //------------------------------------------------------ //Desc:Direct3D框架函数 //------------------------------------------------------ bool Setup() { // 你可以在此初始化顶点向量、载入纹理等 return true; } void Cleanup() { // 清除在Setup中载入的资源 } bool Display() { if( Device ) // 只有当设备有效时才能渲染 { // 在此填入渲染代码 } return true; } //------------------------------------------------------ //Desc:窗口处理函数 //------------------------------------------------------ LRESULT CALLBACK 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); }