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

#include "defcha3dcore.h"


CGeometryResource::CGeometryResource(){

	VertexBuffer = NULL;
	IndexBuffer = new CVector(sizeof(ID3D11Buffer **));
	Material = new CVector(sizeof(MaterialResource));
	IndexCount = new CVector(sizeof(int));
}

CGeometryResource::~CGeometryResource(){

	SAFE_RELEASE(VertexBuffer);
	for (int i = 0; i <= IndexBuffer->PushPos - 1; i++){
		ID3D11Buffer **index_buffer = (ID3D11Buffer **)IndexBuffer->GetData(i);
		SAFE_RELEASE(*index_buffer);
	}

	delete IndexBuffer;
	delete Material;
	delete IndexCount;
}

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

CChaResourceObject::CChaResourceObject(){

	ReadyResource = false;
	GeometryResource = new CVector(sizeof(CGeometryResource));
	TextureOrigin = new CVector(sizeof(ID3D11Texture2D **));
	ShaderResourceOrigin = new CVector(sizeof(ID3D11ShaderResourceView **));
}

CChaResourceObject::~CChaResourceObject(){

	for (int i = 0; i <= GeometryResource->PushPos - 1; i++){
		CGeometryResource *gmt_res = (CGeometryResource *)GeometryResource->GetData(i);
		delete gmt_res;
	}
	for (int i = 0; i <= TextureOrigin->PushPos - 1; i++){
		ID3D11Texture2D **texture = (ID3D11Texture2D **)TextureOrigin->GetData(i);
		SAFE_RELEASE(*texture);
	}
	for (int i = 0; i <= ShaderResourceOrigin->PushPos - 1; i++){
		ID3D11ShaderResourceView **res = (ID3D11ShaderResourceView **)ShaderResourceOrigin->GetData(i);
		SAFE_RELEASE(*res);
	}

	delete TextureOrigin;
	delete ShaderResourceOrigin;
}

