⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 graphicslayer.cpp

📁 <B>DirectX9.0 3D游戏编程</B>
💻 CPP
字号:
/*******************************************************************
 *         Advanced 3D Game Programming using DirectX 9.0
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * copyright (c) 2003 by Peter A Walsh and Adrian Perez
 * See license.txt for modification and distribution information
 ******************************************************************/


#include <algorithm>

#include "stdafx.h"
#include "GraphicsLayer.h"
#include "Application.h"
#include "GameErrors.h"
#include "DxHelper.h"
#include "Window.h"
#include "d3d9.h"

using namespace std;


/**
 * This is the static member variable that points to the one
 * (and only one) graphics layer allowed in each application.
 */
cGraphicsLayer* cGraphicsLayer::m_pGlobalGLayer = NULL;

cGraphicsLayer::cGraphicsLayer( HWND hWnd )
{
	if( m_pGlobalGLayer )
		throw cGameError( 
			"cGraphicsLayer object already instantiated\n");
	m_pGlobalGLayer = this;

	m_hWnd = hWnd ;

	m_pD3D			 = 0;
	m_pDevice		 = 0;

	m_pBackSurf		 = 0;
}


void cGraphicsLayer::DestroyAll()
{

    SafeRelease( m_pBackSurf );
	SafeRelease( m_pDevice );

	SafeRelease( m_pD3D );

	/**
	 * Prevent any further access to the graphics class
	 */
	m_pGlobalGLayer = NULL;
}

cGraphicsLayer::~cGraphicsLayer()
{
	DestroyAll();
}


void cGraphicsLayer::Flip()
{

	HRESULT r = 0;

	// Make sure the device has been created.
	assert( m_pDevice );
	
	// Blit the back buffer to the primary surface
	r = m_pDevice->Present( NULL, NULL, NULL, NULL );
	if( FAILED( r ) )
	{
		OutputDebugString( "Flipping Failed!\n" );
	}

}


