/////////////////////////////////////////////////
//
//  filename: DispWindow.cpp
//  author:Chafumi Touji
//  date: 2020/03/09 ver1.00
//
/////////////////////////////////////////////////

#include "StdAfx.h"
#include "Main.h"
#include "defcha3dcore.h"
#include "MainWindow.h"
#include "CustomButton.h"
#include "DispWindow.h"
#include "Config.h"

CDispWindow::CDispWindow() {

	LButtonDown = false;
	TimerID = 0;
	DownPoint = CPoint(0, 0);
	EyePosX = 0.0f;
	EyePosY = 0.0f;

	LightPosX = 10.0f;
	LightPosY = -10.0f;
	LightPosZ = -10.0f;

	Width = 0;
	Height = 0;
	IsFullScreen = false;
	BackFullScreen = false;
	IsTransparent = false;

	TransparentR = COLOR_TRANSPARENT_R;
	TransparentG = COLOR_TRANSPARENT_G;
	TransparentB = COLOR_TRANSPARENT_B;

	ChaDataObject = NULL;
	ChaResourceObject = NULL;

	DisplayWidth = ::GetSystemMetrics(SM_CXSCREEN);
	DisplayHeight = ::GetSystemMetrics(SM_CYSCREEN);

	RotationX = 3.14159265f / 2.0f - 0.5f;
	RotationY = 0.000f;
	RotationZ = 3.14159265f - 0.4f;
	CameraHeight = 0.2f;

	Zoom = 6.0f;

	m_pDepthStencilView = NULL;
	m_pSurface = NULL;

	Rock = false;
	ReloadRock = false;

	::CoInitialize(NULL);
}

CDispWindow::~CDispWindow() {

	ReleaseD3D();
	timeKillEvent(TimerID);

	::CoUninitialize();
}

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

