読者です 読者をやめる 読者になる 読者になる

hayateasdf's blog

C#,javascript,pythonなどいろいろ。広く浅く

スキニング Cube DirectX9

// -----------------------------------------------------
// main.cpp
// -----------------------------------------------------
#pragma comment(lib, "d3d9.lib")
#pragma comment(lib, "d3dx9.lib")

#include <windows.h>
#include <tchar.h>
#include <d3d9.h>
#include <d3dx9.h>
#include "SkinCube.h"


TCHAR gName[100] = _T("スキニングテスト");
LRESULT CALLBACK WndProc(HWND hWnd, UINT mes, WPARAM wParam, LPARAM lParam){
	if(mes == WM_DESTROY || mes == WM_CLOSE) { PostQuitMessage(0); return 0; }
	return DefWindowProc(hWnd, mes, wParam, lParam);
}

int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
	MSG msg; HWND hWnd;
	WNDCLASSEX wcex = {sizeof(WNDCLASSEX), CS_HREDRAW | CS_VREDRAW, WndProc, 0, 0, hInstance, NULL, NULL,
		(HBRUSH)(COLOR_WINDOW + 1), NULL, (TCHAR*)gName, NULL};

	if(!RegisterClassEx(&wcex))
		return 0;
	int w = 640, h = 480;
	RECT clientRect = { 0, 0, w, h };
	::AdjustWindowRect(&clientRect, WS_OVERLAPPEDWINDOW, FALSE);

	if(!(hWnd = CreateWindow(gName, gName, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, clientRect.right - clientRect.left, clientRect.bottom - clientRect.top, NULL, NULL, hInstance, NULL)))
		return 0;


	//D3D初期化
	D3DPRESENT_PARAMETERS param = {w, h, D3DFMT_UNKNOWN, 0, D3DMULTISAMPLE_NONE, 0, D3DSWAPEFFECT_DISCARD, NULL, TRUE, TRUE, D3DFMT_D24FS8, 0, 0};
	LPDIRECT3D9 d3d;
	IDirect3DDevice9* device;
	if(!(d3d = Direct3DCreate9(D3D_SDK_VERSION))) return 0;

	if(FAILED(d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, &param, &device)))
	if(FAILED(d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &param, &device)))
	if(FAILED(d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_REF, hWnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, &param, &device)))
	if(FAILED(d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_REF, hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &param, &device)))
	{
		d3d->Release();
		return 0;
	}


	SkinCube cube_;
	cube_.Initialize(device);

	ShowWindow(hWnd, nCmdShow);

	do
	{
		if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)){ DispatchMessage(&msg); }
		
		cube_.Update(device);

		
		device->BeginScene();
		device->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(128, 128, 128), 1.0f, 0);

		cube_.Render(device);

		device->EndScene();
		device->Present(NULL, NULL, NULL, NULL);

	}while(msg.message != WM_QUIT);


	d3d->Release();
	device->Release();

	return 0;
}
// -----------------------------------------------------
// SkinCube.h
// -----------------------------------------------------
#pragma once
#define SAFE_RELEASE(a) if(a){ a->Release(); a = NULL; }
#define ROT(a) sinf(a) * 20 * 2 * 3.141592f / 180.0f

template<typename T>
class VertexBuffer
{
private:
	IDirect3DVertexBuffer9* vBuffer_;
	DWORD size_;
public:
	VertexBuffer() : vBuffer_(NULL), size_(-1){}
	~VertexBuffer(){ SAFE_RELEASE(vBuffer_); }

	void CreateVertexBuffer(IDirect3DDevice9* device, T* data, DWORD size, DWORD FVF)
	{
		size_ = sizeof(T) * size;
		if(FAILED(device->CreateVertexBuffer(size_, NULL, FVF, D3DPOOL_MANAGED, &vBuffer_, NULL))){
			throw;
		}
		void* p;
		if(FAILED(vBuffer_->Lock(0, size_, (void**)&p, NULL))){
			throw;
		}
		memcpy_s(p, size_, data, size_);
		vBuffer_->Unlock();
		
	}
	void SetStreamSource(IDirect3DDevice9* device, UINT StreamNumber, UINT OffsetInBytes)
	{
		device->SetStreamSource(StreamNumber, vBuffer_, OffsetInBytes, sizeof(T));
	}
};

