////////////////////////////////////////////////////////
// filename: ChaColliderObject.cpp
// author: Chafumi Touji
// version: 1.0.0
// date: 2020/03/08
////////////////////////////////////////////////////////

#include "defcha3dcore.h"

////////////////////////////////////////////////////////////

CColliderPolygonData::CColliderPolygonData() {

	wmemset(VertexID, 0, SIZE_CHAR_MAX);
	wmemset(NormalID, 0, SIZE_CHAR_MAX);
	VertexIndex = new CVector(sizeof(int32_t));
	NormalIndex = new CVector(sizeof(int32_t));
	VertexBuffer = NULL;
	VertexBufferView = NULL;
}

CColliderPolygonData::~CColliderPolygonData() {

	delete VertexIndex;
	delete NormalIndex;
	VertexIndex = NULL;
	NormalIndex = NULL;

	SAFE_RELEASE(VertexBuffer);
	delete VertexBufferView;
	VertexBufferView = NULL;
}

///////////////////////////////////////////////////////////////

CColliderGeometry::CColliderGeometry() {

	wmemset(GeometryID, 0, SIZE_CHAR_MAX);
	VertexCount = 0;
	VecFloatArray = new CVector(sizeof(int64_t));
	PolygonData = new CVector(sizeof(int64_t));
	BindShapeMatrix = XMMatrixIdentity();
	Weights = NULL;
	WeightCount = 0;
	VertexIndexCount = 0;
	memset(&ColliderPos[0], 0, sizeof(CColliderVertex));
	memset(&ColliderPos[1], 0, sizeof(CColliderVertex));
	memset(&TransformedColliderPos[0], 0, sizeof(CColliderVertex));
	memset(&TransformedColliderPos[1], 0, sizeof(CColliderVertex));
	Buffer = NULL;
	TransformedBuffer = NULL;
	DataType = DATA_TYPE_ORIGINAL;
}

CColliderGeometry::~CColliderGeometry() {

	if (DataType == DATA_TYPE_ORIGINAL) {
		for (int i = 0; i <= VecFloatArray->PushPos - 1; i++) {
			CFloatArray* data = *(CFloatArray**)VecFloatArray->GetData(i);
			delete data;
			data = NULL;
		}
		for (int i = 0; i <= PolygonData->PushPos - 1; i++) {
			CColliderPolygonData* data = *(CColliderPolygonData**)PolygonData->GetData(i);
			delete data;
			data = NULL;
		}
		if (Weights != NULL) {
			for (int i = 0; i <= WeightCount - 1; i++) {
				for (int j = 0; j <= WEIGHT_BONE_APPLY_NUM - 1; j++) {
					delete[] Weights[i][j];
					Weights[i][j] = NULL;
				}
				delete[] Weights[i];
				Weights[i] = NULL;
			}
			delete[] Weights;
			Weights = NULL;
		}

		if (Buffer != NULL) {
			delete[] Buffer;
			delete[] TransformedBuffer;
			Buffer = NULL;
			TransformedBuffer = NULL;
		}
	}
	else if (DataType == DATA_TYPE_COPY && TransformedBuffer != NULL) {
		delete[] TransformedBuffer;
		TransformedBuffer = NULL;
	}
}

CFloatArray* CColliderGeometry::GetFloatArray(wchar_t* id) {

	for (int i = 0; i <= VecFloatArray->PushPos - 1; i++) {
		if (wcscmp((*(CFloatArray**)VecFloatArray->GetData(i))->ID, id) == 0)
			return *(CFloatArray**)VecFloatArray->GetData(i);
	}

	return NULL;
}

/////////////////////////////////////////////////////////////////////

CChaColliderObject::CChaColliderObject() {

	wmemset(ModelID, 0, SIZE_CHAR_MAX);
	ColliderGeometry = new CVector(sizeof(int64_t));
	ResourceOrigin = NULL;
	ResManager = NULL;

	m_pConstantBufferCollider = NULL;
	constant_buffer_collider_begin = 0;
	constant_buffer_collider_num = 0;

	m_pConstantBufferColliderParam = NULL;
	constant_buffer_collider_param_begin = 0;
	constant_buffer_collider_param_num = 0;

	CenterPos = XMFLOAT4(0, 0, 0, 0);
	Length = 0.0f;
}

CChaColliderObject::~CChaColliderObject() {

	if (m_pConstantBufferCollider != NULL) {
		m_pConstantBufferCollider->Unmap(0, NULL);
		SAFE_RELEASE(m_pConstantBufferCollider);
		m_pConstantBufferCollider = NULL;
	}

	if (ResManager != NULL) {
		ResManager->FreeResourceNum(constant_buffer_collider_num);
	}

	if (m_pConstantBufferColliderParam != NULL) {
		m_pConstantBufferColliderParam->Unmap(0, NULL);
		SAFE_RELEASE(m_pConstantBufferColliderParam);
		m_pConstantBufferColliderParam = NULL;
	}

	if (ResManager != NULL) {
		ResManager->FreeResourceNum(constant_buffer_collider_param_num);
	}

	for (int i = 0; i <= ColliderGeometry->PushPos - 1; i++) {
		CColliderGeometry* gmt = *(CColliderGeometry**)ColliderGeometry->GetData(i);
		delete gmt;
		gmt = NULL;
	}

	delete ColliderGeometry;
	ColliderGeometry = NULL;
}

