MuckyFoot-UrbanChaos/thrust/d3dframe.cpp
2017-05-20 11:14:17 +10:00

756 lines
24 KiB
C++

//-----------------------------------------------------------------------------
// 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
//-----------------------------------------------------------------------------
#define STRICT
#include <windows.h>
#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;
}