game.cpp

来自「DirectInput的基本实现 只是基本应用」· C++ 代码 · 共 258 行

CPP
258
字号
#include "StdAfx.h"
#include ".\game.h"

CGame::CGame(void) :
m_pD3D(NULL),
m_pDevice(NULL),
m_bDeviceLost(false),
m_pFont(NULL)
{
	for(int i=0; i<2; ++i)
		m_pBall[i] = NULL;
}

CGame::~CGame(void)
{
	SAFE_RELEASE(m_pD3D);
	SAFE_RELEASE(m_pDevice);
	SAFE_RELEASE(m_pFont);

	for(int i=0; i<2; ++i)
		SAFE_DELETE(m_pBall[i]);
}

bool CGame::Init( HINSTANCE hInstance, HWND hWnd )
{
	// COM初始化
	CoInitialize(NULL);

	if(FAILED(_InitD3D(hWnd)))
		return false;

	// 创建字体
	D3DXCreateFont( m_pDevice, 15, 0, FW_BOLD, 1, FALSE, DEFAULT_CHARSET,
					OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE,
					"Arial", &m_pFont );

	for(int i=0; i<2; ++i)
	{
		m_pBall[i] = new CStaticMesh;
		m_pBall[i]->Init( m_pDevice, "ball.X" );
		m_pBall[i]->SetTextureFromFile( 0, "texture.dds" );
		m_boundSphere[i]._center = D3DXVECTOR3(-5.0f + i*10.0f, 0.0f, 0.0f);
		m_boundSphere[i].radius = 3.0f;
		m_bRotate[i] = false;
		m_fAngle[i] = 0.0f;
	}

	return true;
}

HRESULT CGame::_InitD3D(HWND hWnd)
{
	// COM interface
	if( NULL == ( m_pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) )
		return E_FAIL;

	// current display mode
	D3DDISPLAYMODE d3ddm;
	if( FAILED(m_pD3D->GetAdapterDisplayMode( D3DADAPTER_DEFAULT, &d3ddm)))
		return E_FAIL;

	RECT rect;
	GetClientRect(hWnd, &rect);

	ZeroMemory(&m_d3dpp, sizeof(m_d3dpp));
	m_d3dpp.Windowed = TRUE/*FALSE*/;
	m_d3dpp.BackBufferCount = 1;
	m_d3dpp.BackBufferFormat = d3ddm.Format;
	m_d3dpp.BackBufferWidth = rect.right - rect.left;
	m_d3dpp.BackBufferHeight = rect.bottom - rect.top;
	//m_d3dpp.BackBufferWidth = d3ddm.Width;
	//m_d3dpp.BackBufferHeight = d3ddm.Height;
	m_d3dpp.hDeviceWindow = hWnd;
	m_d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
	m_d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
	m_d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
	m_d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
	m_d3dpp.EnableAutoDepthStencil = TRUE;   

	// Create D3D Device  
	if( FAILED( m_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
		D3DCREATE_SOFTWARE_VERTEXPROCESSING,
		&m_d3dpp, &m_pDevice ) ) )
	{
		return E_FAIL;
	}

	return S_OK;
}

void CGame::Update(float fElapsedTime)
{
	D3DXMATRIX matRroj;
	D3DXMatrixPerspectiveFovLH( &matRroj, D3DX_PI/4, 4.f/3.f, 1.f, 500.0f );
	m_pDevice->SetTransform(D3DTS_PROJECTION, &matRroj);
	// 更新视矩阵
	D3DXMATRIX matView;
	D3DXMatrixLookAtLH( &matView, &D3DXVECTOR3(13.0f, 13.0f, 13.0f), &D3DXVECTOR3(0.0f, 0.0f, 0.0f), &D3DXVECTOR3(0.0f, 1.0f, 0.0f) );
	m_pDevice->SetTransform(D3DTS_VIEW, &matView);
}