bool CChaColliderObject::LoadCollider(const wchar_t* filename) {

	//Colliderモデルファイルを読み込む。

	FILE* fp = NULL;

	wchar_t out_file_name[SIZE_CHAR_MAX];
	wmemset(out_file_name, 0, SIZE_CHAR_MAX);
	wcscpy_s(out_file_name, SIZE_CHAR_MAX, filename);

	_wfopen_s(&fp, out_file_name, L"r");

	if (fp == NULL)
		return false;

	CColliderGeometry* gmt = NULL;
	CFloatArray* float_array = NULL;
	CColliderPolygonData* pgn_data = NULL;

	char* ctx = NULL;
	wchar_t w_line[SIZE_CHAR_MAX];
	char line[SIZE_CHAR_MAX];
	char param1[SIZE_CHAR_MAX];
	char param2[SIZE_CHAR_MAX];
	int mode = READ_MODE_INIT;
	size_t size;
	while (fgetws(w_line, SIZE_CHAR_MAX, fp) != NULL) {

		wcstombs_s(&size, line, w_line, SIZE_CHAR_MAX);
		memset(param1, 0, SIZE_CHAR_MAX);
		memset(param2, 0, SIZE_CHAR_MAX);
		GetParam(line, param1, param2, " []<>\n");

		if (strcmp(param1, "MODEL_ID") == 0) {
			fgetws(w_line, SIZE_CHAR_MAX, fp);
			wcstombs_s(&size, line, w_line, SIZE_CHAR_MAX);
			GetParam(line, param1, param2, " \n");
			mbstowcs_s(&size, ModelID, param1, SIZE_CHAR_MAX);

			continue;
		}
		if (strcmp(param1, "GEOMETRY_BEGIN") == 0) {

			//ジオメトリをロード

			gmt = new CColliderGeometry();

			while (fgetws(w_line, SIZE_CHAR_MAX, fp) != NULL) {

				wcstombs_s(&size, line, w_line, SIZE_CHAR_MAX);
				memset(param1, 0, SIZE_CHAR_MAX);
				memset(param2, 0, SIZE_CHAR_MAX);
				GetParam(line, param1, param2, " []<>\n");

				if (strcmp(param1, "GEOMETRY_ID") == 0)
					mbstowcs_s(&size, gmt->GeometryID, param2, SIZE_CHAR_MAX);
				if (strcmp(param1, "VERTEX_COUNT") == 0)
					gmt->VertexCount = atoi(param2);
				if (strcmp(param1, "BIND_SHAPE_MATRIX") == 0) {
					char tmp_line[FLOAT_STRING_SIZE * 16];
					memset(tmp_line, 0, FLOAT_STRING_SIZE * 16);
					fgets(tmp_line, FLOAT_STRING_SIZE * 16, fp);

					float m[16];
					memset(m, 0, sizeof(float) * 16);
					char* tmp = strtok_s(tmp_line, " \n", &ctx);
					m[0] = (float)atof(tmp);
					for (int i = 1; i <= 15; i++) {
						tmp = strtok_s(NULL, " \n", &ctx);
						m[i] = (float)atof(tmp);
					}
					gmt->BindShapeMatrix = XMMATRIX(m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8], m[9], m[10], m[11], m[12], m[13], m[14], m[15]);
				}
				if (strcmp(param1, "COLLIDER_TYPE") == 0) {
					wchar_t type[SIZE_CHAR_MAX];
					wmemset(type, 0, SIZE_CHAR_MAX);
					mbstowcs_s(&size, type, param2, SIZE_CHAR_MAX);
					if (wcscmp(type, L"COLLIDER_TYPE_SPHERE") == 0)
						gmt->ColliderType = COLLIDER_TYPE_SPHERE;
					else if (wcscmp(type, L"COLLIDER_TYPE_BOX") == 0)
						gmt->ColliderType = COLLIDER_TYPE_BOX;
					else if (wcscmp(type, L"COLLIDER_TYPE_CAPSULE") == 0)
						gmt->ColliderType = COLLIDER_TYPE_CAPSULE;
					else if (wcscmp(type, L"COLLIDER_TYPE_RECT") == 0)
						gmt->ColliderType = COLLIDER_TYPE_RECT;
					else if (wcscmp(type, L"COLLIDER_TYPE_MESH") == 0)
						gmt->ColliderType = COLLIDER_TYPE_MESH;
					else
						gmt->ColliderType = COLLIDER_TYPE_UNKNOWN;
				}
				if (strcmp(param1, "R") == 0) {
					gmt->R = (float)atof(param2);
				}
				if (strcmp(param1, "FLOAT_ARRAY_BEGIN") == 0) {

					//バーテックス値をロード

					float_array = new CFloatArray();
					int float_count = -1;
					int vertex_count = -1;

					while (fgetws(w_line, SIZE_CHAR_MAX, fp) != NULL) {

						wcstombs_s(&size, line, w_line, SIZE_CHAR_MAX);
						memset(param1, 0, SIZE_CHAR_MAX);
						memset(param2, 0, SIZE_CHAR_MAX);
						GetParam(line, param1, param2, " <>\n");

						if (strcmp(param1, "FLOAT_ARRAY_ID") == 0)
							mbstowcs_s(&size, float_array->ID, param2, SIZE_CHAR_MAX);
						if (strcmp(param1, "FLOAT_ARRAY_FLOAT_COUNT") == 0)
							float_count = atoi(param2);
						if (strcmp(param1, "FLOAT_ARRAY_COUNT") == 0)
							vertex_count = atoi(param2);
						if (strcmp(param1, "FLOAT_ARRAY") == 0) {
							if (float_count > 0 && vertex_count > 0) {

								CVector* float_data = NULL;
								if (float_count == 2)
									float_data = new CVector(sizeof(float2));
								else if (float_count == 3)
									float_data = new CVector(sizeof(float3));
								else if (float_count == 4)
									float_data = new CVector(sizeof(float4));
								else
									float_data = new CVector(sizeof(float));

								char* tmp_line = new char[FLOAT_STRING_SIZE * vertex_count * float_count];
								memset(tmp_line, 0, FLOAT_STRING_SIZE * vertex_count * float_count);
								fgets(tmp_line, FLOAT_STRING_SIZE * vertex_count * float_count, fp);

								float* data = new float[vertex_count * float_count];
								memset(data, 0, sizeof(float) * vertex_count * float_count);

								char* tmp = strtok_s(tmp_line, " \n", &ctx);
								int count = 0;
								data[count] = (float)atof(tmp);
								while (count <= vertex_count * float_count) {
									count++;
									tmp = strtok_s(NULL, " \n", &ctx);
									if (tmp == NULL)
										break;
									data[count] = (float)atof(tmp);
								}

								for (int i = 0; i <= vertex_count * float_count - 1; i += float_count) {
									if (float_count == 2) {
										float2 value;
										value.x = data[i];
										value.y = data[i + 1];
										float_data->Push((void*)&value);
									}
									if (float_count == 3) {
										float3 value;
										value.x = data[i];
										value.y = data[i + 1];
										value.z = data[i + 2];
										float_data->Push((void*)&value);
									}
									if (float_count == 4) {
										float4 value;
										value.x = data[i];
										value.y = data[i + 1];
										value.z = data[i + 2];
										value.w = data[i + 3];
										float_data->Push((void*)&value);
									}
								}
								float_array->FloatData = float_data;

								delete[] data;
								delete[] tmp_line;
							}
						}
						if (strcmp(param1, "FLOAT_ARRAY_END") == 0) {
							gmt->VecFloatArray->Push((void*)&float_array);
							break;
						}
					}
				}

				if (strcmp(param1, "POLYGON_DATA_BEGIN") == 0) {

					//ポリゴンブロックをロード

					pgn_data = new CColliderPolygonData();

					while (fgetws(w_line, SIZE_CHAR_MAX, fp) != NULL) {

						memset(param1, 0, SIZE_CHAR_MAX);
						memset(param2, 0, SIZE_CHAR_MAX);
						wcstombs_s(&size, line, w_line, SIZE_CHAR_MAX);
						GetParam(line, param1, param2, " <>\n");
						if (strcmp(param1, "VERTEX_ID") == 0)
							mbstowcs_s(&size, pgn_data->VertexID, param2, SIZE_CHAR_MAX);
						if (strcmp(param1, "NORMAL_ID") == 0)
							mbstowcs_s(&size, pgn_data->NormalID, param2, SIZE_CHAR_MAX);
						if (strcmp(param1, "VERTEX_INDEX_COUNT") == 0) {
							int count = atoi(param2);
							gmt->VertexIndexCount += count;
							if (count > 0) {
								char* tmp_line = new char[FLOAT_STRING_SIZE * count];
								memset(tmp_line, 0, FLOAT_STRING_SIZE * count);
								fgets(tmp_line, FLOAT_STRING_SIZE * count, fp);
								char* tmp = strtok_s(tmp_line, " \n", &ctx);
								int index = atoi(tmp);
								pgn_data->VertexIndex->Push((void*)&index);
								do {
									tmp = strtok_s(NULL, " \n", &ctx);
									if (tmp == NULL)
										break;
									index = atoi(tmp);
									pgn_data->VertexIndex->Push((void*)&index);
								} while (tmp != NULL);
								delete[] tmp_line;
							}
						}
						if (strcmp(param1, "NORMAL_INDEX_COUNT") == 0) {
							int count = atoi(param2);
							if (count > 0) {
								char* tmp_line = new char[FLOAT_STRING_SIZE * count];
								memset(tmp_line, 0, FLOAT_STRING_SIZE * count);
								fgets(tmp_line, FLOAT_STRING_SIZE * count, fp);
								char* tmp = strtok_s(tmp_line, " \n", &ctx);
								int index = atoi(tmp);
								pgn_data->NormalIndex->Push((void*)&index);
								do {
									tmp = strtok_s(NULL, " \n", &ctx);
									if (tmp == NULL)
										break;
									index = atoi(tmp);
									pgn_data->NormalIndex->Push((void*)&index);
								} while (tmp != NULL);
								delete[] tmp_line;
							}
						}
						if (strcmp(param1, "POLYGON_DATA_END") == 0) {
							gmt->PolygonData->Push((void*)&pgn_data);
							break;
						}
					}
				}
				if (strcmp(param1, "WEIGHTS_BEGIN") == 0) {

					//ウェイトのロード

					int weight_count = -1;
					int apply_bone_num = -1;
					while (fgetws(w_line, SIZE_CHAR_MAX, fp) != NULL) {

						memset(param1, 0, SIZE_CHAR_MAX);
						memset(param2, 0, SIZE_CHAR_MAX);
						wcstombs_s(&size, line, w_line, SIZE_CHAR_MAX);
						GetParam(line, param1, param2, " <>\n");
						if (strcmp(param1, "WEIGHTS_SIZE") == 0) {
							weight_count = atoi(param2);
							gmt->WeightCount = weight_count;
						}
						if (strcmp(param1, "APPLY_BONE_NUM") == 0) {
							apply_bone_num = atoi(param2);
							if (weight_count > 0 && apply_bone_num > 0) {
								gmt->Weights = (int64_t***) new int64_t * *[weight_count];
								for (int i = 0; i <= weight_count - 1; i++) {
									gmt->Weights[i] = (int64_t**) new int64_t * [apply_bone_num];
									for (int j = 0; j <= apply_bone_num - 1; j++) {
										gmt->Weights[i][j] = (int64_t*) new float2();
										memset(gmt->Weights[i][j], 0, sizeof(float2));
									}
								}

								char* tmp_line = new char[FLOAT_STRING_SIZE * weight_count * apply_bone_num];
								memset(tmp_line, 0, FLOAT_STRING_SIZE * weight_count * apply_bone_num);
								fgets(tmp_line, FLOAT_STRING_SIZE * weight_count * apply_bone_num, fp);

								float* data = new float[weight_count * apply_bone_num * 2];
								memset(data, 0, sizeof(float) * weight_count * apply_bone_num * 2);

								char* tmp = strtok_s(tmp_line, " \n", &ctx);
								int count = 0;
								data[count] = (float)atof(tmp);
								count++;
								do {
									tmp = strtok_s(NULL, " \n", &ctx);
									if (tmp == NULL)
										break;
									data[count] = (float)atof(tmp);
									count++;
								} while (tmp != NULL);

								count = 0;
								for (int i = 0; i <= weight_count - 1; i++) {
									for (int j = 0; j <= apply_bone_num - 1; j++) {
										float2* value = (float2*)gmt->Weights[i][j];
										value->x = data[count] + 0.00001f;
										value->y = data[count + 1];
										count += 2;
									}
								}

								delete[] tmp_line;
								delete[] data;
							}
						}
						if (strcmp(param1, "WEIGHTS_END") == 0) {
							break;
						}
					}
				}
				if (strcmp(param1, "GEOMETRY_END") == 0) {

					ColliderGeometry->Push((void*)&gmt);
					break;
				}
			}
		}
	}

	fclose(fp);

	return true;
}