bool CChaResourceObject::CreateResource( ID3D11Device *m_pDevice, CChaDataObject *object){
	
	if (object == NULL)
		return false;

	//////////////////////////////////////////////////////////////////
	// テクスチャリソース作成

	D3D11_TEXTURE2D_DESC desc_texture_2d;
	ZeroMemory(&desc_texture_2d, sizeof(D3D11_TEXTURE2D_DESC));
	desc_texture_2d.MipLevels = 1;
	desc_texture_2d.ArraySize = 1;
	desc_texture_2d.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
	desc_texture_2d.SampleDesc.Count = 1;
	desc_texture_2d.SampleDesc.Quality = 0;
	desc_texture_2d.Usage = D3D11_USAGE_DEFAULT;
	desc_texture_2d.BindFlags = D3D11_BIND_SHADER_RESOURCE;
	desc_texture_2d.CPUAccessFlags = 0;
	desc_texture_2d.MiscFlags = 0;

	D3DX11_IMAGE_LOAD_INFO info;
	ZeroMemory(&info, sizeof(D3DX11_IMAGE_LOAD_INFO));
	info.Width = D3DX11_DEFAULT;
	info.Height = D3DX11_DEFAULT;
	info.Depth = D3DX11_DEFAULT;
	info.FirstMipLevel = D3DX11_DEFAULT;
	info.MipLevels = 1;
	info.Usage = D3D11_USAGE_DEFAULT;
	info.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
	info.CpuAccessFlags = 0;
	info.MiscFlags = 0;
	info.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
	info.Filter = D3DX11_FILTER_LINEAR;
	info.MipFilter = D3DX11_FILTER_LINEAR;
	info.pSrcInfo = NULL;

	D3D11_SHADER_RESOURCE_VIEW_DESC desc_shader_resource;
	ZeroMemory(&desc_shader_resource, sizeof(D3D11_SHADER_RESOURCE_VIEW_DESC));
	desc_shader_resource.Format = info.Format;
	desc_shader_resource.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
	desc_shader_resource.Texture2D.MipLevels = info.MipLevels;
	desc_shader_resource.Texture2D.MostDetailedMip = 0;

	size_t size;
	wchar_t name[SIZE_CHAR_MAX];
	for (int i = 0; i <= object->TextureName->PushPos - 1; i++){
		ID3D11Texture2D *texture = NULL;
		ID3D11ShaderResourceView *shader_res = NULL;
		CTextureName *tex_name = (CTextureName *)object->TextureName->GetData(i);
		if (tex_name != NULL && tex_name->TextureName != NULL ){
			mbstowcs_s(&size, name, tex_name->TextureName, SIZE_CHAR_MAX);
			HRESULT hr = D3DX11CreateTextureFromFile(m_pDevice, name, &info, NULL, (ID3D11Resource **)&texture, NULL);
			hr = m_pDevice->CreateShaderResourceView(texture, &desc_shader_resource, &shader_res);
			if (hr == S_OK){
				TextureOrigin->Push((void*)&texture);
				ShaderResourceOrigin->Push((void *)&shader_res);
			}
		}
	}

	//////////////////////////////////////////////////////////////////
	// バッファ作成

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

		CGeometry *gmt = (CGeometry *)object->Geometry->GetData(i);
		CGeometryResource *gmt_res = new CGeometryResource();

		int vertex_count = gmt->VertexCount;
		char *buffer = new char[sizeof( CVertex ) * (vertex_count)];
		memset(buffer, 0, sizeof(CVertex)* (vertex_count));
		char *data = new char[sizeof(CVertex)];
		int vertex_pos = 0;

		for (int j = 0; j <= gmt->PolygonData->PushPos - 1; j++){

			CPolygonData *pgn_data = (CPolygonData *)gmt->PolygonData->GetData(j);
			CVertexData *vertex_data = gmt->GetVertexData(pgn_data->VertexID);
			CVertexData *normal_data = gmt->GetVertexData(pgn_data->NormalID);
			CVertexData *color_data = gmt->GetVertexData(pgn_data->ColorID);
			CVertexData *tex_data = gmt->GetVertexData(pgn_data->TexID);

			//Material取得
			CMaterial *material = object->GetMaterial(pgn_data->MaterialID);
			ID3D11Texture2D **texture = NULL;
			ID3D11ShaderResourceView **shader_res = NULL;
			MaterialResource *material_resource = new MaterialResource();
			memset(material_resource, 0, sizeof(MaterialResource));
			if (material != NULL){
				int material_num = object->GetMaterialNum(pgn_data->MaterialID);
				int texture_num = object->GetTextureNum(material_num);
				if (texture_num >= 0){
					texture = (ID3D11Texture2D **)TextureOrigin->GetData(texture_num);
					shader_res = (ID3D11ShaderResourceView **)ShaderResourceOrigin->GetData(texture_num);
				}
				material_resource->diffuse = material->diffuse;
				material_resource->ambient = material->ambient;
				material_resource->emmition = material->emmition;
				material_resource->specular = material->specular;
				material_resource->Texture = texture;
				material_resource->ShaderResourceView = shader_res;
			}
			gmt_res->Material->Push((void *)material_resource);

			int index_count = pgn_data->VertexIndex->PushPos;
			int *buffer_index = new int[index_count];
			memset(buffer_index, 0, ( index_count ) * sizeof(int));

			float3 vertex;
			float3 normal;
			float4 color;
			float2 tex;
			for (int k = 0; k <= pgn_data->VertexIndex->PushPos - 1; k++){
				memset(data, 0, sizeof(CVertex));
				memset( &vertex, 0, sizeof(float3));
				memset( &normal, 0, sizeof(float3));
				memset( &color, 0, sizeof(float4));
				memset( &tex, 0, sizeof(float2));
				if (vertex_data != NULL){
					int vertex_index = *(int *)pgn_data->VertexIndex->GetData(k);
					vertex = *(float3 *)vertex_data->Data->GetData(vertex_index);
					vertex_pos = vertex_index;
				}
				if (normal_data != NULL){
					int normal_index = *(int *)pgn_data->NormalIndex->GetData(k);
					normal = *(float3 *)normal_data->Data->GetData(normal_index);
				}
				if (color_data != NULL){
					int color_index = *(int *)pgn_data->ColorIndex->GetData(k);
					color = *(float4 *)color_data->Data->GetData(color_index);
				}
				if (tex_data != NULL){
					int tex_index = *(int *)pgn_data->TexIndex->GetData(k);
					tex = *(float2 *)tex_data->Data->GetData(tex_index);
				}
				memcpy_s((char *)data, sizeof(CVertex), &vertex, sizeof(float3));
				memcpy_s((char *)data + sizeof(float3), sizeof(CVertex), &normal, sizeof(float3));
				memcpy_s((char *)data + sizeof(float3)+sizeof(float3), sizeof(CVertex), &color, sizeof(float4));
				memcpy_s((char *)data + sizeof(float3)+sizeof(float3)+sizeof(float4), sizeof(CVertex), &tex, sizeof(float2));
				memcpy_s((char *)buffer + vertex_pos * sizeof(CVertex), sizeof(CVertex), data, sizeof(CVertex));
				buffer_index[k] = *(int *) pgn_data->VertexIndex->GetData( k );
			}

			D3D11_BUFFER_DESC desc_index;
			ZeroMemory(&desc_index, sizeof(D3D11_BUFFER_DESC));
			desc_index.Usage = D3D11_USAGE_DEFAULT;
			desc_index.ByteWidth = sizeof(int)* index_count;
			desc_index.BindFlags = D3D11_BIND_INDEX_BUFFER;
			desc_index.CPUAccessFlags = 0;
			desc_index.MiscFlags = 0;

			D3D11_SUBRESOURCE_DATA res_data_index;
			res_data_index.pSysMem = &buffer_index[0];
			ID3D11Buffer *index_buffer = NULL;
			HRESULT hr = m_pDevice->CreateBuffer(&desc_index, &res_data_index, &index_buffer);

			gmt_res->IndexBuffer->Push((void *) &index_buffer);
			gmt_res->IndexCount->Push((void *) &index_count);

			delete[] buffer_index;
		}

		D3D11_BUFFER_DESC desc_buffer;
		ZeroMemory(&desc_buffer, sizeof(D3D11_BUFFER_DESC));
		desc_buffer.ByteWidth = sizeof(CVertex)* vertex_count;
		desc_buffer.Usage = D3D11_USAGE_DYNAMIC;
		desc_buffer.BindFlags = D3D11_BIND_VERTEX_BUFFER;
		desc_buffer.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
		desc_buffer.MiscFlags = 0;
		desc_buffer.StructureByteStride = sizeof(float);

		D3D11_SUBRESOURCE_DATA res_data_buffer;
		res_data_buffer.pSysMem = &buffer[0];
		ID3D11Buffer *vertex_buffer = NULL;
		HRESULT hr = m_pDevice->CreateBuffer(&desc_buffer, &res_data_buffer, &vertex_buffer);

		gmt_res->VertexBuffer = vertex_buffer;
		GeometryResource->Push((void *)gmt_res);

		delete[] data;
		delete[] buffer;
	}

	ReadyResource = true;

	return true;
}

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