void CGame::Render(float fElapsedTime)
{
	// 在每次渲染前判断是否发生设备丢失
	HRESULT hr;

	// 后备缓冲区须与窗口大小一致才能正确获得D3DERR_DEVICENOTRESET
	// 否则检测系统协调层级只能获得D3DERR_DEVICELOST
	if( m_bDeviceLost == true )
	{
		Sleep( 100 ); // 100 milliseconds
		// 检查系统协调层级,系统可以根据函数返回值判断设备丢失时采取的措施
		if( FAILED( hr = m_pDevice->TestCooperativeLevel() ) )
		{
			if( hr == D3DERR_DEVICELOST )
				return;

			// 设备丢失能够被自动重置,这时候返回进行再次尝试
			if( hr == D3DERR_DEVICENOTRESET )
			{
				// 清空内存资源
				InvalidateDeviceObjects();
				// 调用Reset函数重置设备
				hr = m_pDevice->Reset( &m_d3dpp );
				if( FAILED(hr ) )
					return;
				// 重新设置内存资源里的数据
				RestoreDeviceObjects();

				return;
			}
		}
		m_bDeviceLost = false;
	}

	m_pDevice->Clear( 0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, 
					  D3DCOLOR_XRGB(0,0,0), 1.0f, 0 );

	m_pDevice->BeginScene();

	m_pDevice->SetRenderState( D3DRS_LIGHTING, false );

	D3DXMATRIX matWorld;

	for(int i=0; i<2; ++i)
	{
		if(m_bRotate[i])
			m_fAngle[i] += 1.5f * fElapsedTime;

		D3DXMatrixRotationY(&matWorld, m_fAngle[i]);
		matWorld._41 = -5.0f + i*10.0f;
		matWorld._42 = 0.0f;
		matWorld._43 = 0.0f;

		m_pDevice->SetTransform( D3DTS_WORLD, &matWorld );
		m_pBall[i]->Render(matWorld);
	}

	m_pDevice->EndScene();

	hr = m_pDevice->Present( NULL, NULL, NULL, NULL );
	if( hr == D3DERR_DEVICELOST )
		m_bDeviceLost = true;
}

void CGame::InvalidateDeviceObjects(void)
{
	m_pFont->OnLostDevice();
}

void CGame::RestoreDeviceObjects(void)
{
	m_pFont->OnResetDevice();
}

void CGame::HandleMessage(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	switch (message)
	{
	case WM_LBUTTONDOWN:
		{
			POINT pt;
			GetCursorPos(&pt);
			ScreenToClient(hWnd, &pt);
			
			Ray ray = CalculateRay(pt.x, pt.y);
			D3DXMATRIX mat;
			m_pDevice->GetTransform(D3DTS_VIEW, &mat);
			D3DXMatrixInverse(&mat, NULL, &mat);
			ray = TransformRay(ray, &mat);

			for(int i=0; i<2; ++i)
			{
				if( CheckIntersection(&ray, &m_boundSphere[i]) )
					m_bRotate[i] = true;
				else
					m_bRotate[i] = false;
			}
		
		}
		break;
	}
}

CGame::Ray CGame::CalculateRay(int x, int y)
{
	float px=0.0f;
	float py=0.0f;
	//获取视口大小
	D3DVIEWPORT9 vp;
	m_pDevice->GetViewport(&vp);
	//获取投影矩阵
	D3DXMATRIX proj;
	m_pDevice->GetTransform(D3DTS_PROJECTION,&proj);
	
	//计算拾取射线
	px=(((2.0f*x)/vp.Width)-1.0f)/proj._11;
	py=(((-2.0f*y)/vp.Height)+1.0f)/proj._22;
	Ray ray;
	ray._origin = D3DXVECTOR3(0.0f,0.0f,0.0f);
	ray._dirction = D3DXVECTOR3(px,py,1.0f);
	return ray;
}

CGame::Ray CGame::TransformRay(Ray ray, D3DXMATRIX* T)
{
	Ray transRay;
	//转换射线的起点
	D3DXVec3TransformCoord(&transRay._origin,&ray._origin,T);
	//转换射线的方向
	D3DXVec3TransformNormal(&transRay._dirction,&ray._dirction,T);
	D3DXVec3Normalize(&transRay._dirction,&transRay._dirction);
	return transRay;
}

BOOL CGame::CheckIntersection(Ray* ray, BoundSphere* sphere)
{
	//计算t0与t1的值
	D3DXVECTOR3 v = ray->_origin-sphere->_center;
	float b = 2.0f*D3DXVec3Dot(&ray->_dirction,&v);
	float c = D3DXVec3Dot(&v,&v)-(sphere->radius*sphere->radius);

	float n = (b*b)-(4.0f*c);
	if (n<0.0f)
	{
		return false;
	}
	n = sqrtf(n);
	float t0 = (-b+n)/2.0f;
	float t1 = (-b-n)/2.0f;
	//判断是否相交
	if (t0>=0||t1>=0)
	{
		return true;
	}
	return false;
}

⌨️ 快捷键说明

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