bool CDispWindow::InitD3D() {

	///////////////////////////////////////////////////////////////////////
	//デバイスの準備

	//ファクトリー作成
	HRESULT hr = CreateDXGIFactory(IID_IDXGIFactory4, (void**)&m_pFactory);

	int adapterIndex = 0;    //列挙するデバイスのインデックス
	bool adapter_found = false;

	// 目的のデバイスを探索
	while (m_pFactory->EnumAdapters1(adapterIndex, &m_pAdapter) != DXGI_ERROR_NOT_FOUND) {
		DXGI_ADAPTER_DESC1 desc;
		m_pAdapter->GetDesc1(&desc);  // デバイスの情報を取得

		hr = D3D12CreateDevice(m_pAdapter, D3D_FEATURE_LEVEL_11_0, __uuidof(ID3D12Device), nullptr);
		if (hr == S_OK) {
			adapter_found = true;
			break;
		}

		++adapterIndex;
	}

	if (adapter_found == false) {
		hr = m_pFactory->EnumWarpAdapter(IID_PPV_ARGS(&m_pAdapter));
	}

	hr = D3D12CreateDevice(m_pAdapter, D3D_FEATURE_LEVEL_11_0, IID_ID3D12Device1, (void**)&m_pDevice);


	/////////////////////////////////////////////////////////////////////////////
	//コマンドキュー作成


	D3D12_COMMAND_QUEUE_DESC desc;
	ZeroMemory(&desc, sizeof(desc));
	desc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
	desc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
	hr = m_pDevice->CreateCommandQueue(&desc, IID_ID3D12CommandQueue, (void**)&m_pCmdQue);

	//フェンス作成
	m_pDevice->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_ID3D12Fence1, (void**)&m_pFence);
	FenceValue = 1;

	//フェンスイベント作成
	FenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);

	// コマンドアロケータを生成.
	hr = m_pDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_ID3D12CommandAllocator, (void**)&m_pCmdAlloc);

	// コマンドリストを生成.
	hr = m_pDevice->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_pCmdAlloc, nullptr, IID_ID3D12CommandList, (void**)&m_pCmdList);
	m_pCmdList->Close();


	////////////////////////////////////////////////////////////////////////////
	//スワップチェイン作成

	DXGI_SWAP_CHAIN_DESC desc2;
	ZeroMemory(&desc2, sizeof(desc2));
	desc2.BufferCount = 2;
	desc2.BufferDesc.Width = DisplayWidth;
	desc2.BufferDesc.Height = DisplayHeight;
	desc2.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
	desc2.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
	desc2.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
	desc2.OutputWindow = m_hWnd;
	desc2.SampleDesc.Count = 1;
	desc2.Windowed = TRUE;

	IDXGISwapChain* tmpSwapChain;
	hr = m_pFactory->CreateSwapChain(m_pCmdQue, &desc2, (IDXGISwapChain**)&tmpSwapChain);
	hr = tmpSwapChain->QueryInterface(__uuidof(IDXGISwapChain3), (void**)&m_pSwapChain);
	tmpSwapChain->Release();

	FrameIndex = m_pSwapChain->GetCurrentBackBufferIndex();


	///////////////////////////////////////////////////////////////////////////////////
	//レンダーターゲット作成

	D3D12_DESCRIPTOR_HEAP_DESC desc3;
	ZeroMemory(&desc3, sizeof(desc3));
	desc3.NumDescriptors = 2;
	desc3.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
	desc3.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;

	// レンダーターゲットビュー用ディスクリプタヒープを生成.
	hr = m_pDevice->CreateDescriptorHeap(&desc3, IID_ID3D12DescriptorHeap, (void**)&m_pRTVHeap);

	// レンダーターゲットビューのディスクリプタサイズを取得.
	RTVDescriptorSize = m_pDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);

	// レンダーターゲットビューを生成.
	D3D12_CPU_DESCRIPTOR_HANDLE handle = m_pRTVHeap->GetCPUDescriptorHandleForHeapStart();
	D3D12_RENDER_TARGET_VIEW_DESC desc4;
	ZeroMemory(&desc4, sizeof(desc4));
	desc4.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
	desc4.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;
	desc4.Texture2D.MipSlice = 0;
	desc4.Texture2D.PlaneSlice = 0;

	// フレームバッファ数分ループさせる.
	for (int i = 0; i <= 1; i++) {
		// バックバッファ取得.
		hr = m_pSwapChain->GetBuffer(i, IID_ID3D12Resource, (void**)&m_pRenderTarget[i]);
		// レンダーターゲットビューを生成.
		m_pDevice->CreateRenderTargetView(m_pRenderTarget[i], &desc4, handle);
		handle.ptr += RTVDescriptorSize;
	}


	/////////////////////////////////////////////////////////////////////////////////
	//デプスバッファ作成

	// 深度ステンシルビュー用ディスクリプタヒープの設定.
	D3D12_DESCRIPTOR_HEAP_DESC desc5;
	ZeroMemory(&desc5, sizeof(desc5));
	desc5.NumDescriptors = 1;
	desc5.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
	desc5.Type = D3D12_DESCRIPTOR_HEAP_TYPE_DSV;
	// 深度ステンシルビュー用ディスクリプタヒープを生成.
	hr = m_pDevice->CreateDescriptorHeap(&desc5, IID_ID3D12DescriptorHeap, (void**)&m_pDepthHeap);
	// 深度ステンシルビューのディスクリプタサイズを取得.
	DepthDescriptorSize = m_pDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_DSV);

	// 深度ステンシルビューを生成.

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

	// リソースの設定.
	D3D12_RESOURCE_DESC desc6;
	ZeroMemory(&desc6, sizeof(desc6));
	desc6.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
	desc6.Alignment = 0;
	desc6.Width = DisplayWidth;
	desc6.Height = DisplayHeight;
	desc6.DepthOrArraySize = 1;
	desc6.MipLevels = 0;
	desc6.Format = DXGI_FORMAT_D32_FLOAT;
	desc6.SampleDesc.Count = 1;
	desc6.SampleDesc.Quality = 0;
	desc6.Flags = D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
	desc6.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;

	// クリア値の設定.
	D3D12_CLEAR_VALUE clearValue;
	ZeroMemory(&clearValue, sizeof(clearValue));
	clearValue.Format = DXGI_FORMAT_D32_FLOAT;
	clearValue.DepthStencil.Depth = 1.0f;
	clearValue.DepthStencil.Stencil = 0;

	// リソースを生成.
	hr = m_pDevice->CreateCommittedResource(&prop, D3D12_HEAP_FLAG_NONE, &desc6, D3D12_RESOURCE_STATE_DEPTH_WRITE, &clearValue, IID_PPV_ARGS(&m_pDepthStencilView));

	// 深度ステンシルビューの設定.
	D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc;
	ZeroMemory(&dsvDesc, sizeof(dsvDesc));
	dsvDesc.Format = DXGI_FORMAT_D32_FLOAT;
	dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D;
	dsvDesc.Texture2D.MipSlice = 0;
