////////////////////////////////////////////////////////
// filename: CLight.cpp
// author: Chafumi Touji
// version: 1.0.0
// date: 2020/07/11
////////////////////////////////////////////////////////

#include "defcha3dcore.h"
#include "CLight.h"

CPointLight::CPointLight(){

	m_pTextureShadowMap = NULL;
	m_pShadowMapRenderTargetView = NULL;
	m_pShadowMapShaderResourceView = NULL;
	m_pTextureShadowMapSoft = NULL;
	m_pShadowMapSoftRenderTargetView = NULL;
	m_pShadowMapSoftShaderResourceView = NULL;
	m_pTextureShadowMapSoftOrg = NULL;
	m_pShadowMapSoftOrgRenderTargetView = NULL;
	m_pShadowMapSoftOrgShaderResourceView = NULL;
	m_pConstantBufferPointLight = NULL;
	m_pTextureVolumeLight = NULL;
	m_pVolumeLightRenderTargetView = NULL;
	m_pVolumeLightShaderResourceView = NULL;

	ShadowPower = 1.0f;
	ShadowFar = 1.0f;
	LightColor = XMFLOAT4(1, 1, 1, 1);
	UpdateShadowMap = false;

	ZeroMemory(&constant_buffer_pl, sizeof(ConstantBufferPointLight));
}

CPointLight::~CPointLight(){

	SAFE_RELEASE(m_pTextureShadowMapSoft);
	SAFE_RELEASE(m_pShadowMapSoftRenderTargetView);
	SAFE_RELEASE(m_pShadowMapSoftShaderResourceView);
	SAFE_RELEASE(m_pTextureShadowMapSoftOrg);
	SAFE_RELEASE(m_pShadowMapSoftOrgRenderTargetView);
	SAFE_RELEASE(m_pShadowMapSoftOrgShaderResourceView);
	SAFE_RELEASE(m_pConstantBufferPointLight);
	SAFE_RELEASE(m_pTextureVolumeLight);
	SAFE_RELEASE(m_pVolumeLightRenderTargetView);
	SAFE_RELEASE(m_pVolumeLightShaderResourceView);

	if (m_pTextureShadowMap != NULL){
		for (int i = 0; i <= 5; i++)
			SAFE_RELEASE(m_pTextureShadowMap[i]);
		delete[] m_pTextureShadowMap;
	}
	if (m_pShadowMapShaderResourceView != NULL){
		for (int i = 0; i <= 5; i++)
			SAFE_RELEASE(m_pShadowMapShaderResourceView[i]);
		delete[] m_pShadowMapShaderResourceView;
	}
	if (m_pShadowMapRenderTargetView != NULL){
		for (int i = 0; i <= 5; i++)
			SAFE_RELEASE(m_pShadowMapRenderTargetView[i]);
		delete[] m_pShadowMapRenderTargetView;
	}
}

bool CPointLight::CreatePointLight(CCommonDevice *device, float pos_x, float pos_y, float pos_z, float power, float resolution, int size){

	LightPos = XMFLOAT4(pos_x, pos_y, pos_z, 1.0f);
	Power = power;
	TextureSize = size;
	ShadowPower = 1.0f;
	ShadowFar = 1.0f;
	ShadowMapResolution = resolution;

	CreateResource(device);

	return true;
}

bool CPointLight::CreatePointLight(CCommonDevice *device, float pos_x, float pos_y, float pos_z, float power, float resolution ){

	return CreatePointLight(device, pos_x, pos_y, pos_z, power, resolution, DEFAULT_POINT_LIGHT_TEXTUER_SIZE);
}

bool CPointLight::SetLightColor(float r, float g, float b){

	LightColor = XMFLOAT4(r, g, b, Power);

	return true;
}

bool CPointLight::SetPoint(float pos_x, float pos_y, float pos_z){

	LightPos = XMFLOAT4(pos_x, pos_y, pos_z, 1.0f);
	UpdateShadowMap = false;

	return true;
}