bool CChaColliderObject::CreateResource(ID3D12Device* device, CChaResourceObject* object_origin, CResManager* res_manager) {

	if (object_origin == NULL)
		return false;

	//////////////////////////////////////////////////////////////////
	//コンスタントバッファ作成

	if (res_manager == NULL)
		return false;

	ResManager = res_manager;
	ResourceOrigin = object_origin;

	bool collider_only_mesh = true;
	for (int i = 0; i <= ColliderGeometry->PushPos - 1; i++) {

		CColliderGeometry* gmt = *(CColliderGeometry**)ColliderGeometry->GetData(i);

		gmt->Buffer = new char[sizeof(CColliderVertex) * gmt->VertexIndexCount];
		memset(gmt->Buffer, 0, sizeof(CColliderVertex) * gmt->VertexIndexCount);
		gmt->TransformedBuffer = new char[sizeof(CColliderVertex) * gmt->VertexIndexCount];
		memset(gmt->TransformedBuffer, 0, sizeof(CColliderVertex) * gmt->VertexIndexCount);
		char* data = new char[sizeof(CColliderVertex)];
		int vertex_pos = 0;

		if (gmt->PolygonData->PushPos == 0) {
			//頂点が２つ以下の場合

			collider_only_mesh = false;
			CFloatArray* vertex_data = *(CFloatArray**)gmt->VecFloatArray->GetData(0);

			float3 vertex;
			float3 normal;
			float2 weight[WEIGHT_BONE_APPLY_NUM];
			memset(weight, 0, sizeof(float2) * WEIGHT_BONE_APPLY_NUM);

			for (int k = 0; k <= vertex_data->FloatData->PushPos - 1; k++) {
				memset(data, 0, sizeof(CColliderVertex));
				memset(&vertex, 0, sizeof(float3));
				memset(&normal, 0, sizeof(float3));
				memset(weight, 0, sizeof(float2) * WEIGHT_BONE_APPLY_NUM);
				vertex = *(float3*)vertex_data->FloatData->GetData(k);
				if (gmt->Weights != NULL) {
					int64_t** weights = gmt->Weights[k];
					for (int l = 0; l <= WEIGHT_BONE_APPLY_NUM - 1; l++) {
						float2* w = (float2*)weights[l];
						weight[l].x = w->x;
						weight[l].y = w->y;
					}
				}
				memcpy_s((char*)data, sizeof(float3), &vertex, sizeof(float3));
				memcpy_s((char*)data + sizeof(float3), sizeof(float3), &normal, sizeof(float3));
				memcpy_s((char*)data + sizeof(float3) + sizeof(float3), sizeof(float2) * WEIGHT_BONE_APPLY_NUM, weight, sizeof(float2) * WEIGHT_BONE_APPLY_NUM);
				memcpy_s((char*)&gmt->ColliderPos[k], sizeof(CColliderVertex), data, sizeof(CColliderVertex));
			}
		}
		else {
			//メッシュの場合
			for (int j = 0; j <= gmt->PolygonData->PushPos - 1; j++) {

				CColliderPolygonData* pgn_data = *(CColliderPolygonData**)gmt->PolygonData->GetData(j);
				pgn_data->PgnVtxCount = 0;

				CFloatArray* vertex_data = gmt->GetFloatArray(pgn_data->VertexID);
				CFloatArray* normal_data = gmt->GetFloatArray(pgn_data->NormalID);

				float3 vertex;
				float3 normal;
				float2 weight[WEIGHT_BONE_APPLY_NUM];
				for (int k = 0; k <= pgn_data->VertexIndex->PushPos - 1; k++) {
					memset(data, 0, sizeof(CColliderVertex));
					memset(&vertex, 0, sizeof(float3));
					memset(&normal, 0, sizeof(float3));
					memset(weight, 0, sizeof(float2) * WEIGHT_BONE_APPLY_NUM);
					if (vertex_data != NULL) {
						int32_t vertex_index = *(int32_t*)pgn_data->VertexIndex->GetData(k);
						vertex = *(float3*)vertex_data->FloatData->GetData(vertex_index);
						if (gmt->Weights != NULL) {
							int64_t** weights = gmt->Weights[vertex_index];
							for (int l = 0; l <= WEIGHT_BONE_APPLY_NUM - 1; l++) {
								float2* w = (float2*)weights[l];
								weight[l].x = w->x;
								weight[l].y = w->y;
							}
						}
					}
					if (normal_data != NULL) {
						int32_t normal_index = *(int32_t*)pgn_data->NormalIndex->GetData(k);
						normal = *(float3*)normal_data->FloatData->GetData(normal_index);
					}
					memcpy_s((char*)data, sizeof(float3), &vertex, sizeof(float3));
					memcpy_s((char*)data + sizeof(float3), sizeof(float3), &normal, sizeof(float3));
					memcpy_s((char*)data + sizeof(float3) + sizeof(float3), sizeof(float2) * WEIGHT_BONE_APPLY_NUM, weight, sizeof(float2) * WEIGHT_BONE_APPLY_NUM);
					memcpy_s((char*)gmt->Buffer + pgn_data->PgnVtxCount * sizeof(CColliderVertex), sizeof(CColliderVertex), data, sizeof(CColliderVertex));
					pgn_data->PgnVtxCount++;
				}

				// ヒーププロパティの設定.
				D3D12_HEAP_PROPERTIES prop;
				ZeroMemory(&prop, sizeof(prop));
				prop.Type = D3D12_HEAP_TYPE_UPLOAD;
				prop.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
				prop.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
				prop.CreationNodeMask = 1;
				prop.VisibleNodeMask = 1;

				// リソースの設定.
				D3D12_RESOURCE_DESC desc_buffer;
				ZeroMemory(&desc_buffer, sizeof(desc_buffer));
				desc_buffer.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
				desc_buffer.Alignment = 0;
				desc_buffer.Width = sizeof(CColliderVertex) * pgn_data->PgnVtxCount;
				desc_buffer.Height = 1;
				desc_buffer.DepthOrArraySize = 1;
				desc_buffer.MipLevels = 1;
				desc_buffer.Format = DXGI_FORMAT_UNKNOWN;
				desc_buffer.SampleDesc.Count = 1;
				desc_buffer.SampleDesc.Quality = 0;
				desc_buffer.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
				desc_buffer.Flags = D3D12_RESOURCE_FLAG_NONE;

				// リソースを生成.
				ID3D12Resource* vertex_buffer;
				HRESULT hr = device->CreateCommittedResource(&prop, D3D12_HEAP_FLAG_NONE, &desc_buffer, D3D12_RESOURCE_STATE_GENERIC_READ, NULL, IID_PPV_ARGS(&vertex_buffer));

				UINT8* pData;
				hr = vertex_buffer->Map(0, NULL, (void**)(&pData));
				memcpy(pData, &gmt->Buffer[0], sizeof(CColliderVertex) * pgn_data->PgnVtxCount);
				vertex_buffer->Unmap(0, NULL);

				// 頂点バッファビューの設定.
				pgn_data->VertexBufferView = new D3D12_VERTEX_BUFFER_VIEW;
				pgn_data->VertexBufferView->BufferLocation = vertex_buffer->GetGPUVirtualAddress();
				pgn_data->VertexBufferView->StrideInBytes = sizeof(CColliderVertex);
				pgn_data->VertexBufferView->SizeInBytes = sizeof(CColliderVertex) * pgn_data->PgnVtxCount;

				pgn_data->VertexBuffer = vertex_buffer;
			}
		}

		delete[] data;
	}

	// 定数バッファを生成.
	// ヒーププロパティの設定.
	D3D12_HEAP_PROPERTIES prop;
	ZeroMemory(&prop, sizeof(prop));
	prop.Type = D3D12_HEAP_TYPE_UPLOAD;
	prop.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
	prop.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
	prop.CreationNodeMask = 1;
	prop.VisibleNodeMask = 1;

	// リソースの設定.
	D3D12_RESOURCE_DESC desc2;
	ZeroMemory(&desc2, sizeof(desc2));
	desc2.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
	desc2.Alignment = 0;
	desc2.Width = 0x100;
	desc2.Height = 1;
	desc2.DepthOrArraySize = 1;
	desc2.MipLevels = 1;
	desc2.Format = DXGI_FORMAT_UNKNOWN;
	desc2.SampleDesc.Count = 1;
	desc2.SampleDesc.Quality = 0;
	desc2.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
	desc2.Flags = D3D12_RESOURCE_FLAG_NONE;

	// リソースを生成.
	HRESULT hr = device->CreateCommittedResource(&prop, D3D12_HEAP_FLAG_NONE, &desc2, D3D12_RESOURCE_STATE_GENERIC_READ, NULL, IID_ID3D12Resource, (void**)&m_pConstantBufferColliderParam);

	// 定数バッファビューの設定.
	D3D12_CONSTANT_BUFFER_VIEW_DESC bufferDesc = {};
	bufferDesc.BufferLocation = m_pConstantBufferColliderParam->GetGPUVirtualAddress();
	bufferDesc.SizeInBytes = 0x100;

	// 定数バッファビューを生成.
	int64_t res_num = 0;
	D3D12_CPU_DESCRIPTOR_HANDLE handle = ResManager->CreateCPUHandle(&res_num);
	device->CreateConstantBufferView(&bufferDesc, handle);
	constant_buffer_collider_param_num = (UINT)res_num;

	// マップする. アプリケーション終了まで Unmap しない.
	hr = m_pConstantBufferColliderParam->Map(0, NULL, (void**)&constant_buffer_collider_param_begin);

	if (collider_only_mesh == false) {

		// 定数バッファを生成.
		// ヒーププロパティの設定.

		// リソースの設定.
		desc2.Width = 0x100 * 3 * sizeof(XMFLOAT4);

		// リソースを生成.
		HRESULT hr = device->CreateCommittedResource(&prop, D3D12_HEAP_FLAG_NONE, &desc2, D3D12_RESOURCE_STATE_GENERIC_READ, NULL, IID_ID3D12Resource, (void**)&m_pConstantBufferCollider);

		// 定数バッファビューの設定.
		D3D12_CONSTANT_BUFFER_VIEW_DESC bufferDesc = {};
		bufferDesc.BufferLocation = m_pConstantBufferCollider->GetGPUVirtualAddress();
		bufferDesc.SizeInBytes = 0x100 * 3 * sizeof(XMFLOAT4);

		// 定数バッファビューを生成.
		int64_t res_num = 0;
		D3D12_CPU_DESCRIPTOR_HANDLE handle = ResManager->CreateCPUHandle(&res_num);
		device->CreateConstantBufferView(&bufferDesc, handle);
		constant_buffer_collider_num = (UINT)res_num;

		// マップする. アプリケーション終了まで Unmap しない.
		hr = m_pConstantBufferCollider->Map(0, NULL, (void**)&constant_buffer_collider_begin);
	}

	return true;
}

