1 //-----------------------------------------------------------------------------
2 // File: D3DFrame.cpp
3 //
4 // Desc: Class to manage the Direct3D environment objects such as buffers,
5 //       viewports, and 3D devices.
6 //
7 //       The class is initialized with the Initialize() function, after which
8 //       the Get????() functions can be used to access the objects needed for
9 //       rendering. If the device or display needs to be changed, the
10 //       ChangeDevice() function can be called. If the display window is moved
11 //       the changes need to be reported with the Move() function.
12 //
13 //       After rendering a frame, the ShowFrame() function filps or blits the
14 //       backbuffer contents to the primary. If surfaces are lost, they can be
15 //       restored with the RestoreSurfaces() function. Finally, if normal
16 //       Windows output is needed, the FlipToGDISurface() provides a GDI
17 //       surface to draw on.
18 //
19 //
20 // Copyright (c) 1995-1998 by Microsoft, all rights reserved
21 //-----------------------------------------------------------------------------
22 
23 #include <windows.h>
24 #include "D3DFrame.h"
25 #include "D3DUtil.h"
26 
27 
28 
29 
30 //-----------------------------------------------------------------------------
31 // Name: EnumZBufferFormatsCallback()
32 // Desc: Enumeration function to report valid pixel formats for z-buffers.
33 //-----------------------------------------------------------------------------
EnumZBufferFormatsCallback(DDPIXELFORMAT * pddpf,VOID * pddpfDesired)34 static HRESULT WINAPI EnumZBufferFormatsCallback( DDPIXELFORMAT* pddpf,
35                                                   VOID* pddpfDesired )
36 {
37     if( NULL==pddpf || NULL==pddpfDesired )
38         return D3DENUMRET_CANCEL;
39 
40     // If the current pixel format's match the desired ones (DDPF_ZBUFFER and
41     // possibly DDPF_STENCILBUFFER), lets copy it and return. This function is
42     // not choosy...it accepts the first valid format that comes along.
43     if( pddpf->dwFlags == ((DDPIXELFORMAT*)pddpfDesired)->dwFlags )
44     {
45         memcpy( pddpfDesired, pddpf, sizeof(DDPIXELFORMAT) );
46 
47 		// We're happy with a 16-bit z-buffer. Otherwise, keep looking.
48 		if( pddpf->dwZBufferBitDepth == 16 )
49 			return D3DENUMRET_CANCEL;
50     }
51 
52     return D3DENUMRET_OK;
53 }
54 
55 
56 
57 
58 //-----------------------------------------------------------------------------
59 // Name: CD3DFramework()
60 // Desc: The constructor. Clears static variables
61 //-----------------------------------------------------------------------------
CD3DFramework()62 CD3DFramework::CD3DFramework()
63 {
64      m_hWnd             = NULL;
65      m_bIsFullscreen    = FALSE;
66      m_dwRenderWidth    = 0L;
67      m_dwRenderHeight   = 0L;
68      m_pddsFrontBuffer  = NULL;
69      m_pddsBackBuffer   = NULL;
70      m_pddsRenderTarget = NULL;
71      m_pddsZBuffer      = NULL;
72      m_pd3dDevice       = NULL;
73      m_pvViewport       = NULL;
74      m_pDD              = NULL;
75      m_pD3D             = NULL;
76      m_dwDeviceMemType  = NULL;
77 }
78 
79 
80 
81 
82 //-----------------------------------------------------------------------------
83 // Name: ~CD3DFramework()
84 // Desc: The destructor. Deletes all objects
85 //-----------------------------------------------------------------------------
~CD3DFramework()86 CD3DFramework::~CD3DFramework()
87 {
88     DestroyObjects();
89 }
90 
91 
92 
93 
94 //-----------------------------------------------------------------------------
95 // Name: DestroyObjects()
96 // Desc: Cleans everything up upon deletion. This code returns an error
97 //       if any of the objects have remaining reference counts.
98 //-----------------------------------------------------------------------------
DestroyObjects()99 HRESULT CD3DFramework::DestroyObjects()
100 {
101     LONG nDD  = 0L; // Number of outstanding DDraw references
102     LONG nD3D = 0L; // Number of outstanding D3DDevice references
103 
104     SAFE_RELEASE( m_pvViewport );
105 
106     // Do a safe check for releasing the D3DDEVICE. RefCount must be zero.
107     if( m_pd3dDevice )
108         if( 0 < ( nD3D = m_pd3dDevice->Release() ) )
109             DEBUG_MSG( TEXT("Error: D3DDevice object is still referenced!") );
110 	m_pd3dDevice = NULL;
111 
112     // In windowed mode, release the explicity created backbuffer.
113     if( FALSE == m_bIsFullscreen )
114         SAFE_RELEASE( m_pddsBackBuffer );
115     SAFE_RELEASE( m_pddsRenderTarget ); //Note: release before frontbuffer
116     SAFE_RELEASE( m_pddsZBuffer );
117     SAFE_RELEASE( m_pddsFrontBuffer );
118     SAFE_RELEASE( m_pD3D );
119 
120     // Do a safe check for releasing DDRAW. RefCount must be zero.
121     if( m_pDD )
122 	{
123 	    m_pDD->SetCooperativeLevel( m_hWnd, DDSCL_NORMAL );
124 
125         if( 0 < ( nDD = m_pDD->Release() ) )
126             DEBUG_MSG( TEXT("Error: DDraw object is still referenced!") );
127 	}
128 	m_pDD = NULL;
129 
130     // Return successful, unless there are outstanding DD or D3DDevice refs.
131     return ( nDD==0 && nD3D==0 ) ? S_OK : D3DFWERR_NONZEROREFCOUNT;
132 }
133 
134 
135 
136 
137 //-----------------------------------------------------------------------------
138 // Name: Initialize()
139 // Desc: Creates the internal objects for the framework
140 //-----------------------------------------------------------------------------
Initialize(HWND hWnd,GUID * pDriverGUID,GUID * pDeviceGUID,DDSURFACEDESC2 * pMode,DWORD dwFlags)141 HRESULT CD3DFramework::Initialize( HWND hWnd, GUID* pDriverGUID,
142                                    GUID* pDeviceGUID, DDSURFACEDESC2* pMode,
143 								   DWORD dwFlags )
144 {
145 	HRESULT hr;
146 
147     // Check params. A NULL mode is valid for windowed modes only. A NULL
148 	// device GUID is legal for apps that only want 2D support.
149     if( NULL==hWnd || ( NULL==pMode && (dwFlags&D3DFW_FULLSCREEN) ) )
150         return E_INVALIDARG;
151 
152     // Setup state for windowed/fullscreen mode
153     m_hWnd          = hWnd;
154     m_bIsFullscreen = ( dwFlags & D3DFW_FULLSCREEN ) ? TRUE : FALSE;
155 
156     // Create the D3D rendering environment (surfaces, device, viewport, etc.)
157     if( FAILED( hr = CreateEnvironment( pDriverGUID, pDeviceGUID, pMode,
158 		                                dwFlags ) ) )
159 	{
160 		DestroyObjects();
161 		if( E_FAIL == hr )
162 			hr = D3DFWERR_INITIALIZATIONFAILED;
163 	}
164 	return hr;
165 }
166 
167 
168 
169 
170 //-----------------------------------------------------------------------------
171 // Name: CreateEnvironment()
172 // Desc: Creates the internal objects for the framework
173 //-----------------------------------------------------------------------------
CreateEnvironment(GUID * pDriverGUID,GUID * pDeviceGUID,DDSURFACEDESC2 * pMode,DWORD dwFlags)174 HRESULT CD3DFramework::CreateEnvironment( GUID* pDriverGUID, GUID* pDeviceGUID,
175 										  DDSURFACEDESC2* pMode, DWORD dwFlags )
176 {
177     HRESULT hr;
178 
179 	// Create the DDraw object
180 	if( FAILED( hr = CreateDirectDraw( pDriverGUID, dwFlags ) ) )
181 		return hr;
182 
183 	// Create the Direct3D object
184 	if( pDeviceGUID )
185 		if( FAILED( hr = CreateDirect3D( pDeviceGUID, dwFlags ) ) )
186 			return hr;
187 
188 	// Create the front and back buffers, and attach a clipper
189 	if( FAILED( hr = CreateBuffers( pMode, dwFlags ) ) )
190 		return hr;
191 
192 	// If there is no device GUID, then the app only wants 2D, so we're done
193 	if( NULL == pDeviceGUID )
194 		return S_OK;
195 
196 	// Create and attach the zbuffer
197 	if( dwFlags & D3DFW_ZBUFFER )
198 		if( FAILED( hr = CreateZBuffer() ) )
199 			return hr;
200 
201 	// Query the render buffer for the 3ddevice
202 	if( FAILED( hr = Create3DDevice( pDeviceGUID ) ) )
203 		return hr;
204 
205 	// Create and set the viewport
206 	if( FAILED( hr = CreateViewport() ) )
207 		return hr;
208 
209 	return S_OK;
210 }
211 
212 
213 
214 
215 //-----------------------------------------------------------------------------
216 // Name: CreateDirectDraw()
217 // Desc: Create the DirectDraw interface
218 //-----------------------------------------------------------------------------
CreateDirectDraw(GUID * pDriverGUID,DWORD dwFlags)219 HRESULT CD3DFramework::CreateDirectDraw( GUID* pDriverGUID, DWORD dwFlags )
220 {
221     // Create the DirectDraw interface, and query for the DD4 interface
222     LPDIRECTDRAW pDD;
223     if( FAILED( DirectDrawCreate( pDriverGUID, &pDD, NULL ) ) )
224     {
225         DEBUG_MSG( TEXT("Could not create DirectDraw") );
226         return D3DFWERR_NODIRECTDRAW;
227     }
228 
229     if( FAILED( pDD->QueryInterface( IID_IDirectDraw4, (VOID**)&m_pDD ) ) )
230     {
231         pDD->Release();
232         DEBUG_MSG( TEXT("Couldn't query for DirectDraw4") );
233         return D3DFWERR_NODIRECTDRAW;
234     }
235     pDD->Release();
236 
237     // Set the Windows cooperative level
238     DWORD dwCoopFlags = DDSCL_NORMAL;
239     if( m_bIsFullscreen )
240         dwCoopFlags = DDSCL_ALLOWREBOOT|DDSCL_EXCLUSIVE|DDSCL_FULLSCREEN;
241 
242     // By defualt, set the flag to allow D3D to optimize floating point calcs
243     if( 0L == ( dwFlags & D3DFW_NO_FPUSETUP ) )
244         dwCoopFlags |= DDSCL_FPUSETUP;
245 
246     if( FAILED( m_pDD->SetCooperativeLevel( m_hWnd, dwCoopFlags ) ) )
247     {
248         DEBUG_MSG( TEXT("Couldn't set coop level") );
249         return D3DFWERR_COULDNTSETCOOPLEVEL;
250     }
251 
252 	return S_OK;
253 }
254 
255 
256 
257 
258 //-----------------------------------------------------------------------------
259 // Name: CreateDirect3D()
260 // Desc: Create the Direct3D interface
261 //-----------------------------------------------------------------------------
CreateDirect3D(GUID * pDeviceGUID,DWORD dwFlags)262 HRESULT CD3DFramework::CreateDirect3D( GUID* pDeviceGUID, DWORD dwFlags )
263 {
264     // Query DirectDraw for access to Direct3D
265     if( FAILED( m_pDD->QueryInterface( IID_IDirect3D3, (VOID**)&m_pD3D ) ) )
266     {
267         DEBUG_MSG( TEXT("Couldn't query the Direct3D interface") );
268         return D3DFWERR_NODIRECT3D;
269     }
270 
271     // Use the FindDevice() method to test if the requested device
272     // exists, and if so, take note of what memory type it takes.
273     D3DFINDDEVICERESULT  devResult;
274     D3DFINDDEVICESEARCH  devSearch;
275     ZeroMemory( &devResult, sizeof(D3DFINDDEVICERESULT) );
276     ZeroMemory( &devSearch, sizeof(D3DFINDDEVICESEARCH) );
277     devResult.dwSize  = sizeof(D3DFINDDEVICERESULT);
278     devSearch.dwSize  = sizeof(D3DFINDDEVICESEARCH);
279     devSearch.dwFlags = D3DFDS_GUID;
280     CopyMemory( &devSearch.guid, pDeviceGUID, sizeof(GUID) );
281 
282     if( FAILED( m_pD3D->FindDevice( &devSearch, &devResult ) ) )
283     {
284         DEBUG_MSG( TEXT("Couldn't find the specified device") );
285         return D3DFWERR_NODIRECT3D;
286     }
287 
288     // Whether device is SW or HW, get the devicedesc, and the defualt memtype
289     if( 0L == devResult.ddHwDesc.dwFlags )
290     {
291         m_dwDeviceMemType = DDSCAPS_SYSTEMMEMORY;
292         memcpy( &m_ddDeviceDesc, &devResult.ddSwDesc, sizeof(D3DDEVICEDESC) );
293     }
294     else
295     {
296         m_dwDeviceMemType = DDSCAPS_VIDEOMEMORY;
297         memcpy( &m_ddDeviceDesc, &devResult.ddHwDesc, sizeof(D3DDEVICEDESC) );
298     }
299 
300     // Using the device GUID, let's enumerate a format for our z-buffer, in
301     // case we later decide to create one.
302 	ZeroMemory( &m_ddpfZBuffer, sizeof(DDPIXELFORMAT) );
303 
304     if( dwFlags & D3DFW_STENCILBUFFER )
305         m_ddpfZBuffer.dwFlags = DDPF_ZBUFFER | DDPF_STENCILBUFFER;
306     else
307         m_ddpfZBuffer.dwFlags = DDPF_ZBUFFER;
308 
309     // Get an appropiate pixel format from enumeration of the formats.
310     m_pD3D->EnumZBufferFormats( *pDeviceGUID, EnumZBufferFormatsCallback,
311                                 (VOID*)&m_ddpfZBuffer );
312 
313     if( sizeof(DDPIXELFORMAT) != m_ddpfZBuffer.dwSize )
314     {
315         DEBUG_MSG( TEXT("Device doesn't support requested zbuffer format") );
316         return D3DFWERR_NOZBUFFER;
317     }
318 
319     return S_OK;
320 }
321 
322 
323 
324 
325 //-----------------------------------------------------------------------------
326 // Name: CreateBuffers()
327 // Desc: Creates the primary and (optional) backbuffer for rendering.
328 //       Windowed mode and fullscreen mode are handled differently.
329 //-----------------------------------------------------------------------------
CreateBuffers(DDSURFACEDESC2 * pddsd,DWORD dwFlags)330 HRESULT CD3DFramework::CreateBuffers( DDSURFACEDESC2* pddsd, DWORD dwFlags )
331 {
332     HRESULT hr;
333 
334 	if( dwFlags & D3DFW_FULLSCREEN )
335 	{
336 		// Get the dimensions of the viewport and screen bounds
337 		// Store the rectangle which contains the renderer
338 		SetRect( &m_rcViewportRect, 0, 0, pddsd->dwWidth, pddsd->dwHeight );
339 		memcpy( &m_rcScreenRect, &m_rcViewportRect, sizeof(RECT) );
340 		m_dwRenderWidth  = m_rcViewportRect.right;
341 		m_dwRenderHeight = m_rcViewportRect.bottom;
342 
343 		// Set the display mode to the requested dimensions. Check for
344 		// 320x200x8 modes, and set flag to avoid using ModeX
345 		DWORD dwModeFlags = 0;
346 
347 		if( (320==m_dwRenderWidth) && (200==m_dwRenderHeight) &&
348 			(8==pddsd->ddpfPixelFormat.dwRGBBitCount) )
349 			dwModeFlags |= DDSDM_STANDARDVGAMODE;
350 
351 		if( FAILED( m_pDD->SetDisplayMode( m_dwRenderWidth, m_dwRenderHeight,
352 									pddsd->ddpfPixelFormat.dwRGBBitCount,
353 									pddsd->dwRefreshRate, dwModeFlags ) ) )
354 		{
355 			DEBUG_MSG( TEXT("Can't set display mode") );
356 			return D3DFWERR_BADDISPLAYMODE;
357 		}
358 
359 		// Create the primary surface
360 		DDSURFACEDESC2 ddsd;
361 		D3DUtil_InitSurfaceDesc( ddsd, DDSD_CAPS );
362 		ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_3DDEVICE;
363 
364 		// With no backbuffer, the primary becomes the render target
365 		if( dwFlags & D3DFW_BACKBUFFER )
366 		{
367 			ddsd.dwFlags          |= DDSD_BACKBUFFERCOUNT;
368 			ddsd.ddsCaps.dwCaps   |= DDSCAPS_FLIP | DDSCAPS_COMPLEX;
369 			ddsd.dwBackBufferCount = 1;
370 		}
371 
372 		if( FAILED( hr = m_pDD->CreateSurface( &ddsd, &m_pddsFrontBuffer, NULL ) ) )
373 		{
374 			DEBUG_MSG( TEXT("Error: Can't create primary surface") );
375 			if( hr != DDERR_OUTOFVIDEOMEMORY )
376 				return D3DFWERR_NOPRIMARY;
377 			DEBUG_MSG( TEXT("Error: Out of video memory") );
378 			return DDERR_OUTOFVIDEOMEMORY;
379 		}
380 
381 		// Get the backbuffer. For fullscreen mode, the backbuffer was created
382 		// along with the primary, but windowed mode still needs to create one.
383 		if( dwFlags & D3DFW_BACKBUFFER )
384 		{
385 			// Get a ptr to the back buffer, which will be our render target
386 			DDSCAPS2 ddscaps;
387 			ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
388 			if( FAILED( hr = m_pddsFrontBuffer->GetAttachedSurface( &ddscaps,
389 														&m_pddsBackBuffer ) ) )
390 			{
391 				DEBUG_MSG( TEXT("Error: Can't get/create the backbuffer") );
392 				if( hr != DDERR_OUTOFVIDEOMEMORY )
393 					return D3DFWERR_NOBACKBUFFER;
394 				DEBUG_MSG( TEXT("Error: Out of video memory") );
395 				return DDERR_OUTOFVIDEOMEMORY;
396 			}
397 		}
398 	}
399 	else // Set up buffers for windowed rendering
400 	{
401 		// Get the dimensions of the viewport and screen bounds
402 		GetClientRect( m_hWnd, &m_rcViewportRect );
403 		GetClientRect( m_hWnd, &m_rcScreenRect );
404 		ClientToScreen( m_hWnd, (POINT*)&m_rcScreenRect.left );
405 		ClientToScreen( m_hWnd, (POINT*)&m_rcScreenRect.right );
406 		m_dwRenderWidth  = m_rcViewportRect.right;
407 		m_dwRenderHeight = m_rcViewportRect.bottom;
408 
409 		// Create the primary surface
410 		DDSURFACEDESC2 ddsd;
411 		D3DUtil_InitSurfaceDesc( ddsd, DDSD_CAPS );
412 		ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
413 
414 		// With no backbuffer, the primary becomes the render target
415 		if( 0L == ( dwFlags & D3DFW_BACKBUFFER ) )
416 			ddsd.ddsCaps.dwCaps |= DDSCAPS_3DDEVICE;
417 
418 		if( FAILED( hr = m_pDD->CreateSurface( &ddsd, &m_pddsFrontBuffer, NULL ) ) )
419 		{
420 			DEBUG_MSG( TEXT("Error: Can't create primary surface") );
421 			if( hr != DDERR_OUTOFVIDEOMEMORY )
422 				return D3DFWERR_NOPRIMARY;
423 			DEBUG_MSG( TEXT("Error: Out of video memory") );
424 			return DDERR_OUTOFVIDEOMEMORY;
425 		}
426 
427 		// If in windowed-mode, create a clipper object
428 		LPDIRECTDRAWCLIPPER pcClipper;
429 		if( FAILED( hr = m_pDD->CreateClipper( 0, &pcClipper, NULL ) ) )
430 		{
431 			DEBUG_MSG( TEXT("Error: Couldn't create clipper") );
432 			return D3DFWERR_NOCLIPPER;
433 		}
434 
435 		// Associate the clipper with the window
436 		pcClipper->SetHWnd( 0, m_hWnd );
437 		m_pddsFrontBuffer->SetClipper( pcClipper );
438 		SAFE_RELEASE( pcClipper );
439 
440 		// Get the backbuffer. For fullscreen mode, the backbuffer was created
441 		// along with the primary, but windowed mode still needs to create one.
442 		if( dwFlags & D3DFW_BACKBUFFER )
443 		{
444 			// Create the back buffer (the render target)
445 			ddsd.dwFlags        = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS;
446 			ddsd.dwWidth        = m_dwRenderWidth;
447 			ddsd.dwHeight       = m_dwRenderHeight;
448 			ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE;
449 
450 			if( FAILED( hr = m_pDD->CreateSurface( &ddsd, &m_pddsBackBuffer, NULL ) ) )
451 			{
452 				DEBUG_MSG( TEXT("Error: Couldn't create the backbuffer") );
453 				if( hr != DDERR_OUTOFVIDEOMEMORY )
454 					return D3DFWERR_NOBACKBUFFER;
455 				DEBUG_MSG( TEXT("Error: Out of video memory") );
456 				return DDERR_OUTOFVIDEOMEMORY;
457 			}
458 		}
459 		else // For rendering without a backbuffer
460 		{
461 			ClientToScreen( m_hWnd, (POINT*)&m_rcViewportRect.left );
462 			ClientToScreen( m_hWnd, (POINT*)&m_rcViewportRect.right );
463 		}
464 	}
465 
466 	// Set up backbuffer ptr and ref counts
467 	if( dwFlags & D3DFW_BACKBUFFER )
468 		m_pddsRenderTarget = m_pddsBackBuffer;
469 	else
470 		m_pddsRenderTarget = m_pddsFrontBuffer;
471 	m_pddsRenderTarget->AddRef();
472 
473     return S_OK;
474 }
475 
476 
477 
478 
479 //-----------------------------------------------------------------------------
480 // Name: CreateZBuffer()
481 // Desc: Internal function called by Create() to make and attach a zbuffer
482 //       to the renderer
483 //-----------------------------------------------------------------------------
CreateZBuffer()484 HRESULT CD3DFramework::CreateZBuffer()
485 {
486 	HRESULT hr;
487 
488     // Check if the device supports z-bufferless hidden surface removal. If so,
489     // we don't really need a z-buffer
490     DWORD dwRasterCaps = m_ddDeviceDesc.dpcTriCaps.dwRasterCaps;
491     if( dwRasterCaps & D3DPRASTERCAPS_ZBUFFERLESSHSR )
492         return S_OK;
493 
494     // Get z-buffer dimensions from the render target
495     // Setup the surface desc for the z-buffer.
496     DDSURFACEDESC2 ddsd;
497     D3DUtil_InitSurfaceDesc( ddsd, DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS |
498                              DDSD_PIXELFORMAT );
499     ddsd.ddsCaps.dwCaps = DDSCAPS_ZBUFFER | m_dwDeviceMemType;
500     ddsd.dwWidth        = m_dwRenderWidth;
501     ddsd.dwHeight       = m_dwRenderHeight;
502     memcpy( &ddsd.ddpfPixelFormat, &m_ddpfZBuffer, sizeof(DDPIXELFORMAT) );
503 
504     // Create and attach a z-buffer
505     if( FAILED( hr = m_pDD->CreateSurface( &ddsd, &m_pddsZBuffer, NULL ) ) )
506     {
507         DEBUG_MSG( TEXT("Error: Couldn't create a ZBuffer surface") );
508 		if( hr != DDERR_OUTOFVIDEOMEMORY )
509 			return D3DFWERR_NOZBUFFER;
510 		DEBUG_MSG( TEXT("Error: Out of video memory") );
511 		return DDERR_OUTOFVIDEOMEMORY;
512     }
513 
514     if( FAILED( m_pddsRenderTarget->AddAttachedSurface( m_pddsZBuffer ) ) )
515     {
516         DEBUG_MSG( TEXT("Error: Couldn't attach zbuffer to render surface") );
517         return D3DFWERR_NOZBUFFER;
518     }
519 
520     return S_OK;
521 }
522 
523 
524 
525 
526 //-----------------------------------------------------------------------------
527 // Name: Create3DDevice()
528 // Desc: Creates the 3D device for the render target
529 //-----------------------------------------------------------------------------
Create3DDevice(GUID * pDeviceGUID)530 HRESULT CD3DFramework::Create3DDevice( GUID* pDeviceGUID )
531 {
532 	// Check that we are NOT in a palettized display. That case will fail,
533 	// since the framework doesn't use palettes.
534 	DDSURFACEDESC2 ddsd;
535 	ddsd.dwSize = sizeof(DDSURFACEDESC2);
536 	m_pDD->GetDisplayMode( &ddsd );
537 	if( ddsd.ddpfPixelFormat.dwRGBBitCount <= 8 )
538 		return D3DFWERR_INVALIDMODE;
539 
540 	// Create the device
541     if( FAILED( m_pD3D->CreateDevice( *pDeviceGUID, m_pddsRenderTarget,
542                                       &m_pd3dDevice, NULL ) ) )
543     {
544         DEBUG_MSG( TEXT("Couldn't create the D3DDevice") );
545         return D3DFWERR_NO3DDEVICE;
546     }
547 
548     return S_OK;
549 }
550 
551 
552 
553 
554 //-----------------------------------------------------------------------------
555 // Name: CreateViewport()
556 // Desc: Create the D3D viewport used by the renderer.
557 //-----------------------------------------------------------------------------
CreateViewport()558 HRESULT CD3DFramework::CreateViewport()
559 {
560     // Set up the viewport data parameters
561     HRESULT      hr;
562     D3DVIEWPORT2 vdData;
563     D3DUtil_InitViewport( vdData, m_dwRenderWidth, m_dwRenderHeight );
564 
565     // Create the viewport
566     if( FAILED( m_pD3D->CreateViewport( &m_pvViewport, NULL ) ) )
567     {
568         DEBUG_MSG( TEXT("Error: Couldn't create a viewport") );
569         return D3DFWERR_NOVIEWPORT;
570     }
571 
572     // Associate the viewport with the D3DDEVICE object
573     if( FAILED( hr = m_pd3dDevice->AddViewport( m_pvViewport ) ) )
574     {
575         DEBUG_MSG( TEXT("Error: Couldn't add the viewport") );
576         return D3DFWERR_NOVIEWPORT;
577     }
578 
579     // Set the parameters to the new viewport
580     if( FAILED( m_pvViewport->SetViewport2( &vdData ) ) )
581     {
582         DEBUG_MSG( TEXT("Error: Couldn't set the viewport data") );
583         return D3DFWERR_NOVIEWPORT;
584     }
585 
586     // Finally, set the current viewport for the current device
587     if( FAILED( m_pd3dDevice->SetCurrentViewport( m_pvViewport ) ) )
588     {
589         DEBUG_MSG( TEXT("Error: Couldn't set current viewport to device") );
590         return D3DFWERR_NOVIEWPORT;
591     }
592 
593     return S_OK;
594 }
595 
596 
597 
598 
599 //-----------------------------------------------------------------------------
600 // Name: ShowFrame()
601 // Desc: Show the frame on the primary surface, via a blt or a flip.
602 //-----------------------------------------------------------------------------
ShowFrame()603 HRESULT CD3DFramework::ShowFrame()
604 {
605 	if( NULL == m_pddsFrontBuffer )
606 		return D3DFWERR_NOTINITIALIZED;
607 
608     // Check for a backbuffer. If no backbuffer exists, then we have nothing to
609     // do. However, to be consistent let's check for lost surfaces
610     if( NULL == m_pddsBackBuffer )
611         return m_pddsFrontBuffer->IsLost();
612 
613     // If we are in fullscreen mode perform a flip.
614     if( m_bIsFullscreen )
615         return m_pddsFrontBuffer->Flip( NULL, DDFLIP_WAIT );
616 
617     // Else, we are in windowed mode, so perform a blit.
618     return m_pddsFrontBuffer->Blt( &m_rcScreenRect, m_pddsBackBuffer,
619                                    &m_rcViewportRect, DDBLT_WAIT, NULL );
620 }
621 
622 
623 
624 
625 //-----------------------------------------------------------------------------
626 // Name: FlipToGDISurface()
627 // Desc: Puts the GDI surface in front of the primary, so that dialog
628 //       boxes and other windows drawing funcs may happen.
629 //-----------------------------------------------------------------------------
FlipToGDISurface(BOOL bDrawFrame)630 HRESULT CD3DFramework::FlipToGDISurface( BOOL bDrawFrame )
631 {
632     if( m_pDD && m_bIsFullscreen )
633     {
634         m_pDD->FlipToGDISurface();
635 
636         if( bDrawFrame )
637         {
638             DrawMenuBar( m_hWnd );
639             RedrawWindow( m_hWnd, NULL, NULL, RDW_FRAME );
640         }
641     }
642 
643     return S_OK;
644 }
645 
646 
647 
648 
649 //-----------------------------------------------------------------------------
650 // Name: RestoreSurfaces()
651 // Desc: Checks for lost surfaces and restores them if lost. Note: Don't
652 //       restore render surface, since it's just a duplicate ptr.
653 //-----------------------------------------------------------------------------
RestoreSurfaces()654 HRESULT CD3DFramework::RestoreSurfaces()
655 {
656     // Check/restore the primary surface
657     if( m_pddsFrontBuffer )
658         if( m_pddsFrontBuffer->IsLost() )
659             m_pddsFrontBuffer->Restore();
660 
661     // Check/restore the back buffer
662     if( m_pddsBackBuffer )
663         if( m_pddsBackBuffer->IsLost() )
664             m_pddsBackBuffer->Restore();
665 
666     // Check/restore the z-buffer surface
667     if( m_pddsZBuffer )
668         if( m_pddsZBuffer->IsLost() )
669             m_pddsZBuffer->Restore();
670 
671     return S_OK;
672 }
673 
674 
675 
676 
677 //-----------------------------------------------------------------------------
678 // Name: Move()
679 // Desc: Moves the screen rect for windowed renderers
680 //-----------------------------------------------------------------------------
Move(INT x,INT y)681 VOID CD3DFramework::Move( INT x, INT y )
682 {
683     if( FALSE == m_bIsFullscreen )
684     {
685         SetRect( &m_rcScreenRect, x, y,
686 			     x + m_dwRenderWidth, y + m_dwRenderHeight );
687 
688 		// If we have no backbuffer, then update viewport rect as well
689 		if( NULL == m_pddsBackBuffer )
690 			CopyMemory( &m_rcViewportRect, &m_rcScreenRect, sizeof(RECT) );
691     }
692 }
693 
694 
695 
696 
697 //-----------------------------------------------------------------------------
698 // Name: ChangeRenderTarget()
699 // Desc: Wrapper for the IDirect3DDevice::SetRenderTarget() function, which
700 //       adds functionality to handle an attached z-buffer. Note that this
701 //       function does NOT alter the current viewport
702 //-----------------------------------------------------------------------------
ChangeRenderTarget(LPDIRECTDRAWSURFACE4 pddsNewTarget)703 HRESULT CD3DFramework::ChangeRenderTarget( LPDIRECTDRAWSURFACE4 pddsNewTarget )
704 {
705     if( NULL == pddsNewTarget )
706         return E_INVALIDARG;
707 
708     // Get the new render target dimensions
709     DDSURFACEDESC2 ddsd;
710     D3DUtil_InitSurfaceDesc( ddsd );
711     pddsNewTarget->GetSurfaceDesc( &ddsd );
712     m_dwRenderWidth  = ddsd.dwWidth;
713     m_dwRenderHeight = ddsd.dwHeight;
714 
715     // If a z-buffer is attached, delete and recreate it
716     if( NULL != m_pddsZBuffer )
717     {
718         // Remove the old z-buffer
719         m_pddsRenderTarget->DeleteAttachedSurface( 0, m_pddsZBuffer );
720         SAFE_RELEASE( m_pddsZBuffer );
721 
722         // Keep track of reference counts
723         SAFE_RELEASE( m_pddsRenderTarget );
724         m_pddsRenderTarget = pddsNewTarget;
725         m_pddsRenderTarget->AddRef();
726 
727         // Create the new z-buffer
728         if( FAILED( CreateZBuffer() ) )
729         {
730             DEBUG_MSG( TEXT("ChangeRenderTarget() - zbuffer create failed") );
731             return D3DFWERR_NOZBUFFER;
732         }
733     }
734     else
735     {
736         // With no z-buffer, we just do accounting on the reference counts
737         SAFE_RELEASE( m_pddsRenderTarget );
738         m_pddsRenderTarget = pddsNewTarget;
739         m_pddsRenderTarget->AddRef();
740     }
741 
742     // Finally, perform the set render target call
743     if( FAILED( m_pd3dDevice->SetRenderTarget( m_pddsRenderTarget, 0 ) ) )
744     {
745         return D3DFWERR_NORENDERTARGET;
746     }
747 
748     return S_OK;
749 }
750 
751 
752 
753 
754 
755