这章主要介绍一下DXUT 里面的GUI元素。要在图形界面中添加GUI元素,首先要定义一个DialogResourceManager对象用来管理对话框资源。DialogResourceManager 管理渲染时状态、Sprite控制批量显示更新、对话框字体、纹理等等。CDXUTDialog 相当于MFC里面的对话框,作为各种控件资源的容器。CD3DSettingsDlg 是一个ms已经写好的对话框类,可以用来设置各种Direct3DDevice9 创建时的参数。点击该对话框的ok 按钮,D3D设备将会重建。
这里先建立了DialogResourceManager全局变量g_DialogResourceManager和CD3DSettingsDlg 全局变量g_SettingsDlg。并且要在 OnCreateDevice OnResetDevice MsgProc OnLostDevice OnDestroyDevice 回调函数中调用自己相应的函数如g_DialogResourceManager.OnCreateDevice(...) 等等。 对于对话框对象使用前必须初始化 init() 参数为DialogResourceManager类对象,即g_DialogResourceManager.之后对于CDXUTDialog类对象g_HUD需要设置自己的消息回调函数 OnGUIEvent()。并且在 dxut 的消息处理函数MsgProc中调用自己的消息处理函数 g_HUD->MsgProc(), 如果是该对话框的消息,Dxut回调函数将不再处理这个消息。而交由对话框处理。 //使用DXUT 框架GUI程序 #include <dxstdafx.h>
//自定义顶点结构 struct CUSTOMVERTEX { float x,y,z,rhw; DWORD diffuse; };
ID3DXFont* g_pFont = NULL; // Font for drawing text ID3DXSprite* g_pTextSprite = NULL; // Sprite for batching draw text calls bool g_bShowHelp = true; // If true, it renders the UI control text CDXUTDialogResourceManager g_DialogResourceManager; // manager for shared resources of dialogs CD3DSettingsDlg g_SettingsDlg; // Device settings dialog CDXUTDialog g_HUD; // dialog for standard controls static const int D3DFVF_CUSTOMVERTEX = D3DFVF_XYZRHW | D3DFVF_DIFFUSE; LPDIRECT3DVERTEXBUFFER9 g_pVB; bool g_vsb = true;
//定义g_HUD对话框上按钮ID static const int IDC_TOGGLEFULLSCREEN=1; static const int IDC_TOGGLEREF=2; static const int IDC_CHANGEDEVICE=3;
HRESULT CALLBACK OnCreateDevice( IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc, void* pUserContext ); HRESULT CALLBACK OnResetDevice( IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc, void* pUserContext ); void CALLBACK OnFrameMove( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext ); void CALLBACK OnFrameRender( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext ); LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool* pbNoFurtherProcessing, void* pUserContext ); void CALLBACK KeyboardProc( UINT nChar, bool bKeyDown, bool bAltDown, void* pUserContext ); void CALLBACK OnGUIEvent( UINT nEvent, int nControlID, CDXUTControl* pControl, void* pUserContext ); void CALLBACK OnLostDevice( void* pUserContext ); void CALLBACK OnDestroyDevice( void* pUserContext ); void InitApp(); void RenderText();
INT WINAPI WinMain( HINSTANCE, HINSTANCE, LPSTR, int ) { //为DEBUG模式激活运行时内存检查 #if defined(DEBUG) | defined(_DEBUG) _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF ); #endif // 设置回调函数,这些函数允许DXUT通知应用程序更换设备,用户输入和窗口消息。 // 回调函数是可选的,因此你要做的仅是设置你感兴趣的事件的回调函数。 DXUTSetCallbackDeviceCreated( OnCreateDevice ); DXUTSetCallbackDeviceReset( OnResetDevice ); DXUTSetCallbackDeviceLost( OnLostDevice ); DXUTSetCallbackDeviceDestroyed( OnDestroyDevice ); DXUTSetCallbackFrameRender( OnFrameRender ); DXUTSetCallbackFrameMove( OnFrameMove ); DXUTSetCallbackMsgProc( MsgProc ); DXUTSetCallbackKeyboard( KeyboardProc ); // 全屏时显示鼠标 DXUTSetCursorSettings( true, true ); //InitApp(); // 初始化DXUT并创建想要的Win32窗口和应用程序的Direct3D设备。调用这些 // 可选函数中的每一个,此外它们允许你设置几个选项来控制框架的行为。 DXUTInit( TRUE, TRUE, TRUE ); DXUTCreateWindow( L"ameng" ); DXUTCreateDevice( D3DADAPTER_DEFAULT, TRUE, 640, 480 ); // 通过DXUT来处理消息循环并分派渲染调用。当在空闲时间和处理窗口消息的 // 时间间隔时,框架将调用OnFrameMove和OnFrameRender回调函数。 DXUTMainLoop(); return DXUTGetExitCode(); } void InitApp() { // 初始化对话框 g_SettingsDlg.Init(&g_DialogResourceManager ); g_HUD.Init(&g_DialogResourceManager ); //设置对话框消息处理函数。 g_HUD.SetCallback( OnGUIEvent ); int iY = 10; g_HUD.AddButton( IDC_TOGGLEFULLSCREEN, L"Toggle full screen", 35, iY, 125, 22 ); g_HUD.AddButton( IDC_TOGGLEREF, L"Toggle REF (F3)", 35, iY += 24, 125, 22,VK_F3 ); g_HUD.AddButton( IDC_CHANGEDEVICE, L"Change device (F2)", 35, iY += 24, 125, 22, VK_F2 ); }
HRESULT CALLBACK OnCreateDevice( IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc, void* pUserContext ) { HRESULT hr; V_RETURN( g_DialogResourceManager.OnCreateDevice( pd3dDevice ) ); InitApp(); V_RETURN( g_SettingsDlg.OnCreateDevice( pd3dDevice ) ); // Initialize the font V_RETURN( D3DXCreateFont( pd3dDevice, 15, 0, FW_BOLD, 1, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, L"Arial", &g_pFont ) ); return S_OK; } HRESULT CALLBACK OnResetDevice( IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc, void* pUserContext ) { HRESULT hr; static CUSTOMVERTEX vertices[] = { { 300.0f, 50.0f, 0.1f, 1.0f, D3DCOLOR_ARGB(255,255,0,0) }, // x, y, z, rhw, color { 500.0f, 350.0f, 0.1f, 1.0f, D3DCOLOR_ARGB(255,0,255,0) }, { 100.0f, 350.0f, 0.1f, 1.0f, D3DCOLOR_ARGB(255,0,0,255) }, }; pd3dDevice->CreateVertexBuffer(3*sizeof(CUSTOMVERTEX),0,D3DFVF_CUSTOMVERTEX,D3DPOOL_DEFAULT,&g_pVB,NULL); BYTE* pVertices; if( FAILED( g_pVB->Lock( 0, sizeof(vertices), (void**)&pVertices, 0 ))) return E_FAIL; memcpy(pVertices,vertices,sizeof(vertices)); g_pVB->Unlock(); V_RETURN( g_DialogResourceManager.OnResetDevice() ); V_RETURN( g_SettingsDlg.OnResetDevice() ); if( g_pFont ) V_RETURN( g_pFont->OnResetDevice() ); // Create a sprite to help batch calls when drawing many lines of text V_RETURN( D3DXCreateSprite( pd3dDevice, &g_pTextSprite ) ); g_HUD.SetLocation( pBackBufferSurfaceDesc->Width-170, 0 ); g_HUD.SetSize( 170, 170 ); return S_OK; } void CALLBACK OnFrameMove( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext ) {
} void CALLBACK OnFrameRender( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext ) { HRESULT hr; V( pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_ARGB(0, 0, 0, 0), 1.0f, 0) ); V(pd3dDevice->SetStreamSource(0,g_pVB,0,sizeof(CUSTOMVERTEX))); V(pd3dDevice->SetFVF(D3DFVF_CUSTOMVERTEX)); if( g_SettingsDlg.IsActive() ) { g_SettingsDlg.OnRender( fElapsedTime ); return; } if(SUCCEEDED(pd3dDevice->BeginScene())) { //更新图像 V(pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST,0,1)); if(g_vsb) { RenderText(); } V( g_HUD.OnRender( fElapsedTime ) ); // V( g_SampleUI.OnRender( fElapsedTime ) ); pd3dDevice->EndScene(); } } void RenderText() { // The helper object simply helps keep track of text position, and color // and then it calls pFont->DrawText( m_pSprite, strMsg, -1, &rc, DT_NOCLIP, m_clr ); // If NULL is passed in as the sprite object, then it will work however the // pFont->DrawText() will not be batched together. Batching calls will improves performance. CDXUTTextHelper txtHelper( g_pFont, g_pTextSprite, 15 ); // Output statistics txtHelper.Begin(); txtHelper.SetInsertionPos( 5, 5 ); txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 1.0f, 0.0f, 1.0f ) ); txtHelper.DrawTextLine( DXUTGetFrameStats(true) ); //为true 显现FPS,默认为false不显使FPS txtHelper.DrawTextLine( DXUTGetDeviceStats() );
//TODO: add UI text as needed txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 1.0f, 1.0f, 1.0f ) ); txtHelper.DrawTextLine( L"Put whatever misc status here" );
// 获取图象后备缓冲区 const D3DSURFACE_DESC* pd3dsdBackBuffer = DXUTGetBackBufferSurfaceDesc(); if( g_bShowHelp ) { txtHelper.SetInsertionPos( 10, pd3dsdBackBuffer->Height-15*6 ); txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 0.75f, 0.0f, 1.0f ) ); txtHelper.DrawTextLine( L"Controls (F1 to hide):" ); txtHelper.SetInsertionPos( 40, pd3dsdBackBuffer->Height-15*5 ); txtHelper.DrawTextLine( L"Quit: ESC" ); } else { //txtHelper.SetInsertionPos( 10, pd3dsdBackBuffer->Height-15*2 ); txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 1.0f, 1.0f, 1.0f ) ); txtHelper.DrawTextLine( L"Press F1 for help" ); } txtHelper.End(); }
//-------------------------------------------------------------------------------------- // Before handling window messages, DXUT passes incoming windows // messages to the application through this callback function. If the application sets // *pbNoFurtherProcessing to TRUE, then DXUT will not process this message. //-------------------------------------------------------------------------------------- LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool* pbNoFurtherProcessing, void* pUserContext ) { // Always allow dialog resource manager calls to handle global messages // so GUI state is updated correctly *pbNoFurtherProcessing = g_DialogResourceManager.MsgProc( hWnd, uMsg, wParam, lParam ); if( *pbNoFurtherProcessing ) return 0; if( g_SettingsDlg.IsActive() ) { g_SettingsDlg.MsgProc( hWnd, uMsg, wParam, lParam ); return 0; } // Give the dialogs a chance to handle the message first *pbNoFurtherProcessing = g_HUD.MsgProc( hWnd, uMsg, wParam, lParam ); if( *pbNoFurtherProcessing ) return 0; return 0; }
//-------------------------------------------------------------------------------------- // As a convenience, DXUT inspects the incoming windows messages for // keystroke messages and decodes the message parameters to pass relevant keyboard // messages to the application. The framework does not remove the underlying keystroke // messages, which are still passed to the application's MsgProc callback. //-------------------------------------------------------------------------------------- void CALLBACK KeyboardProc( UINT nChar, bool bKeyDown, bool bAltDown, void* pUserContext ) { if( bKeyDown ) { switch( nChar ) { case VK_F1: g_bShowHelp = !g_bShowHelp; break; case VK_F4: g_HUD.SetVisible(!g_HUD.GetVisible()); g_vsb = !g_vsb; break; default: break; } } }
//-------------------------------------------------------------------------------------- // Handles the GUI events //-------------------------------------------------------------------------------------- void CALLBACK OnGUIEvent( UINT nEvent, int nControlID, CDXUTControl* pControl, void* pUserContext ) { switch( nControlID ) { case IDC_TOGGLEFULLSCREEN: DXUTToggleFullScreen(); break; case IDC_TOGGLEREF: DXUTToggleREF(); break; case IDC_CHANGEDEVICE: g_SettingsDlg.SetActive( !g_SettingsDlg.IsActive() ); break; } } void CALLBACK OnLostDevice( void* pUserContext ) { if(g_pVB != NULL) { g_pVB->Release(); g_pVB = NULL; } g_DialogResourceManager.OnLostDevice(); g_SettingsDlg.OnLostDevice(); if( g_pFont ) g_pFont->OnLostDevice(); SAFE_RELEASE( g_pTextSprite ); } void CALLBACK OnDestroyDevice( void* pUserContext ) { g_DialogResourceManager.OnDestroyDevice(); g_SettingsDlg.OnDestroyDevice(); SAFE_RELEASE( g_pFont ); }
|