bool CChaColliderObject::Transform() {

	MinPos = XMFLOAT4(1000.0f, 1000.0f, 1000.0f, 0.0f);
	MaxPos = XMFLOAT4(-1000.0f, -1000.0f, -1000.0f, 0.0f);

	float scale_r = ResourceOrigin->Scale.w;

	for (int i = 0; i <= ColliderGeometry->PushPos - 1; i++) {
		CColliderGeometry* gmt = *(CColliderGeometry**)ColliderGeometry->GetData(i);
		if (gmt->ColliderType == COLLIDER_TYPE_SPHERE || gmt->ColliderType == COLLIDER_TYPE_BOX) {
			gmt->TransformedColliderPos[0] = VertexTransform(gmt->ColliderPos[0], gmt->BindShapeMatrix);

			if (gmt->TransformedColliderPos[0].Pos.x - gmt->R * scale_r < MinPos.x)
				MinPos.x = gmt->TransformedColliderPos[0].Pos.x - gmt->R * scale_r;
			if (gmt->TransformedColliderPos[0].Pos.y - gmt->R < MinPos.y)
				MinPos.y = gmt->TransformedColliderPos[0].Pos.y - gmt->R * scale_r;
			if (gmt->TransformedColliderPos[0].Pos.z - gmt->R * scale_r < MinPos.z)
				MinPos.z = gmt->TransformedColliderPos[0].Pos.z - gmt->R * scale_r;
			if (gmt->TransformedColliderPos[0].Pos.x + gmt->R * scale_r > MaxPos.x)
				MaxPos.x = gmt->TransformedColliderPos[0].Pos.x + gmt->R * scale_r;
			if (gmt->TransformedColliderPos[0].Pos.y + gmt->R * scale_r > MaxPos.y)
				MaxPos.y = gmt->TransformedColliderPos[0].Pos.y + gmt->R * scale_r;
			if (gmt->TransformedColliderPos[0].Pos.z + gmt->R * scale_r > MaxPos.z)
				MaxPos.z = gmt->TransformedColliderPos[0].Pos.z + gmt->R * scale_r;
		}
		if (gmt->ColliderType == COLLIDER_TYPE_CAPSULE || gmt->ColliderType == COLLIDER_TYPE_RECT) {
			gmt->TransformedColliderPos[0] = VertexTransform(gmt->ColliderPos[0], gmt->BindShapeMatrix);
			gmt->TransformedColliderPos[1] = VertexTransform(gmt->ColliderPos[1], gmt->BindShapeMatrix);

			if (gmt->TransformedColliderPos[0].Pos.x - gmt->R * scale_r < MinPos.x)
				MinPos.x = gmt->TransformedColliderPos[0].Pos.x - gmt->R * scale_r;
			if (gmt->TransformedColliderPos[0].Pos.y - gmt->R * scale_r < MinPos.y)
				MinPos.y = gmt->TransformedColliderPos[0].Pos.y - gmt->R * scale_r;
			if (gmt->TransformedColliderPos[0].Pos.z - gmt->R * scale_r < MinPos.z)
				MinPos.z = gmt->TransformedColliderPos[0].Pos.z - gmt->R * scale_r;
			if (gmt->TransformedColliderPos[0].Pos.x + gmt->R * scale_r > MaxPos.x)
				MaxPos.x = gmt->TransformedColliderPos[0].Pos.x + gmt->R * scale_r;
			if (gmt->TransformedColliderPos[0].Pos.y + gmt->R * scale_r > MaxPos.y)
				MaxPos.y = gmt->TransformedColliderPos[0].Pos.y + gmt->R * scale_r;
			if (gmt->TransformedColliderPos[0].Pos.z + gmt->R * scale_r > MaxPos.z)
				MaxPos.z = gmt->TransformedColliderPos[0].Pos.z + gmt->R * scale_r;

			if (gmt->TransformedColliderPos[1].Pos.x - gmt->R * scale_r < MinPos.x)
				MinPos.x = gmt->TransformedColliderPos[1].Pos.x - gmt->R * scale_r;
			if (gmt->TransformedColliderPos[1].Pos.y - gmt->R * scale_r < MinPos.y)
				MinPos.y = gmt->TransformedColliderPos[1].Pos.y - gmt->R * scale_r;
			if (gmt->TransformedColliderPos[1].Pos.z - gmt->R * scale_r < MinPos.z)
				MinPos.z = gmt->TransformedColliderPos[1].Pos.z - gmt->R * scale_r;
			if (gmt->TransformedColliderPos[1].Pos.x + gmt->R * scale_r > MaxPos.x)
				MaxPos.x = gmt->TransformedColliderPos[1].Pos.x + gmt->R * scale_r;
			if (gmt->TransformedColliderPos[1].Pos.y + gmt->R * scale_r > MaxPos.y)
				MaxPos.y = gmt->TransformedColliderPos[1].Pos.y + gmt->R * scale_r;
			if (gmt->TransformedColliderPos[1].Pos.z + gmt->R * scale_r > MaxPos.z)
				MaxPos.z = gmt->TransformedColliderPos[1].Pos.z + gmt->R * scale_r;
		}
		if (gmt->ColliderType == COLLIDER_TYPE_MESH) {
			for (int j = 0; j <= gmt->VertexIndexCount - 1; j++) {
				CColliderVertex collider_vertex;
				memcpy_s(&collider_vertex, sizeof(CColliderVertex), &gmt->Buffer[0] + sizeof(CColliderVertex) * j, sizeof(CColliderVertex));

				CColliderVertex transformed_vtx = VertexTransform(collider_vertex, gmt->BindShapeMatrix);
				memcpy_s(gmt->TransformedBuffer + j * sizeof(CColliderVertex), sizeof(CColliderVertex), &transformed_vtx, sizeof(CColliderVertex));

				if (transformed_vtx.Pos.x < MinPos.x)
					MinPos.x = transformed_vtx.Pos.x;
				if (transformed_vtx.Pos.y < MinPos.y)
					MinPos.y = transformed_vtx.Pos.y;
				if (transformed_vtx.Pos.z < MinPos.z)
					MinPos.z = transformed_vtx.Pos.z;
				if (transformed_vtx.Pos.x > MaxPos.x)
					MaxPos.x = transformed_vtx.Pos.x;
				if (transformed_vtx.Pos.y > MaxPos.y)
					MaxPos.y = transformed_vtx.Pos.y;
				if (transformed_vtx.Pos.z > MaxPos.z)
					MaxPos.z = transformed_vtx.Pos.z;
			}
		}
	}

	CenterPos.x = (MinPos.x + MaxPos.x) / 2.0f;
	CenterPos.y = (MinPos.y + MaxPos.y) / 2.0f;
	CenterPos.z = (MinPos.z + MaxPos.z) / 2.0f;
	Length = sqrt(pow(MaxPos.x - MinPos.x, 2.0f) + pow(MaxPos.y - MinPos.y, 2.0f) + pow(MaxPos.z - MinPos.z, 2.0f)) / 2.0f;

	return true;
}