template <typename T>
class IndexBuffer
{
private:
	IDirect3DIndexBuffer9* iBuffer_;
	DWORD size_;
public:
	IndexBuffer() : iBuffer_(NULL), size_(-1){}
	~IndexBuffer(){ SAFE_RELEASE(iBuffer_); }

	void CreateIndexBuffer(IDirect3DDevice9* device, T* data, DWORD size)
	{
		size_ = sizeof(T) * size;
		if(FAILED(device->CreateIndexBuffer(size_, D3DUSAGE_WRITEONLY, D3DFMT_INDEX16, D3DPOOL_MANAGED, &iBuffer_, NULL))){
			throw;
		}
		void* p;
		if(FAILED(iBuffer_->Lock(0, size_, (void**)&p, NULL))){
			throw;
		}
		memcpy_s(p, size_, data, size_);
		iBuffer_->Unlock();
	}
	void SetIndices(IDirect3DDevice9* device)
	{
		device->SetIndices(iBuffer_);
	}
};

class SkinCube
{
private:
	struct Coord{
		float x, y, z;
	};
	struct Weight{
		float weight1;
	};
	struct Color{
		DWORD color;
	};
private:
	IDirect3DVertexDeclaration9 *decl_;
	VertexBuffer<Coord> coordBuf_;
	VertexBuffer<Weight> weightBuf_;
	VertexBuffer<Color> colorBuf_;

	IndexBuffer<WORD> iBuffer_;
	DWORD num_vertex_;
	DWORD num_poly_;
	const DWORD FVF_;
	D3DXMATRIX mat_;
	D3DXVECTOR3 rot_;
public:
	SkinCube() 
		: FVF_(D3DFVF_XYZB1 | D3DFVF_DIFFUSE)
		, decl_(NULL)
		, num_vertex_(-1)
		, num_poly_(-1)
		{ rot_ = D3DXVECTOR3(0, 0, 0); }

	~SkinCube(){ SAFE_RELEASE(decl_); }