//	dsvDesc.Flags = D3D12_DSV_FLAG_NONE;

	// 深度ステンシルビューを生成.
	m_pDevice->CreateDepthStencilView(m_pDepthStencilView, &dsvDesc, m_pDepthHeap->GetCPUDescriptorHandleForHeapStart());

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

	// 定数バッファ用ディスクリプターヒープを生成.
	D3D12_DESCRIPTOR_HEAP_DESC desc7;
	ZeroMemory(&desc7, sizeof(desc7));
	desc7.NumDescriptors = 1;
	desc7.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
	desc7.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
	hr = m_pDevice->CreateDescriptorHeap(&desc7, IID_ID3D12DescriptorHeap, (void**)&m_pHeap);

	//リソースマネージャー生成
	ResManager = new CResManager();
	ResManager->Init(m_pDevice, m_pHeap);

	// 定数バッファを生成.
	// ヒーププロパティの設定.
	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 desc8;
	ZeroMemory(&desc8, sizeof(desc8));
	desc8.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
	desc8.Alignment = 0;
	desc8.Width = 0x100 * 10;
	desc8.Height = 1;
	desc8.DepthOrArraySize = 1;
	desc8.MipLevels = 1;
	desc8.Format = DXGI_FORMAT_UNKNOWN;
	desc8.SampleDesc.Count = 1;
	desc8.SampleDesc.Quality = 0;
	desc8.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
	desc8.Flags = D3D12_RESOURCE_FLAG_NONE;

	// リソースを生成.
	hr = m_pDevice->CreateCommittedResource(&prop, D3D12_HEAP_FLAG_NONE, &desc8, D3D12_RESOURCE_STATE_GENERIC_READ, NULL, IID_ID3D12Resource, (void**)&m_pConstantBuffer);

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

	// 定数バッファビューを生成.
	handle = ResManager->CreateCPUHandle(&constant_buffer_begin_num);
	//	handle = m_pHeap->GetCPUDescriptorHandleForHeapStart();
	m_pDevice->CreateConstantBufferView(&bufferDesc, handle);

	// マップする. アプリケーション終了まで Unmap しない.
	// "Keeping things mapped for the lifetime of the resource is okay." とのこと。
	hr = m_pConstantBuffer->Map(0, NULL, (void**)&constant_buffer_begin);
	HRESULT h = hr;

	///////////////////////////////////////////////////////////////////////////////////
	//シグネチャ作成

	// ディスクリプタレンジの設定.
	D3D12_DESCRIPTOR_RANGE range[1];
	range[0].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
	range[0].NumDescriptors = 1;
	range[0].BaseShaderRegister = 0;
	range[0].RegisterSpace = 0;
	range[0].OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;

	// ルートパラメータの設定.
	D3D12_ROOT_PARAMETER root_param[4];
	ZeroMemory(&root_param[0], sizeof(root_param));
	root_param[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
	root_param[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
	root_param[0].Descriptor.ShaderRegister = 0;
	root_param[0].Descriptor.RegisterSpace = 0;
	root_param[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
	root_param[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
	root_param[1].Descriptor.ShaderRegister = 1;
	root_param[1].Descriptor.RegisterSpace = 0;
	root_param[2].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
	root_param[2].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
	root_param[2].Descriptor.ShaderRegister = 2;
	root_param[2].Descriptor.RegisterSpace = 0;
	root_param[3].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
	root_param[3].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
	root_param[3].DescriptorTable.NumDescriptorRanges = 1;
	root_param[3].DescriptorTable.pDescriptorRanges = &range[0];

	D3D12_STATIC_SAMPLER_DESC sampleDesc = {};
	sampleDesc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
	sampleDesc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
	sampleDesc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
	sampleDesc.BorderColor = D3D12_STATIC_BORDER_COLOR_TRANSPARENT_BLACK;
	sampleDesc.Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR;
	sampleDesc.MaxLOD = D3D12_FLOAT32_MAX;
	sampleDesc.MinLOD = 0.0f;
	sampleDesc.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;

	// ルートシグニチャの設定.
	D3D12_ROOT_SIGNATURE_DESC root_sig_desc;
	ZeroMemory(&root_sig_desc, sizeof(root_sig_desc));
	root_sig_desc.NumParameters = _countof(root_param);
	root_sig_desc.pStaticSamplers = &sampleDesc;
	root_sig_desc.NumStaticSamplers = 1;
	root_sig_desc.pParameters = root_param;
	root_sig_desc.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT;

	// シリアライズする.
	hr = D3D12SerializeRootSignature(&root_sig_desc, D3D_ROOT_SIGNATURE_VERSION_1, &Signature, &Error);
	hr = m_pDevice->CreateRootSignature(0, Signature->GetBufferPointer(), Signature->GetBufferSize(), IID_ID3D12RootSignature, (void**)&RootSignature);
	if (hr != S_OK) {
		hr = m_pDevice->GetDeviceRemovedReason();
		return false;
	}


	////////////////////////////////////////////////////////////////////////////////////
	// パイプラインステートの生成.



	// 頂点シェーダのファイルパスを検索.
//	hr = D3DCompileFromFile(L"shader.hlsl", nullptr, nullptr, "vs_main1", "vs_5_0", 0, 0, &m_pVS1Blob, nullptr);
//	hr = D3DCompileFromFile(L"shader.hlsl", nullptr, nullptr, "ps_main1", "ps_5_0", 0, 0, &m_pPS1Blob, nullptr);

	// コンパイル済み頂点シェーダを読み込む.
	hr = D3DReadFileToBlob(L"shader/vs1.cso", (ID3DBlob**)&m_pVS1Blob);
	hr = D3DReadFileToBlob(L"shader/ps1.cso", (ID3DBlob**)&m_pPS1Blob);

	// 入力レイアウトの設定.
	D3D12_INPUT_ELEMENT_DESC inputElements[] = {
		// texcood 0はテクスチャのUVです。
		// texcood 1〜8はボーンのウェイトが入力されます。WEIGHT_BONE_APPLY_NUMの数だけtexcoordを作る必要があります。(default = 8)

		{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
		{ "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
		{ "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
		{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
		{ "TEXCOORD", 1, DXGI_FORMAT_R32G32_FLOAT, 0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
		{ "TEXCOORD", 2, DXGI_FORMAT_R32G32_FLOAT, 0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
		{ "TEXCOORD", 3, DXGI_FORMAT_R32G32_FLOAT, 0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
		{ "TEXCOORD", 4, DXGI_FORMAT_R32G32_FLOAT, 0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
		{ "TEXCOORD", 5, DXGI_FORMAT_R32G32_FLOAT, 0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
		{ "TEXCOORD", 6, DXGI_FORMAT_R32G32_FLOAT, 0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
		{ "TEXCOORD", 7, DXGI_FORMAT_R32G32_FLOAT, 0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
		{ "TEXCOORD", 8, DXGI_FORMAT_R32G32_FLOAT, 0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
	};

	// ラスタライザーステートの設定.
	D3D12_RASTERIZER_DESC descRS;
	ZeroMemory(&descRS, sizeof(descRS));
	descRS.FillMode = D3D12_FILL_MODE_SOLID;
	descRS.CullMode = D3D12_CULL_MODE_NONE;
	descRS.FrontCounterClockwise = FALSE;
	descRS.DepthBias = D3D12_DEFAULT_DEPTH_BIAS;
	descRS.DepthBiasClamp = D3D12_DEFAULT_DEPTH_BIAS_CLAMP;
	descRS.SlopeScaledDepthBias = D3D12_DEFAULT_SLOPE_SCALED_DEPTH_BIAS;
	descRS.DepthClipEnable = TRUE;
	descRS.MultisampleEnable = FALSE;
	descRS.AntialiasedLineEnable = FALSE;
	descRS.ForcedSampleCount = 0;
	descRS.ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF;

	// レンダーターゲットのブレンド設定.
	D3D12_RENDER_TARGET_BLEND_DESC descRTBS = {};
	descRTBS.BlendEnable = true;
	descRTBS.LogicOpEnable = FALSE;
	descRTBS.RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;

	descRTBS.SrcBlend = D3D12_BLEND_SRC_ALPHA;
	descRTBS.DestBlend = D3D12_BLEND_INV_SRC_ALPHA;
	descRTBS.BlendOp = D3D12_BLEND_OP_ADD;
	descRTBS.SrcBlendAlpha = D3D12_BLEND_ONE;
	descRTBS.DestBlendAlpha = D3D12_BLEND_ZERO;
	descRTBS.BlendOpAlpha = D3D12_BLEND_OP_ADD;
	descRTBS.RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
	descRTBS.LogicOpEnable = FALSE;
	descRTBS.LogicOp = D3D12_LOGIC_OP_NOOP;

	// ブレンドステートの設定.
	D3D12_BLEND_DESC descBS;
	ZeroMemory(&descBS, sizeof(descBS));
	descBS.AlphaToCoverageEnable = FALSE;
	descBS.IndependentBlendEnable = FALSE;
	for (UINT i = 0; i <= D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT - 1; i++) {
		descBS.RenderTarget[i] = descRTBS;
	}

	// パイプラインステートの設定.
	D3D12_GRAPHICS_PIPELINE_STATE_DESC pipeline_desc;
	ZeroMemory(&pipeline_desc, sizeof(pipeline_desc));
	pipeline_desc.InputLayout = { inputElements, _countof(inputElements) };
	pipeline_desc.pRootSignature = RootSignature;
	pipeline_desc.VS = { m_pVS1Blob->GetBufferPointer(), m_pVS1Blob->GetBufferSize() };
	pipeline_desc.PS = { m_pPS1Blob->GetBufferPointer(), m_pPS1Blob->GetBufferSize() };
	pipeline_desc.RasterizerState = descRS;
	pipeline_desc.BlendState = descBS;
	pipeline_desc.SampleMask = UINT_MAX;
	pipeline_desc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
	pipeline_desc.NumRenderTargets = 1;
	pipeline_desc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM;
	pipeline_desc.DSVFormat = DXGI_FORMAT_D32_FLOAT;
	pipeline_desc.SampleDesc.Count = 1;
	pipeline_desc.DepthStencilState.DepthEnable = TRUE;
	pipeline_desc.DepthStencilState.DepthFunc = D3D12_COMPARISON_FUNC_LESS_EQUAL;
	pipeline_desc.DepthStencilState.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL;

	// パイプラインステートを生成.
	hr = m_pDevice->CreateGraphicsPipelineState(&pipeline_desc, IID_PPV_ARGS(&m_pPipeLineState));


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

	ChaDataObject = new CChaDataObject();
	::SetCurrentDirectory(L"./model");
	ChaDataObject->LoadDAE(DEFAULT_MODEL_NAME, EXT_DAE);
	ChaResourceObject = new CChaResourceObject();
	ChaResourceObject->CreateResource(m_pDevice, ChaDataObject, ResManager, true);
	::SetCurrentDirectory(L"..");

	return true;
}

bool CDispWindow::ReleaseD3D() {

	SAFE_RELEASE(m_pDepthStencilView);
	SAFE_RELEASE(m_pSurface);

	return true;
}

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

bool CDispWindow::SetParam(CConfig* config) {

	wcscpy_s(Path, SIZE_CHAR_MAX, config->Path);
	BKColor.x = (float)config->ViewerBKColorR / 255.0f;
	BKColor.y = (float)config->ViewerBKColorG / 255.0f;
	BKColor.z = (float)config->ViewerBKColorB / 255.0f;
	BKColor.w = (float)config->ViewerBKColorA / 255.0f;
	RotationX = config->RotationX;
	RotationZ = config->RotationZ;
	LightPosX = config->LightPosX;
	LightPosY = config->LightPosY;
	LightPosZ = config->LightPosZ;

	return true;
}

bool CDispWindow::CreateWnd(HWND ParentWnd, int x, int y, int w, int h) {

	WNDCLASSEX wcx;
	memset(&wcx, 0, sizeof(WNDCLASSEX));
	wcx.style = CS_HREDRAW | CS_VREDRAW;
	wcx.cbSize = sizeof(WNDCLASSEX);
	wcx.hInstance = NULL;
	wcx.hIcon = NULL;
	wcx.lpszMenuName = NULL;
	wcx.hCursor = LoadCursor(NULL, IDC_ARROW);
	wcx.lpfnWndProc = &CDispWindow::WindowProc;
	wcx.lpszClassName = L"CLASS_DISPWINDOW";
	RegisterClassEx(&wcx);

	Width = w;
	Height = h;
	m_hWnd = CreateWindowEx(WS_EX_LEFT, L"CLASS_DISPWINDOW", _T("ModelViewer"), WS_CHILD, x, y, w, h, ParentWnd, NULL, NULL, NULL);
	::SetWindowLongPtr(m_hWnd, GWLP_USERDATA, (LONG_PTR)this);

	::ShowWindow(m_hWnd, SW_SHOW);

	InitD3D();

	SetParam(theApp->MainWindow->Config);

	if (TimerID == 0)
		TimerID = ::timeSetEvent(50, 1, (LPTIMECALLBACK)TimeUpdateCallback, (DWORD_PTR)this, TIME_PERIODIC);

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

	return true;
}

void CALLBACK  CDispWindow::TimeUpdateCallback(UINT timer_id, UINT msg, LPTIMECALLBACK user, DWORD_PTR data1, DWORD_PTR data2) {

	CDispWindow* disp_wnd = (CDispWindow*)user;

	if (disp_wnd != NULL && disp_wnd->ChaResourceObject != NULL)
		disp_wnd->ChaResourceObject->FrameCount += 3;

	::InvalidateRect(disp_wnd->m_hWnd, NULL, false);
	::UpdateWindow(disp_wnd->m_hWnd);
}

LRESULT CDispWindow::WindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {

	CDispWindow* disp_wnd = (CDispWindow*) ::GetWindowLongPtr(hwnd, GWLP_USERDATA);
	if (disp_wnd != NULL)
		disp_wnd->DispWindowProc(hwnd, message, wParam, lParam);

	return DefWindowProc(hwnd, message, wParam, lParam);
}

LRESULT CDispWindow::DispWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {

	int width = 0;
	int height = 0;
	int x = 0;
	int y = 0;
	int delta = 0;
	int key = 0;

	switch (message) {
	case WM_PAINT:
		OnPaint();
		break;
	case WM_SIZE:
		width = GET_X_LPARAM(lParam);
		height = GET_Y_LPARAM(lParam);
		OnSize((UINT)wParam, width, height);
		break;
	case WM_LBUTTONDOWN:
		x = GET_X_LPARAM(lParam);
		y = GET_Y_LPARAM(lParam);
		OnLButtonDown((UINT)wParam, CPoint(x, y));
		break;
	case WM_LBUTTONUP:
		x = GET_X_LPARAM(lParam);
		y = GET_Y_LPARAM(lParam);
		OnLButtonUp((UINT)wParam, CPoint(x, y));
		break;
	case WM_RBUTTONDOWN:
		x = GET_X_LPARAM(lParam);
		y = GET_Y_LPARAM(lParam);
		OnRButtonDown((UINT)wParam, CPoint(x, y));
		break;
	case WM_RBUTTONUP:
		x = GET_X_LPARAM(lParam);
		y = GET_Y_LPARAM(lParam);
		OnRButtonUp((UINT)wParam, CPoint(x, y));
		break;
	case WM_MOUSEMOVE:
		::SetFocus(m_hWnd);
		x = GET_X_LPARAM(lParam);
		y = GET_Y_LPARAM(lParam);
		OnMouseMove((UINT)wParam, CPoint(x, y));
		break;
	case WM_MOUSEWHEEL:
		x = GET_X_LPARAM(lParam);
		y = GET_Y_LPARAM(lParam);
		key = GET_KEYSTATE_WPARAM(wParam);
		delta = GET_WHEEL_DELTA_WPARAM(wParam);
		OnMouseWheel(key, delta, CPoint(x, y));
		break;
	case WM_KEYDOWN:
		OnKeyDown((UINT)wParam);
		break;
	default:
		break;
	}

	return 0;
}

void CDispWindow::OnKeyDown(UINT nChar) {

	if (nChar == 32 /* enter */) {

		if (IsTransparent == false) {
			BackFullScreen = theApp->MainWindow->IsMaximized;
			IsFullScreen = true;
		}
		else {
			IsFullScreen = BackFullScreen;
		}

		IsTransparent = !IsTransparent;

		if (IsFullScreen == true) {
			::ShowWindow(theApp->MainWindow->m_hWnd, SW_MAXIMIZE);
			theApp->MainWindow->OnSize(SIZE_MAXIMIZED, DisplayWidth, DisplayHeight);
		}
		else {
			::ShowWindow(theApp->MainWindow->m_hWnd, SW_RESTORE);
			theApp->MainWindow->OnSize(SIZE_RESTORED, Width, Height);
		}
		::InvalidateRect(m_hWnd, NULL, false);
		::UpdateWindow(m_hWnd);
	}
}

void CDispWindow::OnSize(UINT nType, int cx, int cy) {

	::InvalidateRect(m_hWnd, NULL, false);
	::UpdateWindow(m_hWnd);
}

bool CDispWindow::Render() {

	D3D12_VIEWPORT vp;
	vp.Width = (float)DisplayWidth;
	vp.Height = (float)DisplayHeight;
	vp.TopLeftX = (float)0;
	vp.TopLeftY = (float)0;
	vp.MinDepth = 0.0f;
	vp.MaxDepth = 1.0f;

	matWorld = XMMatrixIdentity();
	matView = XMMatrixIdentity();
	matProj = XMMatrixIdentity();

	Eye.x = (float)(cos(RotationZ) * sin(RotationX) * Zoom);
	Eye.y = (float)(sin(RotationZ) * sin(RotationX) * Zoom);
	Eye.z = (float)(cos(RotationX) * Zoom + CameraHeight);

	XMVECTOR at = XMVectorSet(0, 0, CameraHeight, 1.0f);
	XMVECTOR eye = XMVectorSet(Eye.x, Eye.y, Eye.z, 1.0f);
	XMVECTOR up = XMVectorSet(0, 0, 1, 1.0f);
	matView = XMMatrixLookAtLH(eye, at, up);

	XMMATRIX move = XMMatrixTranslation(EyePosX, EyePosY, 0.0f);
	XMMATRIX scaling = XMMatrixScaling(-1, 1, 1);
	matView *= move * scaling;

	float wh = (float)Height / (float)Width;
	if (theApp->MainWindow->IsMaximized == true) {
		if (IsTransparent == true)
			wh = (float)DisplayHeight / (float)DisplayWidth;
		else
			wh = (float)DisplayHeight / (float)(DisplayWidth - theApp->MainWindow->MenuWindowWidth);
	}
	matProj = XMMatrixPerspectiveFovLH(0.7853f, 1.0f / wh, 1., 100.0);

	XMStoreFloat4x4(&constant_buffer.MatWorld, XMMatrixTranspose(matWorld));
	XMStoreFloat4x4(&constant_buffer.MatView, XMMatrixTranspose(matView));
	XMStoreFloat4x4(&constant_buffer.MatProj, XMMatrixTranspose(matProj));

	for (int i = 0; i <= 15; i++){
		constant_buffer.LightPos[i] = XMFLOAT4(0, 0, 0, 0);
		constant_buffer.LightColor[i] = XMFLOAT4(0, 0, 0, 0);
	}
	constant_buffer.LightPos[0] = XMFLOAT4(-Eye.x - LightPosX, -Eye.y - LightPosY, -Eye.z - LightPosZ, 0.0f);
	constant_buffer.LightColor[0] = XMFLOAT4(1, 1, 1, 0.5f);

	memcpy(constant_buffer_begin, &constant_buffer, sizeof(constant_buffer));


	// コマンドアロケータとコマンドリストをリセット.
	m_pCmdAlloc->Reset();
	m_pCmdList->Reset(m_pCmdAlloc, m_pPipeLineState);

	// ルートシグニチャを設定.
	m_pCmdList->SetGraphicsRootSignature(RootSignature);

	// ディスクリプタヒープを設定.
	m_pCmdList->SetDescriptorHeaps(1, &m_pHeap);

	// ディスクリプタヒープを設定.

	// ディスクリプタヒープテーブルを設定.
	m_pCmdList->SetGraphicsRootConstantBufferView(0, m_pConstantBuffer->GetGPUVirtualAddress());
	m_pCmdList->SetGraphicsRootDescriptorTable(1, ResManager->GetGPUHandle(constant_buffer_begin_num));

	// ビューポートの設定.
	m_pCmdList->RSSetViewports(1, &vp);

	// シザー矩形の設定.
	D3D12_RECT rect;
	rect.top = 0;
	rect.left = 0;
	rect.right = DisplayWidth;
	rect.bottom = DisplayHeight;
	m_pCmdList->RSSetScissorRects(1, &rect);

	// リソースバリアの設定.
	// Present ---> RenderTarget
	D3D12_RESOURCE_BARRIER barrier;
	ZeroMemory(&barrier, sizeof(barrier));
	barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
	barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
	barrier.Transition.pResource = m_pRenderTarget[FrameIndex];
	barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT;
	barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
	barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_FLAG_NONE;
	m_pCmdList->ResourceBarrier(1, &barrier);

	// レンダーターゲットのハンドルを取得.
	D3D12_CPU_DESCRIPTOR_HANDLE handleRTV = m_pRTVHeap->GetCPUDescriptorHandleForHeapStart();
	D3D12_CPU_DESCRIPTOR_HANDLE handleDSV = m_pDepthHeap->GetCPUDescriptorHandleForHeapStart();
	handleRTV.ptr += (FrameIndex * RTVDescriptorSize);

	// レンダーターゲットの設定.
	m_pCmdList->OMSetRenderTargets(1, &handleRTV, FALSE, &handleDSV);

	// レンダーターゲットビューをクリア.
	float clearColor[] = { 0.8f, 0.8f, 0.8f, 1.0f };
	m_pCmdList->ClearRenderTargetView(handleRTV, clearColor, 0, NULL);

	// 深度ステンシルビューをクリア.
	m_pCmdList->ClearDepthStencilView(handleDSV, D3D12_CLEAR_FLAG_DEPTH, 1.0f, 0, 0, NULL);

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

	// 描画コマンドを生成.
	ChaResourceObject->UpdateTransform();
	ChaResourceObject->Draw(m_pCmdList);

	// リソースバリアの設定.
	// RenderTarget ---> Present
	barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
	barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT;
	m_pCmdList->ResourceBarrier(1, &barrier);

	// コマンドの記録を終了.
	m_pCmdList->Close();

	// コマンド実行.
	ID3D12CommandList* ppCmdLists[] = { m_pCmdList };
	m_pCmdQue->ExecuteCommandLists(_countof(ppCmdLists), ppCmdLists);

	// 表示する.
	m_pSwapChain->Present(1, 0);

	// コマンドの完了を待機.
	WaitForGPU();

	return true;
}

void CDispWindow::WaitForGPU() {

	// シグナル状態にして，フェンス値を増加.

	UINT64 fence = FenceValue;
	HRESULT hr = m_pCmdQue->Signal(m_pFence, fence);

	FenceValue++;

	// 完了を待機.
	if (m_pFence->GetCompletedValue() < fence) {
		hr = m_pFence->SetEventOnCompletion(fence, FenceEvent);
		WaitForSingleObject(FenceEvent, INFINITE);
	}

	// フレームバッファ番号を更新.
	FrameIndex = m_pSwapChain->GetCurrentBackBufferIndex();
}

void CDispWindow::OnPaint() {

	Render();
}

void CDispWindow::OnLButtonDown(UINT nFlag, CPoint point) {

	LButtonDown = true;

	::ClientToScreen(m_hWnd, &point);

	if (IsTransparent == false)
		point.x -= theApp->MainWindow->MenuWindowWidth;

	DownPoint = point;
	LButtonDown = true;
	::SetCapture(m_hWnd);

	::InvalidateRect(m_hWnd, NULL, false);
	::UpdateWindow(m_hWnd);
}

void CDispWindow::OnRButtonDown(UINT nFlag, CPoint point) {

	RButtonDown = true;

	::ClientToScreen(m_hWnd, &point);

	if (IsTransparent == false)
		point.x -= theApp->MainWindow->MenuWindowWidth;

	DownPoint = point;
	RButtonDown = true;
	::SetCapture(m_hWnd);

	::InvalidateRect(m_hWnd, NULL, false);
	::UpdateWindow(m_hWnd);
}

void CDispWindow::OnLButtonUp(UINT nFlag, CPoint point) {

	LButtonDown = false;
	::ReleaseCapture();

	::InvalidateRect(m_hWnd, NULL, false);
	::UpdateWindow(m_hWnd);
}

void CDispWindow::OnRButtonUp(UINT nFlag, CPoint point) {

	::ReleaseCapture();
	RButtonDown = false;

	::InvalidateRect(m_hWnd, NULL, false);
	::UpdateWindow(m_hWnd);
}

void CDispWindow::OnMouseMove(UINT nFlag, CPoint point) {

	::ClientToScreen(m_hWnd, &point);

	if (IsTransparent == false)
		point.x -= theApp->MainWindow->MenuWindowWidth;

	if (RButtonDown == true) {
		int move_x = point.x - DownPoint.x;
		int move_y = point.y - DownPoint.y;
		RotationX -= move_y * 0.03f;
		RotationZ -= move_x * 0.03f;

		int rot_x = (int)(RotationX / (3.14159265f * 2.0f));
		RotationX -= ((float)rot_x) * 3.14159265f * 2.0f;
		if (RotationX < 0.001f)
			RotationX = 0.001f;
		if (RotationX > 3.14159265f)
			RotationX = 3.14159265f;

		int rot_z = (int)(RotationZ / (3.14159265f * 2.0f));
		RotationZ -= ((float)rot_z) * 3.14159265f * 2.0f;
	}
	else if (LButtonDown == true) {
		int move_x = point.x - DownPoint.x;
		int move_y = point.y - DownPoint.y;

		float eye_x = (float)(cos(RotationZ) * sin(RotationX));
		float eye_y = (float)(sin(RotationZ) * sin(RotationX));
		float eye_z = 1.0f;

		float m_x = (float) move_x;
		float m_y = (float) move_y;
		if (theApp->MainWindow->IsMaximized == true) {
			if (IsTransparent == true) {
				m_x /= (float)DisplayWidth / 1.5f;
				m_y /= (float)DisplayHeight / 1.5f;
			}
			else {
				m_x /= (float)(DisplayWidth - theApp->MainWindow->MenuWindowWidth) / 1.5f;
				m_y /= (float)DisplayHeight / 1.5f;
			}
		}
		else {
			m_x /= (float)(Width - theApp->MainWindow->MenuWindowWidth) / 1.5f;
			m_y /= (float)Height / 1.5f;
		}
		float m_z = 0.0f;

		XMVECTOR move = XMVector3Cross(XMVectorSet(eye_x, eye_y, eye_z, 0.0f), XMVectorSet(m_x, m_y, m_z, 0.0f));

		EyePosY += XMVectorGetX(move) * Zoom;
		EyePosX -= XMVectorGetY(move) * Zoom;
	}

	DownPoint = point;

	::InvalidateRect(m_hWnd, NULL, false);
	::UpdateWindow(m_hWnd);
}

void CDispWindow::OnMouseWheel(UINT nFlag, int zDelta, CPoint point) {

	Zoom -= ((float)zDelta) * 0.01f;
	if (Zoom < 0.1f)
		Zoom = 0.1f;

	::InvalidateRect(m_hWnd, NULL, false);
	::UpdateWindow(m_hWnd);
}