CColliderVertex CChaColliderObject::VertexTransform(CColliderVertex vertex, XMMATRIX bind_shape_matrix) {

	CColliderVertex transformed_vtx;
	memcpy(&transformed_vtx, &vertex, sizeof(CColliderVertex));

	XMVECTOR pos_origin = XMVectorSet(vertex.Pos.x, vertex.Pos.y, vertex.Pos.z, 1.0f);
	XMVECTOR normal_origin = XMVectorSet(vertex.Normal.x, vertex.Normal.y, vertex.Normal.z, 1.0f);
	XMVECTOR pos = XMVector4Transform(pos_origin, bind_shape_matrix);
	XMVECTOR normal = XMVector4Transform(normal_origin, bind_shape_matrix);

	XMVECTOR vtx_tmp = XMVectorSet(0, 0, 0, 0);
	XMVECTOR normal_tmp = XMVectorSet(0, 0, 0, 0);
	float add_weight = false;
	for (int i = 0; i <= WEIGHT_BONE_APPLY_NUM - 1; i++) {
		int joint = (int)vertex.Weight[i].x;
		float w = vertex.Weight[i].y;

		if (joint <= 0)
			continue;

		CBoneResource* bone_res = *(CBoneResource**)ResourceOrigin->BoneArray->GetData(joint);
		XMMATRIX mtx = bone_res->BoneMatrix;

		if (w > 0.0000001f) {
			XMVECTOR v = XMVector4Transform(pos, mtx);
			XMVECTOR n = XMVector4Transform(normal, mtx);
			v *= w;
			n *= w;
			vtx_tmp += v;
			normal_tmp += n;
			add_weight = true;
		}
	}
	if (add_weight == true) {
		pos = vtx_tmp;
		normal = normal_tmp;
	}

	pos = XMVector4Transform(pos, ResourceOrigin->TransformMatrix);
	normal = XMVector4Transform(normal, ResourceOrigin->NormalTransformMatrix);

	transformed_vtx.Pos.x = XMVectorGetX(pos);
	transformed_vtx.Pos.y = XMVectorGetY(pos);
	transformed_vtx.Pos.z = XMVectorGetZ(pos);
	transformed_vtx.Normal.x = XMVectorGetX(normal);
	transformed_vtx.Normal.y = XMVectorGetY(normal);
	transformed_vtx.Normal.z = XMVectorGetZ(normal);

	return transformed_vtx;
}