	void Initialize(IDirect3DDevice9* device)
	{
		D3DVERTEXELEMENT9 VertexElements[] ={
			{0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0}, //座標
			{1, 0, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BLENDWEIGHT, 0}, //ウェイト
			{2, 0, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0}, //カラー
			D3DDECL_END()
		};
		device->CreateVertexDeclaration( VertexElements, &decl_);

		Coord coord[] = {
			//box1
			-0.5f,  0.5f, 0.0f,
			 0.5f,  0.5f, 0.0f,
			 0.5f, -0.5f, 0.0f,
			-0.5f, -0.5f, 0.0f,
			
			-0.5f,  0.5f, 1.0f,
			 0.5f,  0.5f, 1.0f,
			 0.5f, -0.5f, 1.0f,
			-0.5f, -0.5f, 1.0f,
			
			//box2
			 1.5f,  0.5f, 0.0f,
			 1.5f,  0.5f, 1.0f,
			 1.5f, -0.5f, 1.0f,
			 1.5f, -0.5f, 0.0f,

			//box3
			 //2.0f,  0.5f, 0.0f,
			 //2.0f,  0.5f, 1.0f,
			 //2.0f, -0.5f, 1.0f,
			 //2.0f, -0.5f, 0.0f,
		};
		coordBuf_.CreateVertexBuffer(device, coord, sizeof(coord) / sizeof(coord[0]), D3DFVF_XYZ);
		num_vertex_ = sizeof(coord) / sizeof(coord[0]);
		Weight weight[] = 
		{
			//box1
			 0.0f,
			 0.0f,
			 0.0f,
			 0.0f,
			
			 0.0f,
			 0.0f,
			 0.0f,
			 0.0f,
			
			//box2
			 1.0f,
			 1.0f,
			 1.0f,
			 1.0f,

			//box3
			 //1.0f,
			 //1.0f,
			 //1.0f,
			 //1.0f,
		};
		weightBuf_.CreateVertexBuffer(device, weight, sizeof(weight) / sizeof(weight[0]), D3DFVF_DIFFUSE);

		Color color[] = 
		{
			//box1
			 0xffff0000,   // top 左上
			 0xffff0000,	// top 右上
			 0xffff0000,	// top 右下
			 0xffff0000,	// top 左下

			 0xffff0000,	// bot 左上
			 0xffff0000,	// bot 右上
			 0xffff0000,	// bot 右下
			 0xffff0000,	// bot 左下

			//box2
			 ~0,	// right 右上前
			 ~0,	// right 右上奥
			 ~0,	// right 右下奥
			 ~0, 	// right 右下前

			//box3
			//~0,	// right2 右上前
			//~0,	// right2 右上奥
			//~0,	// right2 右下奥
			//~0,	// right2 右下前
		};

		colorBuf_.CreateVertexBuffer(device, color, sizeof(color) / sizeof(color[0]), D3DFVF_DIFFUSE);

		WORD index[] = 
		{
			//box1
			0, 1, 3, 1, 2, 3,
			4, 5, 7, 5, 6, 7,	
			4, 0, 7, 0, 3, 7,
			1, 5, 2, 5, 6, 2,
			4, 5, 0, 5, 1, 0,
			7, 6, 3, 6, 2, 3,

			//box2
			1, 8, 2, 8, 11, 2,
			5, 9, 6, 9, 10, 6,
			5, 9, 1, 9, 8, 1,
			6, 10, 2, 10, 11, 2,
			8, 9, 11, 9, 10, 11,

			//box3
			//8, 12, 11, 12, 15, 11,
			//9, 13, 10, 13, 14, 10,
			//9, 13, 8, 13, 12, 8,
			//10, 14, 11, 14, 15, 11,
			//12, 13, 15, 13, 14, 15,
		};
		
		num_poly_ = (sizeof(index) / sizeof(index[0])) / 3;
		iBuffer_.CreateIndexBuffer(device, &index[0], sizeof(index) / sizeof(index[0]));

		device->SetRenderState( D3DRS_LIGHTING,         FALSE );
		device->SetRenderState( D3DRS_DITHERENABLE,     TRUE );
		device->SetRenderState( D3DRS_ZENABLE,          TRUE );
		device->SetRenderState( D3DRS_CULLMODE,         D3DCULL_NONE );
		device->SetRenderState( D3DRS_AMBIENT,          0x33333333 );
		device->SetRenderState( D3DRS_NORMALIZENORMALS, TRUE );
		device->SetRenderState( D3DRS_SRCBLEND,  D3DBLEND_SRCALPHA );
		device->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );
		device->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
		device->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR );
		device->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR );
		device->SetRenderState( D3DRS_VERTEXBLEND, D3DVBF_1WEIGHTS );
	}
	void Transform_(IDirect3DDevice9* device)
	{		
		//ビュー行列作成
		D3DXVECTOR3 vEyePt( 3.0f, 2.0f, -1.0f );
		D3DXVECTOR3 vLookatPt( 0.0f, 0.0f, 0.0f );
		D3DXVECTOR3 vUpVec( 0.0f, 1.0f, 0.0f );
		D3DXMATRIXA16 matView;
		D3DXMatrixLookAtLH( &matView, &vEyePt, &vLookatPt, &vUpVec );
		device->SetTransform( D3DTS_VIEW, &matView );
	
		//射影行列作成
		D3DXMATRIXA16 matProj;
		D3DXMatrixPerspectiveFovLH( &matProj, D3DXToRadian(90.0f), (float)640/480, 1.0f, 100.0f );
		device->SetTransform( D3DTS_PROJECTION, &matProj );
	}
	void Update(IDirect3DDevice9* device)
	{
		Transform_(device);
		D3DXMatrixIdentity(&mat_);
		D3DXMATRIX matRot; 
		D3DXMatrixIdentity(&matRot);

		rot_.x += 0.02f;
		rot_.y += 0.03f;
		rot_.z += 0.05f;
		D3DXMatrixRotationYawPitchRoll(&matRot, ROT(rot_.y), ROT(rot_.x), ROT(rot_.z));
		
		mat_ *= matRot;
		
	}
	void Render(IDirect3DDevice9* device)
	{
		device->SetTransform(D3DTS_WORLDMATRIX(0), &mat_);
		coordBuf_.SetStreamSource(device, 0, 0);
		weightBuf_.SetStreamSource(device, 1, 0);
		colorBuf_.SetStreamSource(device, 2, 0);
		device->SetVertexDeclaration(decl_);
		iBuffer_.SetIndices(device);

		
		device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, num_vertex_, 0, num_poly_);	
	}
};

参考
http://tyfkda.blogspot.jp/2011/12/webgl.html
http://rudora7.blog81.fc2.com/blog-entry-439.html
http://marupeke296.com/cgi-bin/cbbs/cbbs.cgi?mode=al2&namber=3637&rev=&no=0&P=R&KLOG=4
書き方は雑なので参考の方を見てね。