MFC and DirectDraw
Hey
When I initialize Directdraw in MFC, where should I get the Hwnd from? Basically I''m gonna create a DirectDraw object in my View class, but I don''t know how to get the proper window handle from the view class.
Thanks
-----------------------------Kahoy the Slasher
I don''t know much about MFC, really. I have only tried it once or twice, but it didn''t feel right for me...
But anyways, If I remember correctly, all windows objects have a member mHwnd (or someting, not sure about the name). It holds the value of the HWND. Please correct me if I''m wrong.
But anyways, If I remember correctly, all windows objects have a member mHwnd (or someting, not sure about the name). It holds the value of the HWND. Please correct me if I''m wrong.
GetSafeHwnd() is the method you need, I believe. Call it from your main window. You could instead access your main window object''s m_hWnd member, but that''s quite discouraged.
Often you don''t wnat to render into the entier window either.
It that case, add a "picture" control to your dialog resource (its really an MFC CStatic), and use GetSafeHwnd on that CStatic object. You can add a border this way too... look up the MFC Fog example for code.
It that case, add a "picture" control to your dialog resource (its really an MFC CStatic), and use GetSafeHwnd on that CStatic object. You can add a border this way too... look up the MFC Fog example for code.
- The trade-off between price and quality does not exist in Japan. Rather, the idea that high quality brings on cost reduction is widely accepted.-- Tajima & Matsubara
Hmmm...what if I want to use a full-screen display, can I still use the result from GetSafeHwnd() ?
-----------------------------Kahoy the Slasher
Here is a simplified version what I did in one of my demos using DX7. I used my CView derived class's m_hWnd member.
But the trick I did was to use a delayed D3D initialization. That is, don't create D3D in your CViewDerived::OnCreate() function but instead use :: PostMessage() to post a WM_COMMAND or a WM_USER message to yourself. Then you will recieve your own "ID_CREATE_D3D" message after MFC has your window completely created and initialized.
Now after I have that all done, CDirect3DView never gets instantiated. My application uses a derivative of CDirect3DView, and overrides CView::OnDraw to do the rendering. I also add my app specific stuff.
Edited by - Marsupial Rodentia on December 18, 2000 11:06:15 PM
Edited by - Marsupial Rodentia on December 18, 2000 11:07:57 PM
Edited by - Marsupial Rodentia on December 18, 2000 11:10:12 PM
Edited by - Marsupial Rodentia on December 18, 2000 11:17:40 PM
But the trick I did was to use a delayed D3D initialization. That is, don't create D3D in your CViewDerived::OnCreate() function but instead use :: PostMessage() to post a WM_COMMAND or a WM_USER message to yourself. Then you will recieve your own "ID_CREATE_D3D" message after MFC has your window completely created and initialized.
// VideoData.hclass CVideoData {protected: LPDIRECTDRAW7 m_pDraw; LPDIRECT3D7 m_p3D; LPDIRECT3DDEVICE7 m_p3dDevice; LPDIRECTDRAWSURFACE7 m_pFrontBuffer; LPDIRECTDRAWSURFACE7 m_pBackBuffer; LPDIRECTDRAWSURFACE7 m_pDepthBuffer; LPDIRECTDRAWGAMMACONTROL m_pGamma; LPDIRECTDRAWCOLORCONTROL m_pColor;protected: RECT m_rcScreenRect; RECT m_rcViewportRect; BOOL m_bFullscreen; LPGUID m_pDeviceGuid;};// VideoInitTerm.hclass CVideoInitTerm : virtual public CVideoData {public: CVideoInitTerm(); ~CVideoInitTerm();public: virtual void Init( HWND hWnd ); virtual void Term();protected: HRESULT CreateInterfaces( HWND hWnd ); HRESULT DestroyInterfaces(); HRESULT CreateBuffersFullscreen( HWND hWnd ); HRESULT CreateBuffersWindowed( HWND hWnd ); HRESULT DestroyBuffers(); HRESULT CreateDevice( HWND hWnd, LPGUID pDeviceGuid ); HRESULT DestroyDevice(); HRESULT CreateDepthBuffer( HWND hWnd, LPGUID pDeviceGuid ); HRESULT DestroyDepthBuffer();};// Direct3DView.hclass CDirect3DView : virtual public CVideoInitTerm, public CView{ // Generated message map functionsprotected: //{{AFX_MSG(CDirect3DView) afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); afx_msg void OnDestroy(); afx_msg void OnCreated3d(); afx_msg void OnDestroyd3d(); afx_msg void OnMove(int x, int y); afx_msg void OnSize(UINT nType, int cx, int cy); afx_msg void OnResetd3d(); afx_msg BOOL OnEraseBkgnd(CDC* pDC); afx_msg void OnSetFocus(CWnd* pOldWnd); afx_msg void OnKillFocus(CWnd* pNewWnd); //}}AFX_MSG DECLARE_MESSAGE_MAP()};// Direct3DView.cppBEGIN_MESSAGE_MAP(CDirect3DView, CView) //{{AFX_MSG_MAP(CDirect3DView) ON_WM_CREATE() ON_WM_DESTROY() ON_COMMAND(ID_CREATED3D, OnCreated3d) ON_COMMAND(ID_DESTROYD3D, OnDestroyd3d) ON_WM_MOVE() ON_WM_SIZE() ON_COMMAND(ID_RESETD3D, OnResetd3d) ON_WM_ERASEBKGND() ON_WM_SETFOCUS() ON_WM_KILLFOCUS() //}}AFX_MSG_MAPEND_MESSAGE_MAP()void CDirect3DView::OnDraw(CDC* pDC){ CDocument* pDoc = GetDocument(); ASSERT_VALID(pDoc); if( m_bReadyToRender ) { /****m_FrameTimer.Start( 30.0f ); ***/ // This needs to be set/reset for CWnd::OnTimer ClearViewport(); SetTransforms(); UpdateAnimation( m_FrameTimer ); RenderScene( pDoc ); BltToScreen(); m_FrameTimer.Frame(); }}// This function is called by OnDraw, it may be overridden in the derived class.void CDirect3DView::ClearViewport(){ HRESULT hr; ASSERT( m_p3dDevice != NULL ); hr = m_p3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, m_dwVwPrtClrColor, 1.0f, 0L ); if( FAILED( hr ) ) { D3DTRACE( hr, "%s (%i)", __FILE__, __LINE__ ); }}// Must be overridden by the derived classvoid CDirect3DView::UpdateAnimation( CFrameTimer& FrameTimer ){ }// This function is called by OnDraw and should be overridden in derived class.void CDirect3DView::RenderScene( CDocument* pDoc ){ }// This function is called by OnDraw, it could be overridden in derived class.void CDirect3DView::BltToScreen(){ HRESULT hr; ASSERT( m_pFrontBuffer != NULL ); for( ;; ) // Same as a goto statement { // Note that it is important not to get the Dst and Src rects mixed up! hr = m_pFrontBuffer->Blt( &m_rcScreenRect, // Destination m_pBackBuffer, &m_rcViewportRect, // Source DDBLT_WAIT, NULL ); if( hr == DD_OK ) return; if( hr == DDERR_INVALIDRECT ) { ReCreateSDV(); ResetBltDst(); continue; } if( hr == DDERR_SURFACELOST && FAILED( hr = m_pFrontBuffer->Restore() ) ) { return; } if( hr != DDERR_WASSTILLDRAWING ) return; else { // if...then...else what the hell is it? D3DTRACE( hr, "%s (%i)", __FILE__, __LINE__ ); // Prevent infinite loops return; } } return;}// Re-Create Surface, Device, Viewport every time the window is sized// This should be called by OnSizevoid CDirect3DView::ReCreateSDV(){ m_bReadyToRender = FALSE; { DestroyDepthBuffer(); DestroyDevice(); DestroyBuffers(); RECT rcClient; GetClientRect( &rcClient ); if( ((rcClient.right - rcClient.left) == 0) || ((rcClient.bottom - rcClient.top) == 0) ) { return; // There is NO client area! } LPGUID pGuid; if( m_bFullscreen ) { pGuid = (LPGUID)&IID_IDirect3DHALDevice; CreateBuffersFullscreen( m_hWnd ); // TODO: Put some error checking and recovory here } else { pGuid = (LPGUID)&IID_IDirect3DRGBDevice; CreateBuffersWindowed( m_hWnd ); // TODO: Put some error checking and recovory here } CreateDevice( m_hWnd, pGuid ); // TODO: Put some error checking and recovory here CreateDepthBuffer( m_hWnd, pGuid ); // TODO: Put some error checking and recovory here } m_bReadyToRender = TRUE;}// Reset the Blt destination rectangle every time the window is moved// This should be called by OnMovevoid CDirect3DView::ResetBltDst(){ ::GetClientRect( m_hWnd, &m_rcScreenRect ); ::ClientToScreen( m_hWnd, (LPPOINT)&m_rcScreenRect.left ); ::ClientToScreen( m_hWnd, (LPPOINT)&m_rcScreenRect.right );}int CDirect3DView::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CView::OnCreate(lpCreateStruct) == -1) return -1; // POSTPONE DIRECT3D CREATION UNTIL ALL WINDOWS ARE INITIALIZED PostMessage( WM_COMMAND, ID_CREATED3D, 0 ); return 0;}void CDirect3DView::OnDestroy() { // DESTROY DIRECT3D NOW SendMessage( WM_COMMAND, ID_DESTROYD3D, 0 ); CView::OnDestroy();}void CDirect3DView::OnCreated3d() { Init( m_hWnd ); ResetBltDst(); ResetTransforms(); m_bReadyToRender = TRUE;}void CDirect3DView::OnDestroyd3d() { m_bReadyToRender = FALSE; Term();}void CDirect3DView::OnMove(int x, int y) { m_bReadyToRender = FALSE; CView::OnMove(x, y); if( NULL == m_pDraw ) return; ResetBltDst(); m_bReadyToRender = TRUE; Invalidate( FALSE );}void CDirect3DView::OnSize(UINT nType, int cx, int cy) { m_bReadyToRender = FALSE; CView::OnSize(nType, cx, cy); if( NULL == m_pDraw ) return; PostMessage( WM_COMMAND, ID_RESETD3D, 0 );}void CDirect3DView::OnResetd3d() { ReCreateSDV(); ResetBltDst(); Invalidate( FALSE );}BOOL CDirect3DView::OnEraseBkgnd(CDC* pDC) { if( !m_bReadyToRender ) { // Damnit! Why can't two different APIs from the same software company // use the same conventions and representations?!? // Here we have to convert from D3D color to GDI color. SetClassLong( m_hWnd, GCL_HBRBACKGROUND, (long)(HBRUSH)CBrush( ( (DWORD) (((BYTE) (RGB_GETRED(m_dwVwPrtClrColor) | ( (WORD) (RGB_GETGREEN(m_dwVwPrtClrColor)) << 8)) | ( ((DWORD) (BYTE) (RGB_GETBLUE(m_dwVwPrtClrColor))) ) << 16))) ) ); // Go ahead and erase it because D3D isn't ready. return CView::OnEraseBkgnd(pDC); } else { // Get rid of screen flicker, CView::OnPaint will call CDirect3DView::OnDraw, // OnDraw will use D3D to clear the viewport. return TRUE; }}void CDirect3DView::OnSetFocus(CWnd* pOldWnd) { CView::OnSetFocus(pOldWnd); ModifyStyleEx( 0, WS_EX_STATICEDGE, SWP_FRAMECHANGED );}void CDirect3DView::OnKillFocus(CWnd* pNewWnd) { CView::OnKillFocus(pNewWnd); ModifyStyleEx( WS_EX_STATICEDGE, 0, SWP_FRAMECHANGED ); }
Now after I have that all done, CDirect3DView never gets instantiated. My application uses a derivative of CDirect3DView, and overrides CView::OnDraw to do the rendering. I also add my app specific stuff.
Edited by - Marsupial Rodentia on December 18, 2000 11:06:15 PM
Edited by - Marsupial Rodentia on December 18, 2000 11:07:57 PM
Edited by - Marsupial Rodentia on December 18, 2000 11:10:12 PM
Edited by - Marsupial Rodentia on December 18, 2000 11:17:40 PM
I think you can use any ole'' hwnd for a full screen app. (GetSafeHwnd)
Magmai Kai Holmlor
- The disgruntled & disillusioned
Magmai Kai Holmlor
- The disgruntled & disillusioned
- The trade-off between price and quality does not exist in Japan. Rather, the idea that high quality brings on cost reduction is widely accepted.-- Tajima & Matsubara
I''m not done yet.
// VideoInitTerm.cppstatic HRESULT WINAPI EnumZBufferFormatsCallback( DDPIXELFORMAT* pddpf, VOID* pddpfDesired ){ // Return the first matching enumerated z-buffer format DDPIXELFORMAT* pddpfOut = (DDPIXELFORMAT*)pddpfDesired; if( pddpfOut->dwRGBBitCount == pddpf->dwRGBBitCount ) { (*pddpfOut) = (*pddpf); return D3DENUMRET_CANCEL; } return D3DENUMRET_OK;}//////////////////////////////////////////////////////////////////////// Construction/DestructionCVideoInitTerm::CVideoInitTerm() : CVideoData(){}CVideoInitTerm::~CVideoInitTerm(){}//////////////////////////////////////////////////////////////////////// DirectX Initialization / Terminationvoid CVideoInitTerm::Init( HWND hWnd ){ CreateInterfaces( hWnd ); // TODO: Put some error checking and recovory here m_bFullscreen = FALSE; // FIXME: Set this flag in the derived class or the client code. LPGUID pGuid; if( m_bFullscreen ) { pGuid = (LPGUID)&IID_IDirect3DHALDevice; CreateBuffersFullscreen( hWnd ); // TODO: Put some error checking and recovory here } else { pGuid = (LPGUID)&IID_IDirect3DRGBDevice; CreateBuffersWindowed( hWnd ); // TODO: Put some error checking and recovory here } CreateDevice( hWnd, pGuid ); // TODO: Put some error checking and recovory here CreateDepthBuffer( hWnd, pGuid ); // TODO: Put some error checking and recovory here}void CVideoInitTerm::Term(){ DestroyDepthBuffer(); DestroyDevice(); DestroyBuffers(); DestroyInterfaces();}//////////////////////////////////////////////////////////////////////// DirectX Create / DestroyHRESULT CVideoInitTerm::CreateInterfaces( HWND hWnd ){ HRESULT hr = S_OK;; hr = DirectDrawCreateEx(NULL,(VOID**)&m_pDraw,IID_IDirectDraw7,NULL); CHK_DD_RESULT( hr ); hr = m_pDraw->QueryInterface(IID_IDirect3D7, (VOID**)&m_p3D); CHK_DD_RESULT( hr ); hr = m_pDraw->SetCooperativeLevel(hWnd,DDSCL_NORMAL); CHK_DD_RESULT( hr ); return hr;}HRESULT CVideoInitTerm::DestroyInterfaces(){ HRESULT hr = S_OK; SAFE_RELEASE( m_p3D ); SAFE_RELEASE( m_pDraw ); return hr;}// . . .
You may notice my handling of OnSetFocus() and OnKillFocus(). I was writing a 3D editor application with a Multi-Doc interface (MDI) and 4 viewports in each MDI Child Frame. The 4 viewports were four instances of my CDirect3DView derived class, separated by a static CSplitterWnd. The WS_EX_STATICEDGE window style was used to indicate which viewport was active (similar to 3D studio max).
And No, you can't just use any of MFC's m_hWnds, you should use your CView::m_hWnd.
I'm pretty sure the DX documentation says don't use an hWnd from a dialog box. I think once I tried using a CFormView::m_hWnd to init D3D and it didn't work.
Edited by - Marsupial Rodentia on December 18, 2000 11:33:59 PM
And No, you can't just use any of MFC's m_hWnds, you should use your CView::m_hWnd.
I'm pretty sure the DX documentation says don't use an hWnd from a dialog box. I think once I tried using a CFormView::m_hWnd to init D3D and it didn't work.
Edited by - Marsupial Rodentia on December 18, 2000 11:33:59 PM
I''ve init''ed D3D7 off a CDialog''s getsafehwnd(), it worked fine and consumed the whole dialog...
I was thinking about using MDI for some tools...
Magmai Kai Holmlor
- The disgruntled & disillusioned
I was thinking about using MDI for some tools...
Magmai Kai Holmlor
- The disgruntled & disillusioned
- The trade-off between price and quality does not exist in Japan. Rather, the idea that high quality brings on cost reduction is widely accepted.-- Tajima & Matsubara
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement
Recommended Tutorials
Advertisement