在MFC中使用DXUT(Direct3D)框架
源代码 (注:testMFCDXUT例子可能能在VS2008上编译通过,但testSDIDXUT_VS2008SP1是在VS2008SP1新建的工程)
本文使用的是Microsoft DirectX SDK (August 2009) ,VS2008SP1和XPSP3环境.
配置Microsoft DirectX SDK (August 2009)环境
安装完成后需要设置头文件路径和库文件路径.
工具-->选项-->项目和解决方案-->VC++目录
包含文件:
1.C:/Program Files/Microsoft DirectX SDK (August 2009)/Include
2.$(ProjectDir)DXUT/Core
3.$(ProjectDir)DXUT/Optional
库文件:
1.C:/Program Files/Microsoft DirectX SDK (August 2009)/Lib/x86
包含文件的2和3是项目目录下的DXUT源代码目录,这样包含头文件的时候不需要指定路径.
注:要是不怕麻烦的话可以不用设置2和3项包含文件,在附加包含目录中设置
项目-->属性-->配置属性-->C/C++-->常规-->附加包含目录
./DXUT/Core;./DXUT/Optional
为了在MFC中使用DXUT,创建了两个类CDXUTWindow和CDXUTD3D9Device
CDXUTWindow类是MFC的窗口派生类,下面是一些函数和参数的作用
// 是否移除父对话框的其他控件的WS_TABSTOP属性,需在控件创建前设置 BOOL m_bRemoveOtherTabStop; // 是否使当本窗口无鼠标焦点在本窗口有鼠标消息时自动设置焦点 BOOL m_bAutoResetFocus; // 是否继续传递WM_KEYDOWN消息,会有"当当当"按键声 BOOL m_bNoWmKeyDown; // 是否是定时器渲染D3D,渲染需要模拟DXUT可以放在WM_KICKIDLE或者OnIdle中 BOOL m_bTimerRender; // 封装的DXUT框架的渲染函数 static LRESULT CALLBACK OnKickIdle(WPARAM wParam = 0, LPARAM lParam = 0); // 在父对话框中设置本窗口的焦点 static void DXUTResetFocus(); // 重新设置定时器 BOOL ResetTimer(unsigned int nRenderTimerInterval, unsigned int OverTimeMultiple); // 移除父对话框的其他控件的WS_TABSTOP属性 BOOL RemoveOtherTabStop();
CDXUTD3D9Device是DXUT框架的中需要用户实现的D3D9接口类,CDXUTD3D9Device只用有个对外给CDXUTWindow::DXUTWindowInit()调用的CDXUTD3D9Device::DXUTWindowInit接口.其他都是DXUT框架的接口.
// hWnd是CDXUTWindow的窗口句柄 static void CALLBACK DXUTWindowInit(HWND hWnd);
使用步骤:
1.新建MFC工程,这里选择对话框程序
2.从C:/Program Files/Microsoft DirectX SDK (August 2009)/Samples/C++拷贝DXUT文件夹到刚新建的项目目录.
3.拷贝本文中的CDXUTWindow,CDXUTD3D9Device的支持文件和修改的部分DXUT框架文件(DXUT.cpp和DXUT.h)
4.添加CDXUTWindow,CDXUTD3D9Device和DXUT框架的核心文件(刚才拷贝的项目目录下DXUT/Core下的所有*.cpp和*.h)到项目中.
5.取消预编译头文件:项目-->属性-->配置属性-->C/C++-->预编译头文件-->创建/使用编译头文件-->不使用预编译头
6.子类化 CDXUTWindow:拖一个CStatic控件,该控件ID,绑定到CDXUTWindow类上.(也可以用CWnd::Create创建)
到此,程序已经能编译运行了,运行你就能看到DXUT那个熟悉的蓝色背景画面了.
下图是在单文档视图类程序中移植的DXUT框架的CustomUI示例.
如果不喜欢用定时器来调用DXUT渲染函数这种方式,仍然可以在MFC中仿DXUT的渲染消息泵,方法如下
1.1在文档视图类程序的CWinApp::OnIdle直接调用CDXUTWindow::OnKickIdle();
1.2 对话框程序中WM_KICKIDLE消息处理函数中return CDXUTWindow::OnKickIdle();
(注:这里的WM_KICKIDLE消息过程和响应自定义消息一样,就是消息不同而已)
关于WM_CHAR消息和WM_LBUTTONDOWN为什么不响应,可以设置CDXUTWindow::m_bNoWmKeyDown来决定是否传递,但是会有"当当当"的按键声.
有些消息需要从父窗口转发给DXUT控件类的话只能用PostMessage,不能用SendMessage.
CDXUTWindow源代码
////////////////////////////////////////////////////////////////////// // Construction/Destruction /* * Copyright (c) 2010,zyq5945@126.com * All rights reserved. * * 文件名称:CDXUTWindow.h * 文件标识:DXUT框架派生类 * 摘 要:DXUT使用的MFC框架的派生类头文件 * * 当前版本:1.00 * 作 者:zyq5945@126.com(注意把中文字符换成英文字符) * 完成日期:2010年7月26日 * 发布Blog:http://blog.csdn.net/zyq5945/ * */ ////////////////////////////////////////////////////////////////////// #pragma once #ifndef _DXUTWINDOW_H_102AA206_B47D_48e0_AFA8_159D8A8F548A #define _DXUTWINDOW_H_102AA206_B47D_48e0_AFA8_159D8A8F548A #include "DXUT.h" // CDXUTWindow class CDXUTWindow : public CWnd { DECLARE_DYNAMIC(CDXUTWindow) public: CDXUTWindow(); virtual ~CDXUTWindow(); public: public: // 移除父对话框的其他控件的WS_TABSTOP属性 BOOL RemoveOtherTabStop(); public: static BOOL CALLBACK EnumParentWindows(HWND hWnd, LPARAM lParam); // 封装的DXUT框架的渲染函数 static LRESULT CALLBACK OnKickIdle(WPARAM wParam = 0, LPARAM lParam = 0); // 在父对话框中设置本窗口的焦点 static void DXUTResetFocus(); // 重新设置定时器 BOOL ResetTimer(unsigned int nRenderTimerInterval, unsigned int OverTimeMultiple); private: void DXUTWindowInit(); protected: DECLARE_MESSAGE_MAP() public: afx_msg void OnDestroy(); afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); virtual BOOL PreTranslateMessage(MSG* pMsg); protected: virtual void PreSubclassWindow(); public: // 是否移除父对话框的其他控件的WS_TABSTOP属性,需在控件创建前设置 BOOL m_bRemoveOtherTabStop; // 是否使当本窗口无鼠标焦点在本窗口有鼠标消息时自动设置焦点 BOOL m_bAutoResetFocus; // 是否继续传递WM_KEYDOWN消息,会有"当当当"按键声 BOOL m_bNoWmKeyDown; // 是否是定时器渲染D3D,渲染需要模拟DXUT可以放在WM_KICKIDLE或者OnIdle中 BOOL m_bTimerRender; protected: UINT_PTR m_nRenderTimer; static UINT_PTR s_nTimerIndex; static unsigned int s_nRenderTimerInterval; static unsigned int s_nOverTimeMultiple; private: static BOOL s_bDXUTWindowFocus; static CDXUTWindow* s_pDXUTWindow; static unsigned __int64 s_i64TickCount; public: afx_msg BOOL OnEraseBkgnd(CDC* pDC); afx_msg void OnSetFocus(CWnd* pOldWnd); afx_msg void OnKillFocus(CWnd* pNewWnd); afx_msg void OnMouseMove(UINT nFlags, CPoint point); afx_msg void OnTimer(UINT_PTR nIDEvent); }; #endif
////////////////////////////////////////////////////////////////////// // Construction/Destruction /* * Copyright (c) 2010,zyq5945@126.com * All rights reserved. * * 文件名称:CDXUTWindow.cpp * 文件标识:DXUT框架派生类 * 摘 要:DXUT使用的MFC框架的派生类实现文件 * * 当前版本:1.00 * 作 者:zyq5945@126.com(注意把中文字符换成英文字符) * 完成日期:2010年7月26日 * 发布Blog:http://blog.csdn.net/zyq5945/ * */ ////////////////////////////////////////////////////////////////////// // CDXUTWindow.cpp : 实现文件 // #include "stdafx.h" #include "DXUTD3D9.h" #include "DXUTWindow.h" // CDXUTWindow IMPLEMENT_DYNAMIC(CDXUTWindow, CWnd) // 类静态变量 BOOL CDXUTWindow::s_bDXUTWindowFocus = FALSE; CDXUTWindow* CDXUTWindow::s_pDXUTWindow = NULL; unsigned __int64 CDXUTWindow::s_i64TickCount = GetTickCount(); unsigned int CDXUTWindow::s_nRenderTimerInterval = 15; unsigned int CDXUTWindow::s_nOverTimeMultiple = 3; UINT_PTR CDXUTWindow::s_nTimerIndex = 0x59455945; CDXUTWindow::CDXUTWindow() { m_bRemoveOtherTabStop = TRUE; m_bAutoResetFocus = TRUE; m_bNoWmKeyDown = TRUE; m_bTimerRender = TRUE; m_nRenderTimer = 0; } CDXUTWindow::~CDXUTWindow() { } BEGIN_MESSAGE_MAP(CDXUTWindow, CWnd) ON_WM_DESTROY() ON_WM_CREATE() ON_WM_ERASEBKGND() ON_WM_SETFOCUS() ON_WM_KILLFOCUS() ON_WM_MOUSEMOVE() ON_WM_TIMER() END_MESSAGE_MAP() // CDXUTWindow 消息处理程序 void CDXUTWindow::OnDestroy() { ASSERT(s_pDXUTWindow != NULL); s_pDXUTWindow = NULL; _DXUTOnWmClose(); CWnd::OnDestroy(); // TODO: 在此处添加消息处理程序代码 _DXUTMainLoopEnd(); } int CDXUTWindow::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CWnd::OnCreate(lpCreateStruct) == -1) return -1; // TODO: 在此添加您专用的创建代码 DXUTWindowInit(); return 0; } BOOL CDXUTWindow::PreTranslateMessage(MSG* pMsg) { // TODO: 在此添加专用代码和/或调用基类 DXUTStaticWndProc(pMsg->hwnd, pMsg->message, pMsg->wParam, pMsg->lParam); // 去除按键后"当当当"的声音 if ((pMsg->message == WM_KEYDOWN) && m_bNoWmKeyDown) { return TRUE; } return CWnd::PreTranslateMessage(pMsg); } void CDXUTWindow::PreSubclassWindow() { // TODO: 在此添加专用代码和/或调用基类 DXUTWindowInit(); CWnd::PreSubclassWindow(); } BOOL CDXUTWindow::RemoveOtherTabStop() { BOOL bRet = TRUE; HWND hParent = ::GetParent(m_hWnd); if (hParent != NULL) { bRet = ::EnumChildWindows(hParent, EnumParentWindows, 0); } return bRet; } BOOL CDXUTWindow::EnumParentWindows(HWND hWnd, LPARAM lParam) { if (lParam == 0) { LONG lStyle = GetWindowLong(hWnd, GWL_STYLE); if (lStyle & WS_TABSTOP) { SetWindowLong(hWnd, GWL_STYLE, lStyle & (~WS_TABSTOP)); } } else { RECT rc; POINT pt; ::GetCursorPos(&pt); ::ScreenToClient(hWnd, &pt); ::GetClientRect(hWnd, &rc); if (::PtInRect(&rc,pt)) { *((HWND*)lParam) = hWnd; return FALSE; } } return TRUE; } LRESULT CDXUTWindow::OnKickIdle(WPARAM wParam, LPARAM lParam) { if (s_pDXUTWindow !=NULL &&::IsWindow(s_pDXUTWindow->m_hWnd) && s_pDXUTWindow->IsWindowVisible()) { if (wParam == (WPARAM)s_nTimerIndex) { // 定时器 unsigned __int64 i64CurrentTickCount = GetTickCount(); BOOL bNotOverTime = (i64CurrentTickCount - s_i64TickCount) <= (s_nRenderTimerInterval * s_nOverTimeMultiple); if (bNotOverTime ) { _DXUTRender(); } s_i64TickCount = i64CurrentTickCount; } else { // 父窗口WM_KICKIDLE _DXUTRender(); } } return 0; } void CDXUTWindow::DXUTWindowInit() { if (m_bRemoveOtherTabStop) { RemoveOtherTabStop(); } // DXUT只支持一个实例 ASSERT(s_pDXUTWindow == NULL); s_pDXUTWindow = this; ASSERT((m_nRenderTimer != s_nTimerIndex) && (s_nTimerIndex != 0)); VERIFY(ResetTimer(s_nRenderTimerInterval, s_nOverTimeMultiple)); ASSERT(m_nRenderTimer == s_nTimerIndex); CDXUTD3D9Device::DXUTWindowInit(m_hWnd); } BOOL CDXUTWindow::OnEraseBkgnd(CDC* pDC) { // TODO: 在此添加消息处理程序代码和/或调用默认值 return TRUE; } void CDXUTWindow::DXUTResetFocus() { if (s_pDXUTWindow !=NULL && ::IsWindow(s_pDXUTWindow->m_hWnd) && s_pDXUTWindow->IsWindowVisible() && !s_bDXUTWindowFocus) { HWND hWndFocusAbove = NULL; HWND hWndParent = ::GetParent(s_pDXUTWindow->GetSafeHwnd()); if (hWndParent == NULL) { return; } ::EnumChildWindows(hWndParent, EnumParentWindows, (LPARAM)&hWndFocusAbove); if ((hWndFocusAbove == NULL) || (hWndFocusAbove = s_pDXUTWindow->GetSafeHwnd())) { s_pDXUTWindow->SetFocus(); } } } void CDXUTWindow::OnSetFocus(CWnd* pOldWnd) { CWnd::OnSetFocus(pOldWnd); // TODO: 在此处添加消息处理程序代码 s_bDXUTWindowFocus = TRUE; } void CDXUTWindow::OnKillFocus(CWnd* pNewWnd) { CWnd::OnKillFocus(pNewWnd); // TODO: 在此处添加消息处理程序代码 s_bDXUTWindowFocus = FALSE; } void CDXUTWindow::OnMouseMove(UINT nFlags, CPoint point) { // TODO: 在此添加消息处理程序代码和/或调用默认值a if (m_bAutoResetFocus) { SetFocus(); } CWnd::OnMouseMove(nFlags, point); } void CDXUTWindow::OnTimer(UINT_PTR nIDEvent) { // TODO: 在此添加消息处理程序代码和/或调用默认值 if ((nIDEvent == m_nRenderTimer) && m_bTimerRender) { OnKickIdle((WPARAM)s_nTimerIndex); } CWnd::OnTimer(nIDEvent); } BOOL CDXUTWindow::ResetTimer(unsigned int nRenderTimerInterval, unsigned int nOverTimeMultiple) { if ( (nRenderTimerInterval <10 || nRenderTimerInterval > 300) && (nOverTimeMultiple <2 || nOverTimeMultiple >10)) { AfxMessageBox(_T("请设置定时器时间为10毫秒到300毫秒之间的数/n / 定时器处理渲染超时倍数为2到10之间的数/n")); return TRUE; } if (m_nRenderTimer != 0) { VERIFY(KillTimer(m_nRenderTimer)); m_nRenderTimer = 0; } m_nRenderTimer = SetTimer(s_nTimerIndex, nRenderTimerInterval, NULL); ASSERT(m_nRenderTimer == s_nTimerIndex); s_nRenderTimerInterval = nRenderTimerInterval; s_nOverTimeMultiple = nOverTimeMultiple; return (m_nRenderTimer == s_nTimerIndex); }
CDXUTD3D9Device源代码
////////////////////////////////////////////////////////////////////// // Construction/Destruction /* * * 文件名称:DXUTD3D9.h * 文件标识:DXUT框架的主要接口 * 摘 要:DXUT框架的主要接口声明 * * 当前版本:1.00 * 作 者:zyq5945@126.com(注意把中文字符换成英文字符) * 完成日期:2010年7月26日 * 发布Blog:http://blog.csdn.net/zyq5945/ * */ ////////////////////////////////////////////////////////////////////// #pragma once #ifndef _DXUTD3D9_H_102AA206_B47D_48e0_AFA8_159D8A8F548A #define _DXUTD3D9_H_102AA206_B47D_48e0_AFA8_159D8A8F548A #include "dxut.h" class CDXUTD3D9Device { public: // hWnd是CDXUTWindow的窗口句柄 static void CALLBACK DXUTWindowInit(HWND hWnd); protected: static bool CALLBACK IsD3D9DeviceAcceptable( D3DCAPS9* pCaps, D3DFORMAT AdapterFormat, D3DFORMAT BackBufferFormat, bool bWindowed, void* pUserContext ); static bool CALLBACK ModifyDeviceSettings( DXUTDeviceSettings* pDeviceSettings, void* pUserContext ); static HRESULT CALLBACK OnD3D9CreateDevice( IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc, void* pUserContext ); static HRESULT CALLBACK OnD3D9ResetDevice( IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc, void* pUserContext ); static void CALLBACK OnFrameMove( double fTime, float fElapsedTime, void* pUserContext ); static void CALLBACK OnD3D9FrameRender( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext ); static LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool* pbNoFurtherProcessing, void* pUserContext ); static void CALLBACK OnD3D9LostDevice( void* pUserContext ); static void CALLBACK OnD3D9DestroyDevice( void* pUserContext ); }; #endif
////////////////////////////////////////////////////////////////////// // Construction/Destruction /* * * 文件名称:DXUTD3D9.cpp * 文件标识:DXUT框架的主要接口 * 摘 要:DXUT框架的主要接口实现 * * 当前版本:1.00 * 作 者:zyq5945@126.com(注意把中文字符换成英文字符) * 完成日期:2010年7月26日 * 发布Blog:http://blog.csdn.net/zyq5945/ * */ ////////////////////////////////////////////////////////////////////// // DXUTD3D9.cpp : 实现文件 // #include "stdafx.h" #include "DXUTD3D9.h" // CDXUTD3D9Device //-------------------------------------------------------------------------------------- // Rejects any D3D9 devices that aren't acceptable to the app by returning false //-------------------------------------------------------------------------------------- bool CALLBACK CDXUTD3D9Device::IsD3D9DeviceAcceptable( D3DCAPS9* pCaps, D3DFORMAT AdapterFormat, D3DFORMAT BackBufferFormat, bool bWindowed, void* pUserContext ) { // Typically want to skip back buffer formats that don't support alpha blending IDirect3D9* pD3D = DXUTGetD3D9Object(); if( FAILED( pD3D->CheckDeviceFormat( pCaps->AdapterOrdinal, pCaps->DeviceType, AdapterFormat, D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING, D3DRTYPE_TEXTURE, BackBufferFormat ) ) ) return false; return true; } //-------------------------------------------------------------------------------------- // Before a device is created, modify the device settings as needed //-------------------------------------------------------------------------------------- bool CALLBACK CDXUTD3D9Device::ModifyDeviceSettings( DXUTDeviceSettings* pDeviceSettings, void* pUserContext ) { return true; } //-------------------------------------------------------------------------------------- // Create any D3D9 resources that will live through a device reset (D3DPOOL_MANAGED) // and aren't tied to the back buffer size //-------------------------------------------------------------------------------------- HRESULT CALLBACK CDXUTD3D9Device::OnD3D9CreateDevice( IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc, void* pUserContext ) { return S_OK; } //-------------------------------------------------------------------------------------- // Create any D3D9 resources that won't live through a device reset (D3DPOOL_DEFAULT) // or that are tied to the back buffer size //-------------------------------------------------------------------------------------- HRESULT CALLBACK CDXUTD3D9Device::OnD3D9ResetDevice( IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc, void* pUserContext ) { return S_OK; } //-------------------------------------------------------------------------------------- // Handle updates to the scene. This is called regardless of which D3D API is used //-------------------------------------------------------------------------------------- void CALLBACK CDXUTD3D9Device::OnFrameMove( double fTime, float fElapsedTime, void* pUserContext ) { } //-------------------------------------------------------------------------------------- // Render the scene using the D3D9 device //-------------------------------------------------------------------------------------- void CALLBACK CDXUTD3D9Device::OnD3D9FrameRender( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext ) { HRESULT hr; // Clear the render target and the zbuffer V( pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_ARGB( 0, 45, 50, 170 ), 1.0f, 0 ) ); // Render the scene if( SUCCEEDED( pd3dDevice->BeginScene() ) ) { V( pd3dDevice->EndScene() ); } } //-------------------------------------------------------------------------------------- // Handle messages to the application //-------------------------------------------------------------------------------------- LRESULT CALLBACK CDXUTD3D9Device::MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool* pbNoFurtherProcessing, void* pUserContext ) { return 0; } //-------------------------------------------------------------------------------------- // Release D3D9 resources created in the OnD3D9ResetDevice callback //-------------------------------------------------------------------------------------- void CALLBACK CDXUTD3D9Device::OnD3D9LostDevice( void* pUserContext ) { } //-------------------------------------------------------------------------------------- // Release D3D9 resources created in the OnD3D9CreateDevice callback //-------------------------------------------------------------------------------------- void CALLBACK CDXUTD3D9Device::OnD3D9DestroyDevice( void* pUserContext ) { } void CALLBACK CDXUTD3D9Device::DXUTWindowInit(HWND hWnd) { // DXUT只支持一个实例 ASSERT( g_hWndD3DDevice == NULL ); ASSERT( hWnd != NULL); g_hWndD3DDevice = hWnd; LONG lStyle = GetWindowLong(hWnd, GWL_STYLE); if (lStyle & WS_TABSTOP) { SetWindowLong(hWnd, GWL_STYLE, lStyle & (~WS_TABSTOP)); } // Set the callback functions DXUTSetCallbackD3D9DeviceAcceptable( IsD3D9DeviceAcceptable ); DXUTSetCallbackD3D9DeviceCreated( OnD3D9CreateDevice ); DXUTSetCallbackD3D9DeviceReset( OnD3D9ResetDevice ); DXUTSetCallbackD3D9FrameRender( OnD3D9FrameRender ); DXUTSetCallbackD3D9DeviceLost( OnD3D9LostDevice ); DXUTSetCallbackD3D9DeviceDestroyed( OnD3D9DestroyDevice ); DXUTSetCallbackDeviceChanging( ModifyDeviceSettings ); DXUTSetCallbackMsgProc( MsgProc ); DXUTSetCallbackFrameMove( OnFrameMove ); // TODO: Perform any application-level initialization here // Initialize DXUT and create the desired Win32 window and Direct3D device for the application DXUTInit( true, true ); // Parse the command line and show msgboxes DXUTSetHotkeyHandling( true, true, true ); // handle the default hotkeys DXUTSetCursorSettings( true, true ); // Show the cursor and clip it when in full screen _DXUTCreateWindow( L"EmptyProject" ); RECT rc; VERIFY(GetClientRect(hWnd, &rc)); int nWeidth = rc.right - rc.left; int nHeight = rc.bottom - rc.top; ASSERT(nHeight >0 && nWeidth>0); DXUTCreateDevice( true, nWeidth, nHeight ); // Start the render loop HRESULT hr = S_OK; V(_DXUTMainLoopBegin()); return ; }
为了在MFC中使用DXUT框架,在dxut.h添加的声明
////////////////////////////////////////////////////////////////////////// // ZYQ #pragma comment( lib, "imm32.lib" ) #pragma comment( lib, "version.lib" ) #pragma comment( lib, "dxerr.lib" ) #pragma comment( lib, "dxguid.lib" ) //#pragma comment( lib, "d3dx9d.lib" ) //#pragma comment( lib, "d3d9.lib" ) //#pragma comment( lib, "d3dx10d.lib" ) #pragma comment( lib, "winmm.lib" ) #pragma comment( lib, "comctl32.lib" ) #ifndef WM_KICKIDLE #define WM_KICKIDLE 0x036A #endif #ifndef WM_ENTERIDLE #define WM_ENTERIDLE 0x0121 #endif HRESULT WINAPI _DXUTCreateWindow( const WCHAR* strWindowTitle = L"Direct3D Window", HINSTANCE hInstance = NULL, HICON hIcon = NULL, HMENU hMenu = NULL, int x = CW_USEDEFAULT, int y = CW_USEDEFAULT ); HRESULT WINAPI _DXUTMainLoopBegin( HACCEL hAccel = NULL ); void WINAPI _DXUTMainLoopEnd(); void WINAPI _DXUTRender(); LRESULT WINAPI _DXUTOnWmClose(WPARAM wParam = 0, LPARAM lParam = 0); extern HWND g_hWndD3DDevice; //////////////////////////////////////////////////////////////////////////
为了在MFC中使用DXUT框架,在dxut.cpp添加的函数
////////////////////////////////////////////////////////////////////////// // CDXUTWindow的窗口句柄,DXUT的局限性,只能创建一个 HWND g_hWndD3DDevice; //-------------------------------------------------------------------------------------- // Creates a window with the specified window title, icon, menu, and // starting position. If DXUTInit() has not already been called, it will // call it with the default parameters. Instead of calling this, you can // call DXUTSetWindow() to use an existing window. //-------------------------------------------------------------------------------------- HRESULT WINAPI _DXUTCreateWindow( const WCHAR* strWindowTitle, HINSTANCE hInstance, HICON hIcon, HMENU hMenu, int x, int y ) { HRESULT hr; // Not allowed to call this from inside the device callbacks if( GetDXUTState().GetInsideDeviceCallback() ) return DXUT_ERR_MSGBOX( L"DXUTCreateWindow", E_FAIL ); GetDXUTState().SetWindowCreateCalled( true ); if( !GetDXUTState().GetDXUTInited() ) { // If DXUTInit() was already called and failed, then fail. // DXUTInit() must first succeed for this function to succeed if( GetDXUTState().GetDXUTInitCalled() ) return E_FAIL; // If DXUTInit() hasn't been called, then automatically call it // with default params hr = DXUTInit(); if( FAILED( hr ) ) return hr; } if( DXUTGetHWNDFocus() == NULL ) { if( hInstance == NULL ) hInstance = ( HINSTANCE )GetModuleHandle( NULL ); GetDXUTState().SetHInstance( hInstance ); WCHAR szExePath[MAX_PATH]; GetModuleFileName( NULL, szExePath, MAX_PATH ); if( hIcon == NULL ) // If the icon is NULL, then use the first one found in the exe hIcon = ExtractIcon( hInstance, szExePath, 0 ); // // Register the windows class // WNDCLASS wndClass; // wndClass.style = CS_DBLCLKS; // wndClass.lpfnWndProc = DXUTStaticWndProc; // wndClass.cbClsExtra = 0; // wndClass.cbWndExtra = 0; // wndClass.hInstance = hInstance; // wndClass.hIcon = hIcon; // wndClass.hCursor = LoadCursor( NULL, IDC_ARROW ); // wndClass.hbrBackground = ( HBRUSH )GetStockObject( BLACK_BRUSH ); // wndClass.lpszMenuName = NULL; // wndClass.lpszClassName = L"Direct3DWindowClass"; // // if( !RegisterClass( &wndClass ) ) // { // DWORD dwError = GetLastError(); // if( dwError != ERROR_CLASS_ALREADY_EXISTS ) // return DXUT_ERR_MSGBOX( L"RegisterClass", HRESULT_FROM_WIN32(dwError) ); // } // Override the window's initial & size position if there were cmd line args if( GetDXUTState().GetOverrideStartX() != -1 ) x = GetDXUTState().GetOverrideStartX(); if( GetDXUTState().GetOverrideStartY() != -1 ) y = GetDXUTState().GetOverrideStartY(); GetDXUTState().SetWindowCreatedWithDefaultPositions( false ); if( x == CW_USEDEFAULT && y == CW_USEDEFAULT ) GetDXUTState().SetWindowCreatedWithDefaultPositions( true ); // Find the window's initial size, but it might be changed later int nDefaultWidth = 640; int nDefaultHeight = 480; if( GetDXUTState().GetOverrideWidth() != 0 ) nDefaultWidth = GetDXUTState().GetOverrideWidth(); if( GetDXUTState().GetOverrideHeight() != 0 ) nDefaultHeight = GetDXUTState().GetOverrideHeight(); RECT rc; SetRect( &rc, 0, 0, nDefaultWidth, nDefaultHeight ); AdjustWindowRect( &rc, WS_OVERLAPPEDWINDOW, ( hMenu != NULL ) ? true : false ); WCHAR* strCachedWindowTitle = GetDXUTState().GetWindowTitle(); wcscpy_s( strCachedWindowTitle, 256, strWindowTitle ); // // Create the render window // HWND hWnd = CreateWindow( L"Direct3DWindowClass", strWindowTitle, WS_OVERLAPPEDWINDOW, // x, y, ( rc.right - rc.left ), ( rc.bottom - rc.top ), 0, // hMenu, hInstance, 0 ); HWND hWnd = g_hWndD3DDevice; assert(hWnd != NULL); if( hWnd == NULL ) { DWORD dwError = GetLastError(); return DXUT_ERR_MSGBOX( L"CreateWindow", HRESULT_FROM_WIN32(dwError) ); } GetDXUTState().SetWindowCreated( true ); GetDXUTState().SetHWNDFocus( hWnd ); GetDXUTState().SetHWNDDeviceFullScreen( hWnd ); GetDXUTState().SetHWNDDeviceWindowed( hWnd ); } return S_OK; } HACCEL g_hAccel; //-------------------------------------------------------------------------------------- // Handles app's message loop and rendering when idle. If DXUTCreateDevice() or DXUTSetD3D*Device() // has not already been called, it will call DXUTCreateWindow() with the default parameters. //-------------------------------------------------------------------------------------- HRESULT WINAPI _DXUTMainLoopBegin( HACCEL hAccel ) { HRESULT hr; g_hAccel = hAccel; // Not allowed to call this from inside the device callbacks or reenter if( GetDXUTState().GetInsideDeviceCallback() || GetDXUTState().GetInsideMainloop() ) { if( ( GetDXUTState().GetExitCode() == 0 ) || ( GetDXUTState().GetExitCode() == 10 ) ) GetDXUTState().SetExitCode( 1 ); return DXUT_ERR_MSGBOX( L"DXUTMainLoop", E_FAIL ); } GetDXUTState().SetInsideMainloop( true ); // If DXUTCreateDevice() or DXUTSetD3D*Device() has not already been called, // then call DXUTCreateDevice() with the default parameters. if( !GetDXUTState().GetDeviceCreated() ) { if( GetDXUTState().GetDeviceCreateCalled() ) { if( ( GetDXUTState().GetExitCode() == 0 ) || ( GetDXUTState().GetExitCode() == 10 ) ) GetDXUTState().SetExitCode( 1 ); return E_FAIL; // DXUTCreateDevice() must first succeed for this function to succeed } hr = DXUTCreateDevice(); if( FAILED( hr ) ) { if( ( GetDXUTState().GetExitCode() == 0 ) || ( GetDXUTState().GetExitCode() == 10 ) ) GetDXUTState().SetExitCode( 1 ); return hr; } } HWND hWnd = DXUTGetHWND(); // DXUTInit() must have been called and succeeded for this function to proceed // DXUTCreateWindow() or DXUTSetWindow() must have been called and succeeded for this function to proceed // DXUTCreateDevice() or DXUTCreateDeviceFromSettings() or DXUTSetD3D*Device() must have been called and succeeded for this function to proceed if( !GetDXUTState().GetDXUTInited() || !GetDXUTState().GetWindowCreated() || !GetDXUTState().GetDeviceCreated() ) { if( ( GetDXUTState().GetExitCode() == 0 ) || ( GetDXUTState().GetExitCode() == 10 ) ) GetDXUTState().SetExitCode( 1 ); return DXUT_ERR_MSGBOX( L"DXUTMainLoop", E_FAIL ); } // Now we're ready to receive and process Windows messages. // bool bGotMsg; // MSG msg; // msg.message = WM_NULL; // PeekMessage( &msg, NULL, 0U, 0U, PM_NOREMOVE ); // while( WM_QUIT != msg.message ) // { // Use PeekMessage() so we can use idle time to render the scene. // bGotMsg = ( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) != 0 ); // // if( bGotMsg ) // { // // Translate and dispatch the message // if( hAccel == NULL || hWnd == NULL || // 0 == TranslateAccelerator( hWnd, hAccel, &msg ) ) // { // TranslateMessage( &msg ); // DispatchMessage( &msg ); // } // } // else // { // Render a frame during idle time (no messages are waiting) // DXUTRender3DEnvironment(); // } // } // // Cleanup the accelerator table // if( hAccel != NULL ) // DestroyAcceleratorTable( hAccel ); // // GetDXUTState().SetInsideMainloop( false ); return S_OK; } void WINAPI _DXUTMainLoopEnd() { // Cleanup the accelerator table if( g_hAccel != NULL ) DestroyAcceleratorTable( g_hAccel ); GetDXUTState().SetInsideMainloop( false ); } void WINAPI _DXUTRender() { DXUTRender3DEnvironment(); } LRESULT WINAPI _DXUTOnWmClose(WPARAM wParam, LPARAM lParam) { assert(g_hWndD3DDevice != NULL); HMENU hMenu; hMenu = GetMenu( g_hWndD3DDevice ); if( hMenu != NULL ) DestroyMenu( hMenu ); //DestroyWindow( hWnd ); //UnregisterClass( L"Direct3DWindowClass", NULL ); GetDXUTState().SetHWNDFocus( NULL ); GetDXUTState().SetHWNDDeviceFullScreen( NULL ); GetDXUTState().SetHWNDDeviceWindowed( NULL ); return 0; }