bool CPointLight::SetPower(float power){

	Power = power;
	UpdateShadowMap = false;
	LightColor.w = Power;

	return true;
}

bool CPointLight::SetShadowFar(float len){

	ShadowFar = len;
	UpdateShadowMap = false;

	return true;
}

bool CPointLight::SetShadowPower(float power){

	ShadowPower = power;
	UpdateShadowMap = false;

	return true;
}


bool CPointLight::CreateResource(CCommonDevice *device){

	if (device == 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.SampleDesc.Count = 1;
	desc_texture_2d.SampleDesc.Quality = 0;
	desc_texture_2d.Usage = D3D11_USAGE_DEFAULT;
	desc_texture_2d.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
	desc_texture_2d.CPUAccessFlags = 0;
	desc_texture_2d.MiscFlags = 0;
	desc_texture_2d.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;

	m_pTextureShadowMap = (ID3D11Texture2D **) new ID3D11Texture2D*[6];

	desc_texture_2d.Width = device->Width;
	desc_texture_2d.Height = device->Height;
	device->m_pDevice->CreateTexture2D(&desc_texture_2d, NULL, &m_pTextureShadowMapSoft);

	desc_texture_2d.Width = device->Width * ShadowMapResolution;
	desc_texture_2d.Height = device->Height * ShadowMapResolution;
	device->m_pDevice->CreateTexture2D(&desc_texture_2d, NULL, &m_pTextureShadowMapSoftOrg);

	desc_texture_2d.Width = TextureSize;
	desc_texture_2d.Height = TextureSize;
	for (int i = 0; i <= 5; i++){
		device->m_pDevice->CreateTexture2D(&desc_texture_2d, NULL, &m_pTextureShadowMap[i]);
	}

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

	m_pShadowMapShaderResourceView = (ID3D11ShaderResourceView **) new ID3D11ShaderResourceView*[6];
	m_pShadowMapRenderTargetView = (ID3D11RenderTargetView **) new ID3D11RenderTargetView*[6];

	device->m_pDevice->CreateShaderResourceView(m_pTextureShadowMapSoft, &desc_shader_resource, &m_pShadowMapSoftShaderResourceView);
	device->m_pDevice->CreateRenderTargetView(m_pTextureShadowMapSoft, NULL, &m_pShadowMapSoftRenderTargetView);
	device->m_pDevice->CreateShaderResourceView(m_pTextureShadowMapSoftOrg, &desc_shader_resource, &m_pShadowMapSoftOrgShaderResourceView);
	device->m_pDevice->CreateRenderTargetView(m_pTextureShadowMapSoftOrg, NULL, &m_pShadowMapSoftOrgRenderTargetView);

	for (int i = 0; i <= 5; i++){
		device->m_pDevice->CreateShaderResourceView(m_pTextureShadowMap[i], &desc_shader_resource, &m_pShadowMapShaderResourceView[i]);
		device->m_pDevice->CreateRenderTargetView(m_pTextureShadowMap[i], NULL, &m_pShadowMapRenderTargetView[i]);
	}

	//////////////////////////////////////////////////////
	//ボリュームライト

	desc_texture_2d.Width = device->Width;
	desc_texture_2d.Height = device->Height;

	device->m_pDevice->CreateTexture2D(&desc_texture_2d, NULL, &m_pTextureVolumeLight);
	device->m_pDevice->CreateShaderResourceView(m_pTextureVolumeLight, &desc_shader_resource, &m_pVolumeLightShaderResourceView);
	device->m_pDevice->CreateRenderTargetView(m_pTextureVolumeLight, NULL, &m_pVolumeLightRenderTargetView);

	//////////////////////////////////////////////////////////////////
	// ConstantBuffer

	D3D11_BUFFER_DESC desc_buffer;
	m_pConstantBufferPointLight = NULL;
	ZeroMemory(&desc_buffer, sizeof(D3D11_BUFFER_DESC));
	desc_buffer.ByteWidth = sizeof(ConstantBufferPointLight);
	desc_buffer.Usage = D3D11_USAGE_DYNAMIC;
	desc_buffer.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
	desc_buffer.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
	desc_buffer.MiscFlags = 0;
	desc_buffer.StructureByteStride = sizeof(float);
	device->m_pDevice->CreateBuffer(&desc_buffer, NULL, &m_pConstantBufferPointLight);

	return true;
}

bool CPointLight::SetParam(CCommonDevice *device){

	XMMATRIX matProjLight = XMMatrixPerspectiveFovLH(ToRadian(90.00), 1.0f, 0.01, 1000.0);

	XMVECTOR light_pos = XMVectorSet(LightPos.x, LightPos.y, LightPos.z, 1.0f);
	matLight[0] = XMMatrixLookAtLH(light_pos, light_pos + XMVectorSet(-1, 0, 0, 0), XMVectorSet(0, 0, 1, 1));
	matLight[1] = XMMatrixLookAtLH(light_pos, light_pos + XMVectorSet(0, -1, 0, 0), XMVectorSet(0, 0, 1, 1));
	matLight[2] = XMMatrixLookAtLH(light_pos, light_pos + XMVectorSet(0, 0, -1, 0), XMVectorSet(0, -1, 0, 1));
	matLight[3] = XMMatrixLookAtLH(light_pos, light_pos + XMVectorSet(1, 0, 0, 0), XMVectorSet(0, 0, 1, 1));
	matLight[4] = XMMatrixLookAtLH(light_pos, light_pos + XMVectorSet(0, 1, 0, 0), XMVectorSet(0, 0, 1, 1));
	matLight[5] = XMMatrixLookAtLH(light_pos, light_pos + XMVectorSet(0, 0, 1, 0), XMVectorSet(0, -1, 0, 1));

	XMStoreFloat4x4(&constant_buffer_pl.MatLight1, XMMatrixTranspose(matLight[0]));
	XMStoreFloat4x4(&constant_buffer_pl.MatLight2, XMMatrixTranspose(matLight[1]));
	XMStoreFloat4x4(&constant_buffer_pl.MatLight3, XMMatrixTranspose(matLight[2]));
	XMStoreFloat4x4(&constant_buffer_pl.MatLight4, XMMatrixTranspose(matLight[3]));
	XMStoreFloat4x4(&constant_buffer_pl.MatLight5, XMMatrixTranspose(matLight[4]));
	XMStoreFloat4x4(&constant_buffer_pl.MatLight6, XMMatrixTranspose(matLight[5]));
	XMStoreFloat4x4(&constant_buffer_pl.MatProjLight, XMMatrixTranspose(matProjLight));
	constant_buffer_pl.PointLightPos = LightPos;
	constant_buffer_pl.LightColor = LightColor;
	constant_buffer_pl.ShadowParam = XMFLOAT4(ShadowFar, ShadowPower, 0, 0);

	D3D11_MAPPED_SUBRESOURCE resource;
	device->m_pDeviceContext->Map(m_pConstantBufferPointLight, 0, D3D11_MAP_WRITE_DISCARD, 0, &resource);
	memcpy(resource.pData, &constant_buffer_pl, sizeof(ConstantBufferPointLight));
	device->m_pDeviceContext->Unmap(m_pConstantBufferPointLight, 0);

	device->m_pDeviceContext->OMSetBlendState(device->m_pBlendState1, NULL, 0xffffffff);
	device->m_pDeviceContext->IASetInputLayout(device->m_pLayout1);
	device->m_pDeviceContext->VSSetConstantBuffers(3, 1, &m_pConstantBufferPointLight);
	device->m_pDeviceContext->PSSetConstantBuffers(3, 1, &m_pConstantBufferPointLight);

	return true;
}

bool CPointLight::DrawShadowMap(CCommonDevice *device, CChaResourceObject *object){

	if (device == NULL)
		return false;

	if (UpdateShadowMap == true)
		return false;
	UpdateShadowMap = true;

	UINT Num = 1;
	D3D11_VIEWPORT back_vp;
	device->m_pDeviceContext->RSGetViewports(&Num, &back_vp);

	D3D11_VIEWPORT vp;
	vp.Width = (float)TextureSize;
	vp.Height = (float)TextureSize;
	vp.TopLeftX = 0;
	vp.TopLeftY = 0;
	vp.MinDepth = 0.0f;
	vp.MaxDepth = 1.0f;
	device->m_pDeviceContext->RSSetViewports(1, &vp);

	SetParam(device);

	////////////////////////////////////////////////////
	// 描画

	float clear_color[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
	if (object->IsAnimated == true)
		device->m_pDeviceContext->VSSetShader(device->m_pVtxShader3, NULL, 0);
	else
		device->m_pDeviceContext->VSSetShader(device->m_pVtxShader3_1, NULL, 0);

	device->m_pDeviceContext->PSSetShader(device->m_pPxShader3, NULL, 0);
	device->m_pDeviceContext->VSSetConstantBuffers(0, 1, &device->m_pConstantBuffer1);
	device->m_pDeviceContext->PSSetConstantBuffers(0, 1, &device->m_pConstantBuffer1);
	device->m_pDeviceContext->IASetInputLayout(device->m_pLayout1);
	device->m_pDeviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
	device->m_pDeviceContext->OMSetBlendState(device->m_pBlendState1, NULL, 0xffffffff);

	for (int i = 0; i <= 5; i++){

		XMStoreFloat4x4(&constant_buffer_pl.MatLight, XMMatrixTranspose(matLight[i]));

		D3D11_MAPPED_SUBRESOURCE resource;
		device->m_pDeviceContext->Map(m_pConstantBufferPointLight, 0, D3D11_MAP_WRITE_DISCARD, 0, &resource);
		memcpy(resource.pData, &constant_buffer_pl, sizeof(ConstantBufferPointLight));
		device->m_pDeviceContext->Unmap(m_pConstantBufferPointLight, 0);

		device->m_pDeviceContext->VSSetConstantBuffers(3, 1, &m_pConstantBufferPointLight);
		device->m_pDeviceContext->PSSetConstantBuffers(3, 1, &m_pConstantBufferPointLight);

		//Depth Texture
		device->m_pDeviceContext->ClearDepthStencilView(device->m_pDepthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0, 0);
		device->m_pDeviceContext->ClearRenderTargetView(m_pShadowMapRenderTargetView[i], clear_color);

		ID3D11RenderTargetView *rtview[] = { m_pShadowMapRenderTargetView[i] };
		device->m_pDeviceContext->OMSetRenderTargets(1, rtview, device->m_pDepthStencilView);

		if (object != NULL){
			object->UpdateTransform();
			object->Draw(device);
		}
	}

	device->m_pDeviceContext->RSSetViewports(1, &back_vp);

	return true;
}

bool CPointLight::Draw(CCommonDevice *device, CChaResourceObject *object){

	SetParam(device);

	UINT Num = 1;
	D3D11_VIEWPORT back_vp;
	device->m_pDeviceContext->RSGetViewports(&Num, &back_vp);

	D3D11_VIEWPORT vp;
	vp.Width = (float) device->Width * ShadowMapResolution;
	vp.Height = (float) device->Height * ShadowMapResolution;
	vp.TopLeftX = 0;
	vp.TopLeftY = 0;
	vp.MinDepth = 0.0f;
	vp.MaxDepth = 1.0f;
	device->m_pDeviceContext->RSSetViewports(1, &vp);

	device->m_pDeviceContext->VSSetConstantBuffers(3, 1, &m_pConstantBufferPointLight);
	device->m_pDeviceContext->PSSetConstantBuffers(3, 1, &m_pConstantBufferPointLight);

	if (object->IsAnimated == true)
		device->m_pDeviceContext->VSSetShader(device->m_pVtxShader1, NULL, 0);
	else
		device->m_pDeviceContext->VSSetShader(device->m_pVtxShader1_1, NULL, 0);

	device->m_pDeviceContext->PSSetShader(device->m_pPxShader5, NULL, 0);
	device->m_pDeviceContext->VSSetConstantBuffers(0, 1, &device->m_pConstantBuffer1);
	device->m_pDeviceContext->PSSetConstantBuffers(0, 1, &device->m_pConstantBuffer1);
	device->m_pDeviceContext->VSSetConstantBuffers(3, 1, &m_pConstantBufferPointLight);
	device->m_pDeviceContext->PSSetConstantBuffers(3, 1, &m_pConstantBufferPointLight);
	device->m_pDeviceContext->PSSetShaderResources(2, 1, &m_pShadowMapShaderResourceView[0]);
	device->m_pDeviceContext->PSSetShaderResources(3, 1, &m_pShadowMapShaderResourceView[1]);
	device->m_pDeviceContext->PSSetShaderResources(4, 1, &m_pShadowMapShaderResourceView[2]);
	device->m_pDeviceContext->PSSetShaderResources(5, 1, &m_pShadowMapShaderResourceView[3]);
	device->m_pDeviceContext->PSSetShaderResources(6, 1, &m_pShadowMapShaderResourceView[4]);
	device->m_pDeviceContext->PSSetShaderResources(7, 1, &m_pShadowMapShaderResourceView[5]);
	device->m_pDeviceContext->PSSetSamplers(2, 1, &device->m_pSampleState);
	device->m_pDeviceContext->PSSetSamplers(3, 1, &device->m_pSampleState);
	device->m_pDeviceContext->PSSetSamplers(4, 1, &device->m_pSampleState);
	device->m_pDeviceContext->PSSetSamplers(5, 1, &device->m_pSampleState);
	device->m_pDeviceContext->PSSetSamplers(6, 1, &device->m_pSampleState);
	device->m_pDeviceContext->PSSetSamplers(7, 1, &device->m_pSampleState);

	float clear_color[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
	device->m_pDeviceContext->ClearDepthStencilView(device->m_pDepthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0, 0);
	device->m_pDeviceContext->ClearRenderTargetView(m_pShadowMapSoftOrgRenderTargetView, clear_color);

	ID3D11RenderTargetView *rtview[1] = { m_pShadowMapSoftOrgRenderTargetView };
	device->m_pDeviceContext->OMSetRenderTargets(1, rtview, device->m_pDepthStencilView);

	if (object != NULL){
		object->UpdateTransform();
		object->Draw(device);
	}

	device->m_pDeviceContext->RSSetViewports(1, &back_vp);

	//ソフトシャドウ(ガウスフィルタ)
	WriteSoftShadow(device);

	return true;
}

bool CPointLight::WriteSoftShadow(CCommonDevice *device){

	//ソフトシャドウ

	float clear_color[4] = { 0, 0, 0, 0 };
	device->m_pDeviceContext->OMSetRenderTargets(1, &m_pShadowMapSoftRenderTargetView, NULL);
	device->m_pDeviceContext->ClearRenderTargetView(m_pShadowMapSoftRenderTargetView, clear_color);

	device->m_pDeviceContext->VSSetShader(device->m_pVtxShader2, NULL, 0);
	device->m_pDeviceContext->PSSetShader(device->m_pPxShader4, NULL, 0);
	device->m_pDeviceContext->PSSetShaderResources(0, 1, &m_pShadowMapSoftOrgShaderResourceView);
	device->m_pDeviceContext->PSSetSamplers(0, 1, &device->m_pSampleState);

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

	device->m_pDeviceContext->IASetVertexBuffers(0, 1, &device->VertexBuffer, &stride, &offset);
	device->m_pDeviceContext->Draw(4, 0);

	return true;
}
