#include "StdAfx.h"
#include "SkinMesh.h"

namespace {
	const unsigned long palleteSize = 50;	// 行列パレットのサイズ
}

///// SkinMeshクラス /////
SkinMesh::SkinMesh(LPDIRECT3DDEVICE9 pDev) : pDevice(pDev), time(0), pFX(0), pMesh(0) {
}

SkinMesh::~SkinMesh(){
	SAFE_RELEASE(pFX);
	for (unsigned long i = 0; i < boneCombination.size(); ++i) delete[] boneCombination[i].BoneId;
	for (unsigned int i = 0; i < textures.size(); ++i) SAFE_RELEASE(textures[i]);
	SAFE_RELEASE(pMesh);
}

void SkinMesh::CreateMesh(const SkinMeshInitData& skinMeshInitData) {
	LPD3DXMESH pOrgMesh;
	D3DVERTEXELEMENT9 declAry[] = {
		{0, 0,  D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
		{0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BLENDWEIGHT, 0},
		{0, 24, D3DDECLTYPE_UBYTE4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BLENDINDICES, 0},
		{0, 28, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
		{0, 40, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
		D3DDECL_END()
	};
	unsigned int numFace = skinMeshInitData.faces.size();
	unsigned int numVertex = skinMeshInitData.blendVertices.size();
	D3DXCreateMesh(numFace, numVertex, D3DXMESH_MANAGED, declAry, pDevice, &pOrgMesh);
	BlendVertex* vertexBuffer;
	pOrgMesh->LockVertexBuffer(0, (void**)&vertexBuffer);
	for (unsigned int i = 0; i < numVertex; ++i) vertexBuffer[i] = skinMeshInitData.blendVertices[i];
	pOrgMesh->UnlockVertexBuffer();
	unsigned short* indexBuffer;
	pOrgMesh->LockIndexBuffer(0, (void**)&indexBuffer);
	for (unsigned int i = 0; i < numFace; ++i) for (unsigned int j = 0; j < 3; ++j) indexBuffer[3*i + j] = skinMeshInitData.faces[i].indices[j];
	pOrgMesh->UnlockIndexBuffer();
	unsigned long* attributeBuffer;
	pOrgMesh->LockAttributeBuffer(0, &attributeBuffer);
	for (unsigned int i = 0; i < numFace; ++i) attributeBuffer[i] = skinMeshInitData.faces[i].material_number;
	pOrgMesh->UnlockAttributeBuffer();
	for (unsigned int i = 0; i < skinMeshInitData.material.size(); ++i) {
		materials.push_back(skinMeshInitData.material[i]);
		textures.push_back(0);
		char tex_filename[256] = {0};		// UNICODE未対応テクスチャファイル名
		TCHAR textureFilename[256] = {0};	// UNICODE/マルチバイト両対応テクスチャファイル名
		if (strcpy_s(tex_filename, skinMeshInitData.texture_filename[i].c_str())) throw TEXT("テクスチャの読み込みに失敗しました");
#ifdef UNICODE
		if (strlen(tex_filename) > 0) MultiByteToWideChar(CP_OEMCP, MB_PRECOMPOSED, tex_filename, strlen(tex_filename), textureFilename, (sizeof textureFilename)/2);
#else
		if (strlen(tex_filename) > 0) strcpy_s(textureFilename, tex_filename);
#endif
		if (lstrlen(textureFilename) > 0) // UNICODE/マルチバイト両対応テクスチャファイル名からテクスチャを作成
			if(FAILED(D3DXCreateTextureFromFileEx(pDevice, textureFilename, 0, 0, 0, 0, D3DFMT_UNKNOWN, D3DPOOL_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 0xff000000, 0, 0, &textures[i]))) throw TEXT("テクスチャの読み込みに失敗しました");
	}
	LPD3DXSKININFO pSkinInfo = CreateSkinInfo(skinMeshInitData, declAry);
	DivideMesh(numFace, pOrgMesh, pSkinInfo);
	SAFE_RELEASE(pSkinInfo);
	SAFE_RELEASE(pOrgMesh);
}

LPD3DXSKININFO SkinMesh::CreateSkinInfo(const SkinMeshInitData& skinMeshInitData, const D3DVERTEXELEMENT9* declAry) {
	LPD3DXSKININFO pSkinInfo;
	unsigned long numVertex = skinMeshInitData.blendVertices.size();
	unsigned int size = skinMeshInitData.boneInitData.size();
	D3DXCreateSkinInfo(numVertex, declAry, size, &pSkinInfo);
	for (unsigned int i = 0; i < size; ++i) {
		unsigned long numInfluence = 0;								// ボーンiに影響する頂点の数
		unsigned long* vertices = new unsigned long[4*numVertex];	// ボーンiに影響する頂点の配列
		float* weights = new float[4*numVertex];					// ボーンiに影響する重みの配列
		for (unsigned long j = 0; j < numVertex; ++j) {
			for (unsigned int k = 0; k < 4; ++k) {
				if (skinMeshInitData.blendVertices[j].matrixIndex[k] == i) {
					vertices[numInfluence] = j;
					if (k < 3) weights[numInfluence] = skinMeshInitData.blendVertices[j].weight[k];
					else {
						weights[numInfluence] = 1.0;
						for (unsigned int l = 0; l < 3; ++l) weights[numInfluence] -= skinMeshInitData.blendVertices[j].weight[l];
					}
					++numInfluence;
				}
			}
		}
		if(FAILED(pSkinInfo->SetBoneInfluence(i, numInfluence, vertices, weights))) throw TEXT("SkinInfoの作成に失敗しました");;
		delete[] vertices;
		delete[] weights;
	}
	return pSkinInfo;
}

void SkinMesh::DivideMesh(unsigned int numFace, LPD3DXMESH pOrgMesh, LPD3DXSKININFO pSkinInfo) {
	unsigned long* pAdjacencyIn = new unsigned long[3*numFace];
	if (FAILED(pOrgMesh->GenerateAdjacency(0, pAdjacencyIn))) throw TEXT("隣接性情報の作成に失敗しました");
	unsigned long maxFaceInfl;
	unsigned long numBoneCombination;
	LPD3DXBUFFER pBoneCombinationBuffer = 0;
	if(FAILED(pSkinInfo->ConvertToIndexedBlendedMesh(pOrgMesh, 0, palleteSize, pAdjacencyIn, 0, 0, 0, &maxFaceInfl, &numBoneCombination, &pBoneCombinationBuffer, &pMesh))) throw TEXT("メッシュの分割に失敗しました");
	LPD3DXBONECOMBINATION bc = (LPD3DXBONECOMBINATION)pBoneCombinationBuffer->GetBufferPointer();
	for (unsigned long i = 0; i < numBoneCombination; ++i) boneCombination.push_back(bc[i]);
	for (unsigned long i = 0; i < numBoneCombination; ++i) {
		boneCombination[i].BoneId = new unsigned long[palleteSize];
		memcpy(boneCombination[i].BoneId, bc[i].BoneId, palleteSize*sizeof(unsigned long));	 // ディープコピー
	}
	delete[] pAdjacencyIn;
	pBoneCombinationBuffer->Release();
}

void SkinMesh::CreateBoneMatrix(const SkinMeshInitData& skinMeshInitData) {
	bones.resize(skinMeshInitData.boneInitData.size());
	combMat.resize(bones.size());
	for (unsigned int i = 0; i < bones.size(); i++) {
		bones[i].combMatAry = &combMat[0];
		bones[i].id = i;
		int f = skinMeshInitData.boneInitData[i].firstChildIdx;
		if (f != -1) bones[i].firstChild = &bones[f];
		int s = skinMeshInitData.boneInitData[i].siblingIdx;
		if (s != -1) bones[i].sibling = &bones[s];
		bones[i].initMat = skinMeshInitData.boneInitData[i].initMat;
		bones[i].visible = skinMeshInitData.boneInitData[i].visible;
		bones[i].length = skinMeshInitData.boneInitData[i].length;
	}
	for (unsigned int i = 0; i < bones.size(); i++) D3DXMatrixInverse(&bones[i].offsetMat, 0, &bones[i].initMat); // ボーンオフセット行列(初期姿勢(ローカル座標)の逆行列)の入力
	ConvertInitMatrixInParent(&bones[0], 0);
}

void SkinMesh::ConvertInitMatrixInParent(Bone* me, D3DXMATRIX *parentoffsetMat) {
	if (me->firstChild) ConvertInitMatrixInParent(me->firstChild, &me->offsetMat);
	if (me->sibling)	ConvertInitMatrixInParent(me->sibling, parentoffsetMat);
	if (parentoffsetMat) me->initMat *= *parentoffsetMat;
}

void SkinMesh::CreateShader() {
	LPD3DXBUFFER errors = 0;
	HRESULT res = D3DXCreateEffectFromFile(pDevice, TEXT("Shader.fx"), 0, 0, 0, 0, &pFX, &errors);
	if (FAILED(res)) {
		OutputDebugStringA((const char*)errors->GetBufferPointer());
		throw TEXT("シェーダのコンパイルに失敗しました");
	}
	hTech = pFX->GetTechniqueByName("BlendTech");
	hWorld = pFX->GetParameterByName(0, "world");
	hView = pFX->GetParameterByName(0, "view");
	hProj = pFX->GetParameterByName(0, "proj");
	hAmbient = pFX->GetParameterByName(0, "ambient");
	hDiffuse = pFX->GetParameterByName(0, "diffuse");
	hLightDir = pFX->GetParameterByName(0, "lightDir");
	hTexture = pFX->GetParameterByName(0, "tex");
	if (!hTech || !hWorld || !hView || !hProj || !hAmbient || !hDiffuse || !hLightDir || !hTexture) throw TEXT("シェーダファイルに指定した変数名がみつかりませんでした");
}

void SkinMesh::AdvanceTime() { ++time; }

void SkinMesh::UpdateBoneMatrix() {
	D3DXMATRIX* defBone = new D3DXMATRIX[bones.size()];	// 初期配置からの差分
	for (unsigned int i = 0; i < bones.size(); i++) D3DXMatrixIdentity(&defBone[i]);
	//一部のボーンを単振動させる
	D3DXMatrixRotationZ(&defBone[3], D3DXToRadian(sinf(0.1f*time) * 2.0f));			
	D3DXMatrixRotationX(&defBone[5], D3DXToRadian(sinf(0.1f*time) * 20.0f + 5.0f));
	D3DXMatrixRotationX(&defBone[6], D3DXToRadian(-abs(sinf(0.1f*time) * 10.0f)));
	D3DXMatrixRotationX(&defBone[13], D3DXToRadian(-sinf(0.1f*time) * 20.0f + 5.0f));
	D3DXMatrixRotationX(&defBone[14], D3DXToRadian(-abs(sinf(0.1f*time) * 10.0f)));
	D3DXMatrixRotationZ(&defBone[22], D3DXToRadian(sinf(0.1f*time) * 5.0f));
	D3DXMatrixRotationX(&defBone[23], D3DXToRadian(sinf(0.05f*time) * 5.0f - 10.0f));
	for (unsigned int i = 0; i < bones.size(); i++) bones[i].boneMat = defBone[i]*bones[i].initMat;	// 親ボーン座標系に変換
	delete defBone;
}


void SkinMesh::ConvertBoneMatrixInWorld(Bone* me, D3DXMATRIX *parentWorldMat) {
	me->boneMat *= *parentWorldMat;
	me->combMatAry[me->id] = me->offsetMat * me->boneMat;
	if (me->firstChild) ConvertBoneMatrixInWorld(me->firstChild, &me->boneMat);
	if (me->sibling)	ConvertBoneMatrixInWorld(me->sibling, parentWorldMat);
}

void SkinMesh::Draw(D3DXVECTOR3* position, D3DXMATRIX* rotation, D3DLIGHT9* light, Camera* camera) {
	UpdateBoneMatrix();
	D3DXMATRIX trans, world;
	D3DXMatrixTranslation(&trans, position->x, position->y, position->z);
	world = (*rotation)*trans;
	ConvertBoneMatrixInWorld(&bones[0], &world);

	// カメラとライト
	D3DXMATRIX view, projection;
	camera->GetMatrix(&view, &projection);
	D3DXVECTOR3 lightDir = light->Direction;

	////// プログラマブルシェーダ設定
	pFX->SetTechnique(hTech);
	pFX->SetMatrix(hView, &view);
	pFX->SetMatrix(hProj, &projection);
	pFX->SetFloatArray(hLightDir, (const float*)&lightDir, 3);

	// 描画
	pFX->Begin(0, 0);
	for (unsigned long i = 0; i < boneCombination.size(); ++i) {
		unsigned long numBlendMatrix = 0;
		for (unsigned long k = 0; k < palleteSize; ++k) if (boneCombination[i].BoneId[k] != UINT_MAX) numBlendMatrix = k + 1;
		vector<D3DXMATRIX> selectedCombMat;
		for (unsigned long k = 0; k < numBlendMatrix; ++k) selectedCombMat.push_back(combMat[boneCombination[i].BoneId[k]]);
		pFX->SetMatrixArray(hWorld, &selectedCombMat[0], numBlendMatrix);
		pFX->SetFloatArray(hAmbient, (const float*)&materials[boneCombination[i].AttribId].Ambient, 4);
		pFX->SetFloatArray(hDiffuse, (const float*)&materials[boneCombination[i].AttribId].Diffuse, 4);
		pFX->SetTexture(hTexture, textures[boneCombination[i].AttribId]);
		if (textures[boneCombination[i].AttribId]) pFX->BeginPass(0);
		else pFX->BeginPass(1);
		pMesh->DrawSubset(i);
		pFX->EndPass();
	}
	pFX->End();
}

void SkinMesh::CreateBoneObj(const SkinMeshInitData& skinMeshInitData) {
	boneObj.resize(bones.size());
	for (unsigned int i = 0; i < bones.size(); i++ )	D3DXCreateCylinder(pDevice, 0.01f, 0, skinMeshInitData.boneInitData[i].length, 5, 1, &boneObj[i], 0);
}

void SkinMesh::DrawBoneObj(D3DXVECTOR3* position, D3DXMATRIX* rotation, D3DLIGHT9* light, Camera* camera) {
	D3DMATERIAL9 material = {{0.0f, 0.0f, 1.0f, 1.0f}}; material.Power = 10.0f;
	D3DXMATRIX trans, world;
	D3DXMatrixTranslation(&trans, position->x, position->y, position->z);
	world = (*rotation)*trans;
	D3DXMATRIX view, projection;
	camera->GetMatrix(&view, &projection);
	pDevice->SetLight(0, light);
	pDevice->LightEnable(0, TRUE) ;
	pDevice->SetRenderState(D3DRS_LIGHTING, TRUE);
	pDevice->SetMaterial(&material);
	pDevice->SetRenderState(D3DRS_ZENABLE, FALSE);
	pDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);
	pDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);
	pDevice->SetVertexShader(0);
	pDevice->SetPixelShader(0);
	pDevice->SetTransform(D3DTS_VIEW, &view);
	pDevice->SetTransform(D3DTS_PROJECTION, &projection);
	D3DXMATRIX boneObjRot, boneObjTrans;
	D3DXMatrixIdentity(&boneObjRot);
	for (unsigned int i = 0; i < bones.size(); ++i) {
		D3DXMatrixTranslation(&boneObjTrans, 0, 0, bones[i].length/2.0f);
		pDevice->SetTransform(D3DTS_WORLD, &(boneObjRot*boneObjTrans*bones[i].boneMat));
		if (bones[i].visible) boneObj[i]->DrawSubset(0);
	}
	pDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
	pDevice->SetRenderState( D3DRS_ZENABLE, TRUE);
}

HandMadeSkinMesh::HandMadeSkinMesh(LPDIRECT3DDEVICE9 pDevice) : SkinMesh(pDevice) {
	SkinMeshInitData skinMeshInitData;
	CreateSkinMeshData(skinMeshInitData);
	CreateMesh(skinMeshInitData);
	CreateBoneMatrix(skinMeshInitData);
	CreateBoneObj(skinMeshInitData);
	CreateShader();
}



///// 自作スキンメッシュデータ /////
void HandMadeSkinMesh::CreateSkinMeshData(SkinMeshInitData& skinMeshInitData) {
	const int numVtx = 15;
	const BlendVertex vtx[numVtx] = {
		{ D3DXVECTOR3(-0.5000f, -2.2887f, 0.0f), 1.00f, 0.00f, 0.00f, {2, 0, 0, 0}, D3DXVECTOR3(0, 0, 1.0f), D3DXVECTOR2(0.4f, 0) },
		{ D3DXVECTOR3(-0.5000f, -1.2887f, 0.0f), 0.50f, 0.50f, 0.00f, {1, 2, 0, 0}, D3DXVECTOR3(0, 0, 1.0f), D3DXVECTOR2(0.4f, 0.25f) },
		{ D3DXVECTOR3(-0.5000f, -0.2887f, 0.0f), 1.00f, 0.00f, 0.00f, {0, 0, 0, 0}, D3DXVECTOR3(0, 0, 1.0f), D3DXVECTOR2(0.4f, 0.5f) },
		{ D3DXVECTOR3(-1.3660f,  0.2113f, 0.0f), 0.50f, 0.50f, 0.00f, {3, 4, 0, 0}, D3DXVECTOR3(0, 0, 1.0f), D3DXVECTOR2(0.2f, 0.75f) },
		{ D3DXVECTOR3(-2.2321f,  0.7113f, 0.0f), 1.00f, 0.00f, 0.00f, {4, 0, 0, 0}, D3DXVECTOR3(0, 0, 1.0f), D3DXVECTOR2(0, 0.8f) },
		{ D3DXVECTOR3(-1.7321f,  1.5774f, 0.0f), 1.00f, 0.00f, 0.00f, {4, 0, 0, 0}, D3DXVECTOR3(0, 0, 1.0f), D3DXVECTOR2(0, 1) },
		{ D3DXVECTOR3(-0.8660f,  1.0774f, 0.0f), 0.50f, 0.50f, 0.00f, {3, 4, 0, 0}, D3DXVECTOR3(0, 0, 1.0f), D3DXVECTOR2(0.2f, 0.8f) },
		{ D3DXVECTOR3( 0.0000f,  0.5774f, 0.0f), 1.00f, 0.00f, 0.00f, {0, 0, 0, 0}, D3DXVECTOR3(0, 0, 1.0f), D3DXVECTOR2(0.5f, 0.75f) },
		{ D3DXVECTOR3( 0.8660f,  1.0774f, 0.0f), 0.50f, 0.50f, 0.00f, {5, 6, 0, 0}, D3DXVECTOR3(0, 0, 1.0f), D3DXVECTOR2(0.8f, 0.8f) },
		{ D3DXVECTOR3( 1.7321f,  1.5774f, 0.0f), 1.00f, 0.00f, 0.00f, {6, 0, 0, 0}, D3DXVECTOR3(0, 0, 1.0f), D3DXVECTOR2(1, 1) },
		{ D3DXVECTOR3( 2.2321f,  0.7113f, 0.0f), 1.00f, 0.00f, 0.00f, {6, 0, 0, 0}, D3DXVECTOR3(0, 0, 1.0f), D3DXVECTOR2(1, 0.8f) },
		{ D3DXVECTOR3( 1.3660f,  0.2113f, 0.0f), 0.50f, 0.50f, 0.00f, {5, 6, 0, 0}, D3DXVECTOR3(0, 0, 1.0f), D3DXVECTOR2(0.8f, 0.75f) },
		{ D3DXVECTOR3( 0.5000f, -0.2887f, 0.0f), 1.00f, 0.00f, 0.00f, {0, 0, 0, 0}, D3DXVECTOR3(0, 0, 1.0f), D3DXVECTOR2(0.6f, 0.5f) },
		{ D3DXVECTOR3( 0.5000f, -1.2887f, 0.0f), 0.50f, 0.50f, 0.00f, {1, 2, 0, 0}, D3DXVECTOR3(0, 0, 1.0f), D3DXVECTOR2(0.6f, 0.25f) },
		{ D3DXVECTOR3( 0.5000f, -2.2887f, 0.0f), 1.00f, 0.00f, 0.00f, {2, 0, 0, 0}, D3DXVECTOR3(0, 0, 1.0f), D3DXVECTOR2(0.6f, 0) }
	};
	const int numIdx = 13;
	const Face face[numIdx] = {
		{{0, 1, 14}, 0},
		{{1, 13, 14}, 0},
		{{1, 2, 13}, 0},
		{{2, 12, 13}, 0},
		{{2, 7, 12}, 0},
		{{2, 6, 7}, 0},
		{{2, 3, 6}, 0},
		{{3, 5, 6}, 0},
		{{3, 4, 5}, 0},
		{{7, 8, 12}, 0},
		{{8, 11, 12}, 0},
		{{8, 9, 11}, 0},
		{{9, 10, 11}, 0}
	};
	const int numMtl = 1;
	const D3DMATERIAL9 material[numMtl] = {{{1, 1, 1, 1}, {0.3f, 0.3f, 0.3f, 1}}};
	const char* texture_filename[numMtl] = {"tex_test.bmp"};
	const int numBon = 7;
	const int firstChildIdx[numBon] = {1, 2, -1, 4, -1, 6, -1};
	const int siblingIdx[numBon] = {-1, 3, -1, 5, -1, -1, -1};
	const float length[numBon] = {1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f};
	D3DXMATRIX initMat[numBon];
	for (int i = 0; i < numVtx; ++i) {
		skinMeshInitData.blendVertices.push_back(vtx[i]);
		Vertex normal_vertex;
		normal_vertex.position = vtx[i].position;
		normal_vertex.normal = vtx[i].normal;
		normal_vertex.texture = vtx[i].texture;
		skinMeshInitData.vertices.push_back(normal_vertex);
	}
	for (int i = 0; i < numIdx; ++i) skinMeshInitData.faces.push_back(face[i]);
	for (int i = 0; i < numMtl; ++i) skinMeshInitData.material.push_back(material[i]);
	for (int i = 0; i < numMtl; ++i) skinMeshInitData.texture_filename.push_back(texture_filename[i]);
	CreateInitMat(initMat);
	for (int i = 0; i < numBon; ++i) {
		BoneInitData boneInitData;
		boneInitData.firstChildIdx = firstChildIdx[i];
		boneInitData.siblingIdx = siblingIdx[i];
		boneInitData.initMat = initMat[i];
		boneInitData.length = length[i];
		skinMeshInitData.boneInitData.push_back(boneInitData);
	}
}

void HandMadeSkinMesh::CreateInitMat(D3DXMATRIX* initMat) {
	D3DXMatrixRotationZ(&initMat[0], D3DXToRadian(-90.0f));
	D3DXMatrixRotationZ(&initMat[1], D3DXToRadian(-90.0f));
	D3DXMatrixRotationZ(&initMat[2], D3DXToRadian(-90.0f));
	D3DXMatrixRotationZ(&initMat[3], D3DXToRadian(150.0f));
	D3DXMatrixRotationZ(&initMat[4], D3DXToRadian(150.0f));
	D3DXMatrixRotationZ(&initMat[5], D3DXToRadian( 30.0f));
	D3DXMatrixRotationZ(&initMat[6], D3DXToRadian( 30.0f));
	initMat[0]._41 =  0.0000f; initMat[0]._42 =  0.0000f;
	initMat[1]._41 =  0.0000f; initMat[1]._42 = -1.0000f;
	initMat[2]._41 =  0.0000f; initMat[2]._42 = -2.0000f;
	initMat[3]._41 = -0.6830f; initMat[3]._42 =  0.3943f;
	initMat[4]._41 = -1.5490f; initMat[4]._42 =  0.8943f;
	initMat[5]._41 =  0.6830f; initMat[5]._42 =  0.3943f;
	initMat[6]._41 =  1.5490f; initMat[6]._42 =  0.8943f;
}




///// PmdSkinMeshクラス /////
PmdSkinMesh::PmdSkinMesh(LPCTSTR filename, LPDIRECT3DDEVICE9 pDev) : SkinMesh(pDev) , scaleToDirectX(0.1f) {
	// PMDファイルからPMDデータを抽出
    ifstream ifs(filename, ios::binary);
	if (ifs.fail()) throw TEXT("ファイルがありません");
	PmdStruct::PmdHeader pmdHeader;
	ifs.read((char*)&pmdHeader, sizeof(pmdHeader));
	unsigned long numPmdVertex;
	ifs.read((char*)&numPmdVertex, sizeof(numPmdVertex));
	PmdStruct::PmdVertex* pmdVertices = new PmdStruct::PmdVertex[numPmdVertex];
	ifs.read((char*)pmdVertices, sizeof(PmdStruct::PmdVertex)*numPmdVertex);
	unsigned long numPmdFace;
	ifs.read((char*)&numPmdFace, sizeof(numPmdFace));
	unsigned short *pmdFaces = new unsigned short[numPmdFace];
	ifs.read((char*)pmdFaces, sizeof(unsigned short)*numPmdFace);
	unsigned long numPmdMaterial;
	ifs.read((char*)&numPmdMaterial, sizeof(numPmdMaterial));
	PmdStruct::PmdMaterial* pmdMaterial = new PmdStruct::PmdMaterial[numPmdMaterial];
	ifs.read((char*)pmdMaterial, sizeof(PmdStruct::PmdMaterial)*numPmdMaterial);
	unsigned short numPmdBone;
	ifs.read((char*)&numPmdBone, sizeof(numPmdBone));
	PmdStruct::PmdBone* pmdBone = new PmdStruct::PmdBone[numPmdBone];
	ifs.read((char*)pmdBone, sizeof(PmdStruct::PmdBone)*numPmdBone);

	// PMDデータからSkinMeshInitDataにコピー
	SkinMeshInitData skinMeshInitData;
	for (unsigned int i = 0; i < numPmdVertex; ++i) {
		Vertex v;
		v.position = D3DXVECTOR3(pmdVertices[i].pos[0], pmdVertices[i].pos[1], pmdVertices[i].pos[2]);
		v.position *= scaleToDirectX;			// DirectXのスケールに合わせる!
		v.normal= D3DXVECTOR3(pmdVertices[i].normal_vec[0], pmdVertices[i].normal_vec[1], pmdVertices[i].normal_vec[2]);
		v.texture = D3DXVECTOR2(pmdVertices[i].uv[0], pmdVertices[i].uv[1]);
		skinMeshInitData.vertices.push_back(v);

		BlendVertex bv;
		bv.position = v.position;
		bv.normal = v.normal;
		bv.texture = v.texture;
		bv.weight[0] = (float)pmdVertices[i].bone_weight/100.0f;
		bv.weight[1] = 1.0f - bv.weight[0];
		bv.weight[2] = 0;		// これがないとメッシュ分割に失敗する！
		bv.matrixIndex[0] = (unsigned char)pmdVertices[i].bone_num[0];
		bv.matrixIndex[1] = (unsigned char)pmdVertices[i].bone_num[1];
		bv.matrixIndex[2] = 0;	// これがないとメッシュ分割に失敗する！
		bv.matrixIndex[3] = 0;	// これがないとメッシュ分割に失敗する！
		skinMeshInitData.blendVertices.push_back(bv);
	}
	delete pmdVertices;

	Face f;
	for (unsigned int i = 0; i < numPmdFace; ++i) {
		f.indices[i%3] = pmdFaces[i];
		if (i%3 == 2) skinMeshInitData.faces.push_back(f);
	}
	delete pmdFaces;
	
	D3DMATERIAL9 material = {0};
	unsigned int j = 0, material_end = 0;
	for (unsigned int i = 0; i < numPmdMaterial; ++i) {
		CopyMaterial(material, pmdMaterial[i]);
		skinMeshInitData.material.push_back(material);
		char tex[21] = {0};	// ファイル名が20byteのときのために最後に0を追加
		memcpy(tex, pmdMaterial[i].texture_file_name, 20);
		string s(tex);
		s = s.substr(0, s.find("*"));	// temp
		skinMeshInitData.texture_filename.push_back(s);
		material_end += pmdMaterial[i].face_vert_count;
		for (; j < material_end; ++j) skinMeshInitData.faces[j/3].material_number = i;
	}
	delete pmdMaterial;

	for (unsigned int i = 0; i < numPmdBone; ++i) {
		BoneInitData boneInitData;
		for (unsigned int j = i + 1; j < numPmdBone; ++j) {
			if (pmdBone[i].parent_bone_index == pmdBone[j].parent_bone_index) {
				boneInitData.siblingIdx = j;
				break;
			}
		}
		for (unsigned int j = 0; j < numPmdBone; ++j) {
			if (i == pmdBone[j].parent_bone_index) {
				boneInitData.firstChildIdx = j;
				break;
			}
		}
		CreateInitMat(pmdBone, i, &boneInitData.initMat, &boneInitData.length);
		if (pmdBone[i].bone_type == 7) boneInitData.visible = false;
		skinMeshInitData.boneInitData.push_back(boneInitData);
	}
	delete pmdBone;

	CreateMesh(skinMeshInitData);
	CreateBoneMatrix(skinMeshInitData);
	CreateBoneObj(skinMeshInitData);
	CreateShader();
}

void PmdSkinMesh::CreateInitMat(const PmdStruct::PmdBone* pmdBone, unsigned int i, D3DXMATRIX* initMat, float* length) {
		D3DXVECTOR3 pos(pmdBone[i].bone_head_pos[0], pmdBone[i].bone_head_pos[1], pmdBone[i].bone_head_pos[2]);	// ボーンの位置
		pos *= scaleToDirectX;				// DirectXのスケールに合わせる!
		PmdStruct::PmdBone tail = pmdBone[pmdBone[i].tail_pos_bone_index];							// ボーンテイル
		D3DXVECTOR3 tail_pos(tail.bone_head_pos[0], tail.bone_head_pos[1], tail.bone_head_pos[2]);	// ボーンテイルの位置
		tail_pos *= scaleToDirectX;			// DirectXのスケールに合わせる!
		D3DXVECTOR3 dir = tail_pos - pos;	// ボーンの向き
		*length = D3DXVec3Length(&dir);
		D3DXVec3Normalize(&dir, &dir);
		D3DXMATRIX rotation;				// ボーン回転行列(Z軸をdirにあわせる回転)
		D3DXVECTOR3 z(0, 0, 1);				// z軸ベクトル
		D3DXVECTOR3 n;						// 回転軸
		D3DXMatrixRotationAxis(&rotation, D3DXVec3Cross(&n, &z, &dir), acos(D3DXVec3Dot(&z, &dir)));
		D3DXMATRIX translation;				// ボーン平行移動行列
		D3DXMatrixTranslation(&translation, pos.x, pos.y, pos.z);
		*initMat = rotation*translation;
}

void PmdSkinMesh::CopyMaterial(D3DMATERIAL9& material, const PmdStruct::PmdMaterial& pmdMaterial) {
	const float damp = 0.8f;	// アンビエントを弱くする係数
	material.Ambient.a = pmdMaterial.alpha;
	material.Ambient.r = damp*pmdMaterial.mirror_color[0];
	material.Ambient.g = damp*pmdMaterial.mirror_color[1];
	material.Ambient.b = damp*pmdMaterial.mirror_color[2];
	material.Diffuse.a = pmdMaterial.alpha;
	material.Diffuse.r = pmdMaterial.diffuse_color[0];
	material.Diffuse.g = pmdMaterial.diffuse_color[1];
	material.Diffuse.b = pmdMaterial.diffuse_color[2];
	material.Power = pmdMaterial.specularity;
	material.Specular.a = pmdMaterial.alpha;
	material.Specular.r = pmdMaterial.specular_color[0];
	material.Specular.g = pmdMaterial.specular_color[1];
	material.Specular.b = pmdMaterial.specular_color[2];
}
