Advertisement

MFC and DirectDraw

Started by December 17, 2000 11:54 PM
8 comments, last by KahoyTheSlasher 24 years ago
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.
Advertisement
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.
- 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.

          // 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
Advertisement
I think you can use any ole'' hwnd for a full screen app. (GetSafeHwnd)



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
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
- 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