//----------------------------------------------------------------------------- // File: D3DFrame.cpp // // Desc: Class to manage the Direct3D environment objects such as buffers, // viewports, and 3D devices. // // The class is initialized with the Initialize() function, after which // the Get????() functions can be used to access the objects needed for // rendering. If the device or display needs to be changed, the // ChangeDevice() function can be called. If the display window is moved // the changes need to be reported with the Move() function. // // After rendering a frame, the ShowFrame() function filps or blits the // backbuffer contents to the primary. If surfaces are lost, they can be // restored with the RestoreSurfaces() function. Finally, if normal // Windows output is needed, the FlipToGDISurface() provides a GDI // surface to draw on. // // // Copyright (c) 1995-1998 by Microsoft, all rights reserved //----------------------------------------------------------------------------- #include #include "D3DFrame.h" #include "D3DUtil.h" //----------------------------------------------------------------------------- // Name: EnumZBufferFormatsCallback() // Desc: Enumeration function to report valid pixel formats for z-buffers. //----------------------------------------------------------------------------- static HRESULT WINAPI EnumZBufferFormatsCallback( DDPIXELFORMAT* pddpf, VOID* pddpfDesired ) { if( NULL==pddpf || NULL==pddpfDesired ) return D3DENUMRET_CANCEL; // If the current pixel format's match the desired ones (DDPF_ZBUFFER and // possibly DDPF_STENCILBUFFER), lets copy it and return. This function is // not choosy...it accepts the first valid format that comes along. if( pddpf->dwFlags == ((DDPIXELFORMAT*)pddpfDesired)->dwFlags ) { memcpy( pddpfDesired, pddpf, sizeof(DDPIXELFORMAT) ); // We're happy with a 16-bit z-buffer. Otherwise, keep looking. if( pddpf->dwZBufferBitDepth == 16 ) return D3DENUMRET_CANCEL; } return D3DENUMRET_OK; } //----------------------------------------------------------------------------- // Name: CD3DFramework() // Desc: The constructor. Clears static variables //----------------------------------------------------------------------------- CD3DFramework::CD3DFramework() { m_hWnd = NULL; m_bIsFullscreen = FALSE; m_dwRenderWidth = 0L; m_dwRenderHeight = 0L; m_pddsFrontBuffer = NULL; m_pddsBackBuffer = NULL; m_pddsRenderTarget = NULL; m_pddsZBuffer = NULL; m_pd3dDevice = NULL; m_pvViewport = NULL; m_pDD = NULL; m_pD3D = NULL; m_dwDeviceMemType = NULL; } //----------------------------------------------------------------------------- // Name: ~CD3DFramework() // Desc: The destructor. Deletes all objects //----------------------------------------------------------------------------- CD3DFramework::~CD3DFramework() { DestroyObjects(); } //----------------------------------------------------------------------------- // Name: DestroyObjects() // Desc: Cleans everything up upon deletion. This code returns an error // if any of the objects have remaining reference counts. //----------------------------------------------------------------------------- HRESULT CD3DFramework::DestroyObjects() { LONG nDD = 0L; // Number of outstanding DDraw references LONG nD3D = 0L; // Number of outstanding D3DDevice references SAFE_RELEASE( m_pvViewport ); // Do a safe check for releasing the D3DDEVICE. RefCount must be zero. if( m_pd3dDevice ) if( 0 < ( nD3D = m_pd3dDevice->Release() ) ) DEBUG_MSG( TEXT("Error: D3DDevice object is still referenced!") ); m_pd3dDevice = NULL; // In windowed mode, release the explicity created backbuffer. if( FALSE == m_bIsFullscreen ) SAFE_RELEASE( m_pddsBackBuffer ); SAFE_RELEASE( m_pddsRenderTarget ); //Note: release before frontbuffer SAFE_RELEASE( m_pddsZBuffer ); SAFE_RELEASE( m_pddsFrontBuffer ); SAFE_RELEASE( m_pD3D ); // Do a safe check for releasing DDRAW. RefCount must be zero. if( m_pDD ) { m_pDD->SetCooperativeLevel( m_hWnd, DDSCL_NORMAL ); if( 0 < ( nDD = m_pDD->Release() ) ) DEBUG_MSG( TEXT("Error: DDraw object is still referenced!") ); } m_pDD = NULL; // Return successful, unless there are outstanding DD or D3DDevice refs. return ( nDD==0 && nD3D==0 ) ? S_OK : D3DFWERR_NONZEROREFCOUNT; } //----------------------------------------------------------------------------- // Name: Initialize() // Desc: Creates the internal objects for the framework //----------------------------------------------------------------------------- HRESULT CD3DFramework::Initialize( HWND hWnd, GUID* pDriverGUID, GUID* pDeviceGUID, DDSURFACEDESC2* pMode, DWORD dwFlags ) { HRESULT hr; // Check params. A NULL mode is valid for windowed modes only. A NULL // device GUID is legal for apps that only want 2D support. if( NULL==hWnd || ( NULL==pMode && (dwFlags&D3DFW_FULLSCREEN) ) ) return E_INVALIDARG; // Setup state for windowed/fullscreen mode m_hWnd = hWnd; m_bIsFullscreen = ( dwFlags & D3DFW_FULLSCREEN ) ? TRUE : FALSE; // Create the D3D rendering environment (surfaces, device, viewport, etc.) if( FAILED( hr = CreateEnvironment( pDriverGUID, pDeviceGUID, pMode, dwFlags ) ) ) { DestroyObjects(); if( E_FAIL == hr ) hr = D3DFWERR_INITIALIZATIONFAILED; } return hr; } //----------------------------------------------------------------------------- // Name: CreateEnvironment() // Desc: Creates the internal objects for the framework //----------------------------------------------------------------------------- HRESULT CD3DFramework::CreateEnvironment( GUID* pDriverGUID, GUID* pDeviceGUID, DDSURFACEDESC2* pMode, DWORD dwFlags ) { HRESULT hr; // Create the DDraw object if( FAILED( hr = CreateDirectDraw( pDriverGUID, dwFlags ) ) ) return hr; // Create the Direct3D object if( pDeviceGUID ) if( FAILED( hr = CreateDirect3D( pDeviceGUID, dwFlags ) ) ) return hr; // Create the front and back buffers, and attach a clipper if( FAILED( hr = CreateBuffers( pMode, dwFlags ) ) ) return hr; // If there is no device GUID, then the app only wants 2D, so we're done if( NULL == pDeviceGUID ) return S_OK; // Create and attach the zbuffer if( dwFlags & D3DFW_ZBUFFER ) if( FAILED( hr = CreateZBuffer() ) ) return hr; // Query the render buffer for the 3ddevice if( FAILED( hr = Create3DDevice( pDeviceGUID ) ) ) return hr; // Create and set the viewport if( FAILED( hr = CreateViewport() ) ) return hr; return S_OK; } //----------------------------------------------------------------------------- // Name: CreateDirectDraw() // Desc: Create the DirectDraw interface //----------------------------------------------------------------------------- HRESULT CD3DFramework::CreateDirectDraw( GUID* pDriverGUID, DWORD dwFlags ) { // Create the DirectDraw interface, and query for the DD4 interface LPDIRECTDRAW pDD; if( FAILED( DirectDrawCreate( pDriverGUID, &pDD, NULL ) ) ) { DEBUG_MSG( TEXT("Could not create DirectDraw") ); return D3DFWERR_NODIRECTDRAW; } if( FAILED( pDD->QueryInterface( IID_IDirectDraw4, (VOID**)&m_pDD ) ) ) { pDD->Release(); DEBUG_MSG( TEXT("Couldn't query for DirectDraw4") ); return D3DFWERR_NODIRECTDRAW; } pDD->Release(); // Set the Windows cooperative level DWORD dwCoopFlags = DDSCL_NORMAL; if( m_bIsFullscreen ) dwCoopFlags = DDSCL_ALLOWREBOOT|DDSCL_EXCLUSIVE|DDSCL_FULLSCREEN; // By defualt, set the flag to allow D3D to optimize floating point calcs if( 0L == ( dwFlags & D3DFW_NO_FPUSETUP ) ) dwCoopFlags |= DDSCL_FPUSETUP; if( FAILED( m_pDD->SetCooperativeLevel( m_hWnd, dwCoopFlags ) ) ) { DEBUG_MSG( TEXT("Couldn't set coop level") ); return D3DFWERR_COULDNTSETCOOPLEVEL; } return S_OK; } //----------------------------------------------------------------------------- // Name: CreateDirect3D() // Desc: Create the Direct3D interface //----------------------------------------------------------------------------- HRESULT CD3DFramework::CreateDirect3D( GUID* pDeviceGUID, DWORD dwFlags ) { // Query DirectDraw for access to Direct3D if( FAILED( m_pDD->QueryInterface( IID_IDirect3D3, (VOID**)&m_pD3D ) ) ) { DEBUG_MSG( TEXT("Couldn't query the Direct3D interface") ); return D3DFWERR_NODIRECT3D; } // Use the FindDevice() method to test if the requested device // exists, and if so, take note of what memory type it takes. D3DFINDDEVICERESULT devResult; D3DFINDDEVICESEARCH devSearch; ZeroMemory( &devResult, sizeof(D3DFINDDEVICERESULT) ); ZeroMemory( &devSearch, sizeof(D3DFINDDEVICESEARCH) ); devResult.dwSize = sizeof(D3DFINDDEVICERESULT); devSearch.dwSize = sizeof(D3DFINDDEVICESEARCH); devSearch.dwFlags = D3DFDS_GUID; CopyMemory( &devSearch.guid, pDeviceGUID, sizeof(GUID) ); if( FAILED( m_pD3D->FindDevice( &devSearch, &devResult ) ) ) { DEBUG_MSG( TEXT("Couldn't find the specified device") ); return D3DFWERR_NODIRECT3D; } // Whether device is SW or HW, get the devicedesc, and the defualt memtype if( 0L == devResult.ddHwDesc.dwFlags ) { m_dwDeviceMemType = DDSCAPS_SYSTEMMEMORY; memcpy( &m_ddDeviceDesc, &devResult.ddSwDesc, sizeof(D3DDEVICEDESC) ); } else { m_dwDeviceMemType = DDSCAPS_VIDEOMEMORY; memcpy( &m_ddDeviceDesc, &devResult.ddHwDesc, sizeof(D3DDEVICEDESC) ); } // Using the device GUID, let's enumerate a format for our z-buffer, in // case we later decide to create one. ZeroMemory( &m_ddpfZBuffer, sizeof(DDPIXELFORMAT) ); if( dwFlags & D3DFW_STENCILBUFFER ) m_ddpfZBuffer.dwFlags = DDPF_ZBUFFER | DDPF_STENCILBUFFER; else m_ddpfZBuffer.dwFlags = DDPF_ZBUFFER; // Get an appropiate pixel format from enumeration of the formats. m_pD3D->EnumZBufferFormats( *pDeviceGUID, EnumZBufferFormatsCallback, (VOID*)&m_ddpfZBuffer ); if( sizeof(DDPIXELFORMAT) != m_ddpfZBuffer.dwSize ) { DEBUG_MSG( TEXT("Device doesn't support requested zbuffer format") ); return D3DFWERR_NOZBUFFER; } return S_OK; } //----------------------------------------------------------------------------- // Name: CreateBuffers() // Desc: Creates the primary and (optional) backbuffer for rendering. // Windowed mode and fullscreen mode are handled differently. //----------------------------------------------------------------------------- HRESULT CD3DFramework::CreateBuffers( DDSURFACEDESC2* pddsd, DWORD dwFlags ) { HRESULT hr; if( dwFlags & D3DFW_FULLSCREEN ) { // Get the dimensions of the viewport and screen bounds // Store the rectangle which contains the renderer SetRect( &m_rcViewportRect, 0, 0, pddsd->dwWidth, pddsd->dwHeight ); memcpy( &m_rcScreenRect, &m_rcViewportRect, sizeof(RECT) ); m_dwRenderWidth = m_rcViewportRect.right; m_dwRenderHeight = m_rcViewportRect.bottom; // Set the display mode to the requested dimensions. Check for // 320x200x8 modes, and set flag to avoid using ModeX DWORD dwModeFlags = 0; if( (320==m_dwRenderWidth) && (200==m_dwRenderHeight) && (8==pddsd->ddpfPixelFormat.dwRGBBitCount) ) dwModeFlags |= DDSDM_STANDARDVGAMODE; if( FAILED( m_pDD->SetDisplayMode( m_dwRenderWidth, m_dwRenderHeight, pddsd->ddpfPixelFormat.dwRGBBitCount, pddsd->dwRefreshRate, dwModeFlags ) ) ) { DEBUG_MSG( TEXT("Can't set display mode") ); return D3DFWERR_BADDISPLAYMODE; } // Create the primary surface DDSURFACEDESC2 ddsd; D3DUtil_InitSurfaceDesc( ddsd, DDSD_CAPS ); ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_3DDEVICE; // With no backbuffer, the primary becomes the render target if( dwFlags & D3DFW_BACKBUFFER ) { ddsd.dwFlags |= DDSD_BACKBUFFERCOUNT; ddsd.ddsCaps.dwCaps |= DDSCAPS_FLIP | DDSCAPS_COMPLEX; ddsd.dwBackBufferCount = 1; } if( FAILED( hr = m_pDD->CreateSurface( &ddsd, &m_pddsFrontBuffer, NULL ) ) ) { DEBUG_MSG( TEXT("Error: Can't create primary surface") ); if( hr != DDERR_OUTOFVIDEOMEMORY ) return D3DFWERR_NOPRIMARY; DEBUG_MSG( TEXT("Error: Out of video memory") ); return DDERR_OUTOFVIDEOMEMORY; } // Get the backbuffer. For fullscreen mode, the backbuffer was created // along with the primary, but windowed mode still needs to create one. if( dwFlags & D3DFW_BACKBUFFER ) { // Get a ptr to the back buffer, which will be our render target DDSCAPS2 ddscaps; ddscaps.dwCaps = DDSCAPS_BACKBUFFER; if( FAILED( hr = m_pddsFrontBuffer->GetAttachedSurface( &ddscaps, &m_pddsBackBuffer ) ) ) { DEBUG_MSG( TEXT("Error: Can't get/create the backbuffer") ); if( hr != DDERR_OUTOFVIDEOMEMORY ) return D3DFWERR_NOBACKBUFFER; DEBUG_MSG( TEXT("Error: Out of video memory") ); return DDERR_OUTOFVIDEOMEMORY; } } } else // Set up buffers for windowed rendering { // Get the dimensions of the viewport and screen bounds GetClientRect( m_hWnd, &m_rcViewportRect ); GetClientRect( m_hWnd, &m_rcScreenRect ); ClientToScreen( m_hWnd, (POINT*)&m_rcScreenRect.left ); ClientToScreen( m_hWnd, (POINT*)&m_rcScreenRect.right ); m_dwRenderWidth = m_rcViewportRect.right; m_dwRenderHeight = m_rcViewportRect.bottom; // Create the primary surface DDSURFACEDESC2 ddsd; D3DUtil_InitSurfaceDesc( ddsd, DDSD_CAPS ); ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; // With no backbuffer, the primary becomes the render target if( 0L == ( dwFlags & D3DFW_BACKBUFFER ) ) ddsd.ddsCaps.dwCaps |= DDSCAPS_3DDEVICE; if( FAILED( hr = m_pDD->CreateSurface( &ddsd, &m_pddsFrontBuffer, NULL ) ) ) { DEBUG_MSG( TEXT("Error: Can't create primary surface") ); if( hr != DDERR_OUTOFVIDEOMEMORY ) return D3DFWERR_NOPRIMARY; DEBUG_MSG( TEXT("Error: Out of video memory") ); return DDERR_OUTOFVIDEOMEMORY; } // If in windowed-mode, create a clipper object LPDIRECTDRAWCLIPPER pcClipper; if( FAILED( hr = m_pDD->CreateClipper( 0, &pcClipper, NULL ) ) ) { DEBUG_MSG( TEXT("Error: Couldn't create clipper") ); return D3DFWERR_NOCLIPPER; } // Associate the clipper with the window pcClipper->SetHWnd( 0, m_hWnd ); m_pddsFrontBuffer->SetClipper( pcClipper ); SAFE_RELEASE( pcClipper ); // Get the backbuffer. For fullscreen mode, the backbuffer was created // along with the primary, but windowed mode still needs to create one. if( dwFlags & D3DFW_BACKBUFFER ) { // Create the back buffer (the render target) ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS; ddsd.dwWidth = m_dwRenderWidth; ddsd.dwHeight = m_dwRenderHeight; ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE; if( FAILED( hr = m_pDD->CreateSurface( &ddsd, &m_pddsBackBuffer, NULL ) ) ) { DEBUG_MSG( TEXT("Error: Couldn't create the backbuffer") ); if( hr != DDERR_OUTOFVIDEOMEMORY ) return D3DFWERR_NOBACKBUFFER; DEBUG_MSG( TEXT("Error: Out of video memory") ); return DDERR_OUTOFVIDEOMEMORY; } } else // For rendering without a backbuffer { ClientToScreen( m_hWnd, (POINT*)&m_rcViewportRect.left ); ClientToScreen( m_hWnd, (POINT*)&m_rcViewportRect.right ); } } // Set up backbuffer ptr and ref counts if( dwFlags & D3DFW_BACKBUFFER ) m_pddsRenderTarget = m_pddsBackBuffer; else m_pddsRenderTarget = m_pddsFrontBuffer; m_pddsRenderTarget->AddRef(); return S_OK; } //----------------------------------------------------------------------------- // Name: CreateZBuffer() // Desc: Internal function called by Create() to make and attach a zbuffer // to the renderer //----------------------------------------------------------------------------- HRESULT CD3DFramework::CreateZBuffer() { HRESULT hr; // Check if the device supports z-bufferless hidden surface removal. If so, // we don't really need a z-buffer DWORD dwRasterCaps = m_ddDeviceDesc.dpcTriCaps.dwRasterCaps; if( dwRasterCaps & D3DPRASTERCAPS_ZBUFFERLESSHSR ) return S_OK; // Get z-buffer dimensions from the render target // Setup the surface desc for the z-buffer. DDSURFACEDESC2 ddsd; D3DUtil_InitSurfaceDesc( ddsd, DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS | DDSD_PIXELFORMAT ); ddsd.ddsCaps.dwCaps = DDSCAPS_ZBUFFER | m_dwDeviceMemType; ddsd.dwWidth = m_dwRenderWidth; ddsd.dwHeight = m_dwRenderHeight; memcpy( &ddsd.ddpfPixelFormat, &m_ddpfZBuffer, sizeof(DDPIXELFORMAT) ); // Create and attach a z-buffer if( FAILED( hr = m_pDD->CreateSurface( &ddsd, &m_pddsZBuffer, NULL ) ) ) { DEBUG_MSG( TEXT("Error: Couldn't create a ZBuffer surface") ); if( hr != DDERR_OUTOFVIDEOMEMORY ) return D3DFWERR_NOZBUFFER; DEBUG_MSG( TEXT("Error: Out of video memory") ); return DDERR_OUTOFVIDEOMEMORY; } if( FAILED( m_pddsRenderTarget->AddAttachedSurface( m_pddsZBuffer ) ) ) { DEBUG_MSG( TEXT("Error: Couldn't attach zbuffer to render surface") ); return D3DFWERR_NOZBUFFER; } return S_OK; } //----------------------------------------------------------------------------- // Name: Create3DDevice() // Desc: Creates the 3D device for the render target //----------------------------------------------------------------------------- HRESULT CD3DFramework::Create3DDevice( GUID* pDeviceGUID ) { // Check that we are NOT in a palettized display. That case will fail, // since the framework doesn't use palettes. DDSURFACEDESC2 ddsd; ddsd.dwSize = sizeof(DDSURFACEDESC2); m_pDD->GetDisplayMode( &ddsd ); if( ddsd.ddpfPixelFormat.dwRGBBitCount <= 8 ) return D3DFWERR_INVALIDMODE; // Create the device if( FAILED( m_pD3D->CreateDevice( *pDeviceGUID, m_pddsRenderTarget, &m_pd3dDevice, NULL ) ) ) { DEBUG_MSG( TEXT("Couldn't create the D3DDevice") ); return D3DFWERR_NO3DDEVICE; } return S_OK; } //----------------------------------------------------------------------------- // Name: CreateViewport() // Desc: Create the D3D viewport used by the renderer. //----------------------------------------------------------------------------- HRESULT CD3DFramework::CreateViewport() { // Set up the viewport data parameters HRESULT hr; D3DVIEWPORT2 vdData; D3DUtil_InitViewport( vdData, m_dwRenderWidth, m_dwRenderHeight ); // Create the viewport if( FAILED( m_pD3D->CreateViewport( &m_pvViewport, NULL ) ) ) { DEBUG_MSG( TEXT("Error: Couldn't create a viewport") ); return D3DFWERR_NOVIEWPORT; } // Associate the viewport with the D3DDEVICE object if( FAILED( hr = m_pd3dDevice->AddViewport( m_pvViewport ) ) ) { DEBUG_MSG( TEXT("Error: Couldn't add the viewport") ); return D3DFWERR_NOVIEWPORT; } // Set the parameters to the new viewport if( FAILED( m_pvViewport->SetViewport2( &vdData ) ) ) { DEBUG_MSG( TEXT("Error: Couldn't set the viewport data") ); return D3DFWERR_NOVIEWPORT; } // Finally, set the current viewport for the current device if( FAILED( m_pd3dDevice->SetCurrentViewport( m_pvViewport ) ) ) { DEBUG_MSG( TEXT("Error: Couldn't set current viewport to device") ); return D3DFWERR_NOVIEWPORT; } return S_OK; } //----------------------------------------------------------------------------- // Name: ShowFrame() // Desc: Show the frame on the primary surface, via a blt or a flip. //----------------------------------------------------------------------------- HRESULT CD3DFramework::ShowFrame() { if( NULL == m_pddsFrontBuffer ) return D3DFWERR_NOTINITIALIZED; // Check for a backbuffer. If no backbuffer exists, then we have nothing to // do. However, to be consistent let's check for lost surfaces if( NULL == m_pddsBackBuffer ) return m_pddsFrontBuffer->IsLost(); // If we are in fullscreen mode perform a flip. if( m_bIsFullscreen ) return m_pddsFrontBuffer->Flip( NULL, DDFLIP_WAIT ); // Else, we are in windowed mode, so perform a blit. return m_pddsFrontBuffer->Blt( &m_rcScreenRect, m_pddsBackBuffer, &m_rcViewportRect, DDBLT_WAIT, NULL ); } //----------------------------------------------------------------------------- // Name: FlipToGDISurface() // Desc: Puts the GDI surface in front of the primary, so that dialog // boxes and other windows drawing funcs may happen. //----------------------------------------------------------------------------- HRESULT CD3DFramework::FlipToGDISurface( BOOL bDrawFrame ) { if( m_pDD && m_bIsFullscreen ) { m_pDD->FlipToGDISurface(); if( bDrawFrame ) { DrawMenuBar( m_hWnd ); RedrawWindow( m_hWnd, NULL, NULL, RDW_FRAME ); } } return S_OK; } //----------------------------------------------------------------------------- // Name: RestoreSurfaces() // Desc: Checks for lost surfaces and restores them if lost. Note: Don't // restore render surface, since it's just a duplicate ptr. //----------------------------------------------------------------------------- HRESULT CD3DFramework::RestoreSurfaces() { // Check/restore the primary surface if( m_pddsFrontBuffer ) if( m_pddsFrontBuffer->IsLost() ) m_pddsFrontBuffer->Restore(); // Check/restore the back buffer if( m_pddsBackBuffer ) if( m_pddsBackBuffer->IsLost() ) m_pddsBackBuffer->Restore(); // Check/restore the z-buffer surface if( m_pddsZBuffer ) if( m_pddsZBuffer->IsLost() ) m_pddsZBuffer->Restore(); return S_OK; } //----------------------------------------------------------------------------- // Name: Move() // Desc: Moves the screen rect for windowed renderers //----------------------------------------------------------------------------- VOID CD3DFramework::Move( INT x, INT y ) { if( FALSE == m_bIsFullscreen ) { SetRect( &m_rcScreenRect, x, y, x + m_dwRenderWidth, y + m_dwRenderHeight ); // If we have no backbuffer, then update viewport rect as well if( NULL == m_pddsBackBuffer ) CopyMemory( &m_rcViewportRect, &m_rcScreenRect, sizeof(RECT) ); } } //----------------------------------------------------------------------------- // Name: ChangeRenderTarget() // Desc: Wrapper for the IDirect3DDevice::SetRenderTarget() function, which // adds functionality to handle an attached z-buffer. Note that this // function does NOT alter the current viewport //----------------------------------------------------------------------------- HRESULT CD3DFramework::ChangeRenderTarget( LPDIRECTDRAWSURFACE4 pddsNewTarget ) { if( NULL == pddsNewTarget ) return E_INVALIDARG; // Get the new render target dimensions DDSURFACEDESC2 ddsd; D3DUtil_InitSurfaceDesc( ddsd ); pddsNewTarget->GetSurfaceDesc( &ddsd ); m_dwRenderWidth = ddsd.dwWidth; m_dwRenderHeight = ddsd.dwHeight; // If a z-buffer is attached, delete and recreate it if( NULL != m_pddsZBuffer ) { // Remove the old z-buffer m_pddsRenderTarget->DeleteAttachedSurface( 0, m_pddsZBuffer ); SAFE_RELEASE( m_pddsZBuffer ); // Keep track of reference counts SAFE_RELEASE( m_pddsRenderTarget ); m_pddsRenderTarget = pddsNewTarget; m_pddsRenderTarget->AddRef(); // Create the new z-buffer if( FAILED( CreateZBuffer() ) ) { DEBUG_MSG( TEXT("ChangeRenderTarget() - zbuffer create failed") ); return D3DFWERR_NOZBUFFER; } } else { // With no z-buffer, we just do accounting on the reference counts SAFE_RELEASE( m_pddsRenderTarget ); m_pddsRenderTarget = pddsNewTarget; m_pddsRenderTarget->AddRef(); } // Finally, perform the set render target call if( FAILED( m_pd3dDevice->SetRenderTarget( m_pddsRenderTarget, 0 ) ) ) { return D3DFWERR_NORENDERTARGET; } return S_OK; }