bool CChaColliderObject::Draw(ID3D12GraphicsCommandList* m_pCmdList, XMMATRIX matWorld, XMMATRIX matView, XMMATRIX matProj, ID3D12PipelineState* m_pPipeLineStatePoint, ID3D12PipelineState* m_pPipeLineStateMesh, bool collision_xy, bool collision_z ) {

	if (ResourceOrigin == NULL)
		return false;

	//////////////////////////////////////////////////////
	//カプセル・スフィアの場合

	ConstantBufferCollider	constant_buffer_collider;
	memset(&constant_buffer_collider, 0, sizeof(ConstantBufferCollider));

	ConstantBufferColliderParam	constant_buffer_collider_param;
	memset(&constant_buffer_collider_param, 0, sizeof(ConstantBufferColliderParam));

	m_pCmdList->SetPipelineState(m_pPipeLineStatePoint);

	if (collision_z == true || collision_xy == true)
		constant_buffer_collider_param.ColliderState1 = XMFLOAT4(0.00f, 0, 0, 0);
	else
		constant_buffer_collider_param.ColliderState1 = XMFLOAT4(1.00f, 0, 0, 0);

	memcpy(constant_buffer_collider_param_begin, &constant_buffer_collider_param, sizeof(constant_buffer_collider_param));
	m_pCmdList->SetGraphicsRootConstantBufferView(4, m_pConstantBufferColliderParam->GetGPUVirtualAddress());

	int pos = 0;
	bool collider_only_mesh = true;
	for (int i = 0; i <= ColliderGeometry->PushPos - 1; i++) {
		CColliderGeometry* gmt = *(CColliderGeometry**)ColliderGeometry->GetData(i);
		if (gmt->ColliderType == COLLIDER_TYPE_SPHERE || gmt->ColliderType == COLLIDER_TYPE_BOX) {

			constant_buffer_collider.ColliderParam[pos].x = (float)gmt->ColliderType;

			XMVECTOR p1 = XMVectorSet(gmt->TransformedColliderPos[0].Pos.x, gmt->TransformedColliderPos[0].Pos.y, gmt->TransformedColliderPos[0].Pos.z, 1.0f);
			p1 = XMVector4Transform(p1, matWorld);
			p1 = XMVector4Transform(p1, matView);
			p1 = XMVector4Transform(p1, matProj);

			float w = XMVectorGetW(p1);
			constant_buffer_collider.ColliderPos[pos][0] = XMFLOAT4(XMVectorGetX(p1) / w, XMVectorGetY(p1) / w, XMVectorGetZ(p1) / w, 1.0f);
			constant_buffer_collider.ColliderPos[pos][1] = XMFLOAT4(0, 0, 0, 0);
			constant_buffer_collider.ColliderParam[pos].y = gmt->R * ResourceOrigin->Scale.w / w;

			collider_only_mesh = false;

			pos++;
		}
		else if (gmt->ColliderType == COLLIDER_TYPE_CAPSULE || gmt->ColliderType == COLLIDER_TYPE_RECT) {

			constant_buffer_collider.ColliderParam[pos].x = (float)gmt->ColliderType;

			XMVECTOR p1 = XMVectorSet(gmt->TransformedColliderPos[0].Pos.x, gmt->TransformedColliderPos[0].Pos.y, gmt->TransformedColliderPos[0].Pos.z, 1.0f);
			p1 = XMVector4Transform(p1, matWorld);
			p1 = XMVector4Transform(p1, matView);
			p1 = XMVector4Transform(p1, matProj);

			XMVECTOR p2 = XMVectorSet(gmt->TransformedColliderPos[1].Pos.x, gmt->TransformedColliderPos[1].Pos.y, gmt->TransformedColliderPos[1].Pos.z, 1.0f);
			p2 = XMVector4Transform(p2, matWorld);
			p2 = XMVector4Transform(p2, matView);
			p2 = XMVector4Transform(p2, matProj);

			float w1 = XMVectorGetW(p1);
			float w2 = XMVectorGetW(p2);
			constant_buffer_collider.ColliderPos[pos][0] = XMFLOAT4(XMVectorGetX(p1) / w1, XMVectorGetY(p1) / w1, XMVectorGetZ(p1) / w1, 1.0f);
			constant_buffer_collider.ColliderPos[pos][1] = XMFLOAT4(XMVectorGetX(p2) / w2, XMVectorGetY(p2) / w2, XMVectorGetZ(p2) / w2, 1.0f);

			constant_buffer_collider.ColliderParam[pos].y = gmt->R * ResourceOrigin->Scale.w / w1;

			collider_only_mesh = false;

			pos++;
		}
	}

	if (collider_only_mesh == false) {
		memcpy(constant_buffer_collider_begin, &constant_buffer_collider, sizeof(constant_buffer_collider));
		m_pCmdList->SetGraphicsRootConstantBufferView(3, m_pConstantBufferCollider->GetGPUVirtualAddress());
		m_pCmdList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
		m_pCmdList->DrawInstanced(4, 1, 0, 0);
	}

	//////////////////////////////////////////////////////////////////////////////
	//メッシュを描く

	m_pCmdList->SetPipelineState(m_pPipeLineStateMesh);

	ConstantBufferJoint			constant_buffer_joint;

	for (int i = 0; i <= ResourceOrigin->BoneArray->PushPos - 1; i++) {

		CBoneResource* bone_res = *(CBoneResource**)ResourceOrigin->BoneArray->GetData(i);
		XMMATRIX mtx = bone_res->BoneMatrix;
		XMStoreFloat4x4(&constant_buffer_joint.BoneMatrix[i], XMMatrixTranspose(mtx));
	}

	XMStoreFloat4x4(&constant_buffer_joint.MatTransform, XMMatrixTranspose(ResourceOrigin->TransformMatrix));
	XMStoreFloat4x4(&constant_buffer_joint.MatNormalTransform, XMMatrixTranspose(ResourceOrigin->NormalTransformMatrix));

	// プリミティブトポロジーの設定.
	m_pCmdList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
	m_pCmdList->SetGraphicsRootConstantBufferView(2, ResourceOrigin->m_pConstantBufferJoint->GetGPUVirtualAddress());

	for (int i = 0; i <= ColliderGeometry->PushPos - 1; i++) {

		CColliderGeometry* gmt = *(CColliderGeometry**)ColliderGeometry->GetData(i);

		if (gmt->ColliderType == COLLIDER_TYPE_MESH) {

			// 頂点バッファビューを設定.

			XMStoreFloat4x4(&constant_buffer_joint.BindShapeMatrix, XMMatrixTranspose(gmt->BindShapeMatrix));
			memcpy(ResourceOrigin->constant_buffer_joint_begin, &constant_buffer_joint, sizeof(constant_buffer_joint));

			for (int j = 0; j <= gmt->PolygonData->PushPos - 1; j++) {
				CColliderPolygonData* pgn_data = *(CColliderPolygonData**)gmt->PolygonData->GetData(j);
				m_pCmdList->IASetVertexBuffers(0, 1, pgn_data->VertexBufferView);
				m_pCmdList->DrawInstanced(pgn_data->PgnVtxCount, 1, 0, 0);
			}
		}
	}

	return true;
}