void cGraphicsLayer::InitD3DFullScreen( 
	int Ordinal, DWORD flags, int width, int height, int bpp )
{

	HRESULT r = 0;

	// Create the Direct3D interface
	m_pD3D = Direct3DCreate9( D3D_SDK_VERSION );
	if( !m_pD3D )
	{
		throw cGameError( "Could not create IDirect3D9" );
	}

	// Structure to hold the creation parameters for the device
	D3DPRESENT_PARAMETERS d3dpp;
	ZeroMemory( &d3dpp, sizeof( d3dpp ) );

	// The width and height for the initial back buffer
	d3dpp.BackBufferWidth			= width;
	d3dpp.BackBufferHeight			= height;
	
	// Set the flags for the bit depth - only supports 16, 24, and 32 bit formats
	if( bpp == 16 )
		d3dpp.BackBufferFormat		= D3DFMT_R5G6B5;
	else if( bpp == 24 )
		d3dpp.BackBufferFormat		= D3DFMT_R8G8B8;
	else if( bpp == 32 )
		d3dpp.BackBufferFormat		= D3DFMT_A8R8G8B8;
	else
	{
		OutputDebugString( "Invalid surface format - defaulting to 32bit" );
		d3dpp.BackBufferFormat		= D3DFMT_A8R8G8B8;
	}

	// Only have one back buffer associated with the primary surface
	d3dpp.BackBufferCount			= 1;
	// No multisampling
	d3dpp.MultiSampleType			= D3DMULTISAMPLE_NONE;
	// Copy the back buffer to the primary surface normally
	d3dpp.SwapEffect				= D3DSWAPEFFECT_COPY;
	// The handle to the window to render in to
	d3dpp.hDeviceWindow				= m_hWnd;
	// Fullscreen operation
	d3dpp.Windowed					= FALSE;
	
	// If a depth buffer was requested
	if( flags & (GLF_ZBUFFER|GLF_HIRESZBUFFER) )
	{
		// Tell Direct3D we want a depth buffer
		d3dpp.EnableAutoDepthStencil	= TRUE;

		
		if( flags & (GLF_HIRESZBUFFER) )
		{
			
			if( flags & (GLF_STENCIL) )
				// 24 bit depth buffer and 8 bit stencil
				d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;
			else
				// 32 bit depth buffer and no stencil
				d3dpp.AutoDepthStencilFormat = D3DFMT_D32;
		}
		else
		{
			if( flags & (GLF_STENCIL) )
				// 15 bit depth buffer and 1 bit stencil
				d3dpp.AutoDepthStencilFormat = D3DFMT_D15S1;
			else
				// 16 bit depth buffer and no stencil
				d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
		}
		
	}
	else
	{
		// No depth buffer or stencil
		d3dpp.EnableAutoDepthStencil = FALSE;	
	}
	
	// Use the default refresh rate
	d3dpp.FullScreen_RefreshRateInHz= D3DPRESENT_RATE_DEFAULT;
	// Update the screen as soon as possible (dont wait for vsync)
	d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
	// Allow the back buffer to be locked
	d3dpp.Flags						= D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
	
	// Hardware device by default
	D3DDEVTYPE DeviceType = D3DDEVTYPE_HAL;

	if( flags & (GLF_FORCEHARDWARE) )
		DeviceType = D3DDEVTYPE_HAL;
	else if( flags & (GLF_FORCESOFTWARE) )
		DeviceType = D3DDEVTYPE_SW;
	else if( flags & (GLF_FORCEREFERENCE) )
		DeviceType = D3DDEVTYPE_REF;
	
	// Create the device using hardware acceleration if available
	r = m_pD3D->CreateDevice( Ordinal, DeviceType, m_hWnd,
							D3DCREATE_SOFTWARE_VERTEXPROCESSING, 
							&d3dpp, &m_pDevice );
	if( FAILED( r ) )
	{
		throw cGameError( "Could not create IDirect3DDevice9" );
	}

	// Keep a copy of the screen dimensions
	m_rcScreenRect.left = m_rcScreenRect.top = 0;
	m_rcScreenRect.right = width;
	m_rcScreenRect.bottom = height;

	// Get a copy of the pointer to the back buffer
	m_pDevice->GetBackBuffer( Ordinal, 0, D3DBACKBUFFER_TYPE_MONO, &m_pBackSurf );

	// Setup the viewport
	MakeViewport();

	// Build the projection matrix
	MakeProjectionMatrix();

}


void cGraphicsLayer::DrawTextString( int x, int y, 
							DWORD color, const char * str )
{

	HRESULT r = 0;
	
	if( !m_pBackSurf )
		return;

	// Get a handle for the font to use
	HFONT hFont = (HFONT)GetStockObject( SYSTEM_FONT );	
	
	LPD3DXFONT pFont = 0;
	// Create the D3DX Font
	r = D3DXCreateFont( m_pDevice, hFont, &pFont );
	if( FAILED( r ) )
		return;

	// Rectangle where the text will be located
	RECT TextRect = { x, y, 0, 0 };

	// Inform font it is about to be used
	pFont->Begin();

	// Calculate the rectangle the text will occupy
	pFont->DrawText( str, -1, &TextRect, DT_CALCRECT, 0 );

	// Output the text, left aligned
	pFont->DrawText( str, -1, &TextRect, DT_LEFT, color );

	// Finish up drawing
	pFont->End();

	// Release the font
	pFont->Release();

}



void cGraphicsLayer::Create(
	HWND hWnd,
	short width, short height, 
	ULONG flags,
	GUID* pGuid )
{
	new cGraphicsLayer( hWnd ); // construct the object.

	int depth = (flags & GLF_FORCE16BIT) ? 16 : 32;
	
	// Init Direct3D and the device for fullscreen operation
	Graphics()->InitD3DFullScreen( D3DADAPTER_DEFAULT, GLF_ZBUFFER, width, height, depth );
}

void cGraphicsLayer::SetProjectionData( 
	float inFov, 
	float inNear, 
	float inFar )
{
	m_fov = inFov;
	m_far = inFar;
	m_near = inNear;
}

void cGraphicsLayer::GetProjectionData( 
	float* inFov, 
	float* inNear, 
	float* inFar )
{
	if( inFov )
		*inFov = m_fov;
	if( inFar )
		*inFar = m_far;
	if( inNear )
		*inNear = m_near;
}