bool CChaResourceObject::Draw(ID3D11DeviceContext *m_pDeviceContext ){

	if (ReadyResource == false)
		return false;

	UINT stride = sizeof(CVertex);
	UINT offset = 0;
	m_pDeviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

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

		CGeometryResource *gmt_res = (CGeometryResource *)GeometryResource->GetData(i);
		m_pDeviceContext->IASetVertexBuffers(0, 1, &gmt_res->VertexBuffer, &stride, &offset);

		for (int j = 0; j <= gmt_res->IndexBuffer->PushPos - 1; j++){

			ID3D11Buffer **index_buffer = (ID3D11Buffer **)gmt_res->IndexBuffer->GetData(j);
			m_pDeviceContext->IASetIndexBuffer(*index_buffer, DXGI_FORMAT_R32_UINT, 0);

			MaterialResource *material = (MaterialResource *)gmt_res->Material->GetData(j);
			if ( material != NULL && material->ShaderResourceView != NULL )
				m_pDeviceContext->PSSetShaderResources(0, 1, (ID3D11ShaderResourceView **) material->ShaderResourceView);

			int *index_count = (int *) gmt_res->IndexCount->GetData( j );
			m_pDeviceContext->DrawIndexed(*index_count, 0, 0);
		}
	}

	return true;
}

