본문 바로가기
Lib/DirectX

회전하는 입방체 만들기

by KingCat 2011. 11. 9.
#include "d3dUtility.h"

// 장치를 위한 전역 변수 생성
IDirect3DDevice9* Device=0;

// 화면의 해상도를 정의할 상수 전역 변수 인스턴스
const int Width = 800;
const int Height = 600;

// 버텍스 버퍼와 인덱스 버퍼를 저장할 전역 변수 인스턴스 생성
IDirect3DVertexBuffer9* VB = 0;
IDirect3DIndexBuffer9* IB = 0;

// 커스텀 버텍스 포맷을 만들기 위한 구조체
struct Vertex
{
	Vertex(){}
	// 버텍스의 위치 정보만을 보관
	Vertex(float x, float y, float z)
	{
		_x=x; _y=y; _z=z;
	}

	float _x, _y, _z;

	static const DWORD FVF;
};
// 구조체의 유연한 버텍스 포맷 정의
const DWORD Vertex::FVF = D3DFVF_XYZ;

bool Setup()
{
	// 버텍스 버퍼와 인덱스 버퍼 생성
	Device->CreateVertexBuffer(
		8*sizeof(Vertex),
		D3DUSAGE_WRITEONLY,
		Vertex::FVF,
		D3DPOOL_MANAGED,
		&VB,
		0);

	Device->CreateIndexBuffer(
		36*sizeof(WORD),
		D3DUSAGE_WRITEONLY,
		D3DFMT_INDEX16,
		D3DPOOL_MANAGED,
		&IB,
		0);

	// 큐브 데이터로 버퍼를 채운다.
	Vertex* vertices;
	VB->Lock(0,0,(void**)&vertices,0);
	// 단위 큐브의 버텍스들
	vertices[0] = Vertex(-1.0f, -1.0f, -1.0f);
	vertices[1] = Vertex(-1.0f,  1.0f, -1.0f);
	vertices[2] = Vertex( 1.0f,  1.0f, -1.0f);
	vertices[3] = Vertex( 1.0f, -1.0f, -1.0f);
	vertices[4] = Vertex(-1.0f, -1.0f,  1.0f);
	vertices[5] = Vertex(-1.0f,  1.0f,  1.0f);
	vertices[6] = Vertex( 1.0f,  1.0f,  1.0f);
	vertices[7] = Vertex( 1.0f, -1.0f,  1.0f);

	VB->Unlock();

	// 입방체의 삼각형들을 정의
	WORD* indices = 0;
	IB->Lock(0, 0, (void**)&indices, 0);

	// 전면
	indices[0] = 0; indices[1] = 1; indices[2] = 2;
	indices[3] = 0; indices[4] = 2; indices[5] = 3;

	// 후면
	indices[6] = 4; indices[7] = 6; indices[8] = 5;
	indices[9] = 4; indices[10] = 7; indices[11] = 6;

	// 왼쪽 측면
	indices[12] = 4; indices[13] = 5; indices[14] = 1;
	indices[15] = 4; indices[16] = 1; indices[17] = 0;

	// 오른쪽 측면
	indices[18] = 3; indices[19] = 2; indices[20] = 6;
	indices[21] = 3; indices[22] = 6; indices[23] = 7;

	// 상단
	indices[24] = 1; indices[25] = 5; indices[26] = 6;
	indices[27] = 1; indices[28] = 6; indices[29] = 2;

	// 하단
	indices[30] = 4; indices[31] = 0; indices[32] = 3;
	indices[33] = 4; indices[34] = 3; indices[35] = 7;


	IB->Unlock();

	// 카메라의 위치와 방향을 조정
	D3DXVECTOR3 position(0.0f, 0.0f, -5.0f);
	D3DXVECTOR3 target(0.0f, 0.0f, 0.0f);
	D3DXVECTOR3 up(0.0f, 1.0f, 0.0f);
	D3DXMATRIX V;
	D3DXMatrixLookAtLH(&V, &position, &target, &up);
	Device->SetTransform(D3DTS_VIEW, &V);
	
	// 투영 행렬을 지정
	D3DXMATRIX proj;
	D3DXMatrixPerspectiveFovLH(
		&proj,
		D3DX_PI * 0.5f,
		(float)Width / (float)Height,
		1.0f,
		1000.0f);
	Device->SetTransform(D3DTS_PROJECTION, &proj);
	// 렌더 상태를 지정한다.
	Device->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);

	return true;
}

void Cleanup()
{
	// 그 동안 할당했던 메모리(버텍스 버퍼)를 해제.
	d3d::Releasse<IDirect3DVertexBuffer9*>(VB);
	d3d::Releasse<IDirect3DIndexBuffer9*>(IB);
}

bool Display(float timeDelta)
{
	if(Device)
	{
		// 입방체를 회전시킨다.
		D3DXMATRIX Rx, Ry;

		// x축으로 45도 회전
		D3DXMatrixRotationX(&Rx, 3.14f / 4.0f);

		// 각 프레임당 y 회전을 증가
		static float y = 0.0f;
		D3DXMatrixRotationY(&Ry, y);
		y += timeDelta;

		// 각도가 2*PI에 이르면 0으로 초기화
		if(y>=6.28f)
			y=0.0f;

		// 회전을 결합
		D3DXMATRIX p = Rx * Ry;

		Device->SetTransform(D3DTS_WORLD, &p);

		// 장면을 그린다.
		Device->Clear(0,0,D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffffffff, 1.0f, 0);
		Device->BeginScene();

		Device->SetStreamSource(0, VB, 0, sizeof(Vertex));
		Device->SetIndices(IB);
		Device->SetFVF(Vertex::FVF);
		Device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 8, 0, 12);

		Device->EndScene();
		Device->Present(0,0,0,0);
	}
	return true;
}

LRESULT CALLBACK d3d::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	switch(msg)
	{
	case WM_DESTROY:
		::PostQuitMessage(0);
		break;
	case WM_KEYDOWN:
		if(wParam == VK_ESCAPE)
			::DestroyWindow(hwnd);
		break;
	}
	return ::DefWindowProcA(hwnd, msg, wParam, lParam);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE prevInstance,
	PSTR cmdLine, int showCmd)
{
	if(!d3d::InitD3D(hInstance, Width, Height, true, D3DDEVTYPE_HAL, &Device))
	{
		::MessageBox(0, "InitD3D() - FAILED", 0,0);
		return 0;
	}

	if(!Setup())
	{
		::MessageBox(0, "Setup() - FAILED", 0,0);
		return 0;
	}
	d3d::EnterMsgLoop(Display);
	Cleanup();
	Device->Release();
	return 0;
}

결과 :