eResult cGraphicsLayer::MakeProjectionMatrix()
{
	D3DMATRIX mat;
	
	DWORD width, height;
	width = m_rcScreenRect.right;
	height = m_rcScreenRect.bottom;

	float fAspect = ((float)height) / width;

    if( fabs(m_far-m_near) < 0.01f )
        return resFailed;
    if( fabs(sin(m_fov/2)) < 0.01f )
        return resFailed;

	float w = fAspect * (float)( cos(m_fov/2)/sin(m_fov/2) );
	float h =   1.0f  * (float)( cos(m_fov/2)/sin(m_fov/2) );
    float Q = m_far / ( m_far - m_near );

    ZeroMemory( &mat, sizeof(D3DMATRIX) );
    mat._11 = w;
    mat._22 = h;
    mat._33 = Q;
    mat._34 = 1.0f;
    mat._43 = -Q*m_near;

	m_pDevice->SetTransform( D3DTS_PROJECTION, &mat );

    return resAllGood;
}

void cGraphicsLayer::GetViewMatrix( matrix4* pMat )
{
	// Pass the call to the Direct3D Device
	m_pDevice->GetTransform( 
		D3DTS_VIEW, 
		(D3DMATRIX*)pMat );
}

void cGraphicsLayer::SetViewMatrix( const matrix4& mat )
{
	// Pass the call to the Direct3D Device
	m_pDevice->SetTransform( 
		D3DTS_VIEW, 
		(D3DMATRIX*)&mat );
}

void cGraphicsLayer::GetProjectionMatrix( matrix4* pMat )
{
	// Pass the call to the Direct3D Device
	m_pDevice->GetTransform( 
		D3DTS_PROJECTION, 
		(D3DMATRIX*)pMat );
}

void cGraphicsLayer::SetProjectionMatrix( const matrix4& mat )
{
	// Pass the call to the Direct3D Device
	m_pDevice->SetTransform( 
		D3DTS_PROJECTION, 
		(D3DMATRIX*)&mat );
}

void cGraphicsLayer::SetWorldMatrix( const matrix4& mat )
{
	// Pass the call to the Direct3D Device
	m_pDevice->SetTransform( 
		D3DTS_WORLD, 
		(D3DMATRIX*)&mat );
}

void cGraphicsLayer::GetWorldMatrix( matrix4* pMat )
{
	// Pass the call to the Direct3D Device
	m_pDevice->GetTransform( 
		D3DTS_WORLD, 
		(D3DMATRIX*)pMat );
}

void cGraphicsLayer::Clear( 
	bool bClearFrame, 
	bool bClearZ, 
	DWORD frameColor, 
	float zValue )
{
	if( !m_pBackSurf )
		return;

	DWORD flags = bClearFrame ? D3DCLEAR_TARGET : 0L;
	flags |= bClearZ? D3DCLEAR_ZBUFFER : 0L;

	HRESULT hr;
	hr = m_pDevice->Clear( 0, 0, flags, frameColor, zValue, 0);

	if( FAILED( hr ))
	{
		DP0("[cGraphicsLayer::Clear]: Clear failed\n");
	}
}

void cGraphicsLayer::BeginScene()
{
	// Pass the call to the Direct3D Device
	m_pDevice->BeginScene();
}

void cGraphicsLayer::EndScene()
{
	// Pass the call to the Direct3D Device
	m_pDevice->EndScene();
}

void cGraphicsLayer::MakeViewport()
{
	HRESULT hr;
	if( !m_pDevice )
	{
		DP("[cGraphicsLayer::MakeViewport]: no device\n");
		return;
	}

    DWORD dwRenderWidth  = m_rcScreenRect.right;
    DWORD dwRenderHeight = m_rcScreenRect.bottom;
    D3DVIEWPORT9 vp = { 0, 0, dwRenderWidth, dwRenderHeight, 0.0f, 1.0f };

    hr = m_pDevice->SetViewport( &vp );
    if( FAILED( hr ) )
        throw cGameError("viewport setting failed.");
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -