/////////////////////////////////////////////////
//
//  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"
#include "vs1.h"
#include "vs2.h"
#include "ps1.h"
#include "ps2.h"

CDispWindow::CDispWindow(){

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

	LightPosX = 3.0f;
	LightPosY = 5.0f;
	LightPosZ = 5.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_pDevice = NULL;
	m_pDeviceContext = NULL;
	m_pDXGI = NULL;
	m_pAdapter = NULL;
	m_pFactory = NULL;
	m_pSwapChain = NULL;
	m_pBackBuffer = NULL;
	m_pDiffuseTexture = NULL;
	m_pGDITexture = NULL;
	m_pRenderTargetView = NULL;
	m_pDiffuseRenderTargetView = NULL;
	m_pGDIRenderTargetView = NULL;
	m_pDepthStencilView = NULL;
	m_pDepthBuffer = NULL;
	m_pDepthTexture = NULL;
	m_pDiffuseShaderResourceView = NULL;
	m_pGDIShaderResourceView = NULL;
	m_pDepthShaderResourceView = NULL;
	m_pDepthRenderTargetView = NULL;
	m_pLayout = NULL;
	m_pVtxShader1 = NULL;
	m_pVtxShader2 = NULL;
	m_pPxShader1 = NULL;
	m_pPxShader2 = NULL;
	m_pConstantBuffer1 = NULL;
	m_pSampleState = NULL;
	m_pRasterizeState = NULL;
	m_pBlendState = NULL;
	m_pSurface = NULL;

	Rock = false;
	ReloadRock = false;

	::CoInitialize(NULL);
}

CDispWindow::~CDispWindow(){

	ReleaseD3D();
	timeKillEvent(TimerID);
}

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

bool CDispWindow::InitD3D(){

	HRESULT hr = D3D11CreateDevice(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, 0, NULL, 0, D3D11_SDK_VERSION, &m_pDevice, NULL, &m_pDeviceContext);
	if FAILED(hr){
		::MessageBox(m_hWnd, _T("D3DX11CreateDevice Error"), _T("Error"), MB_ICONSTOP);
		exit(1);
	}

	//インターフェース取得
	m_pDXGI = NULL;
	hr = m_pDevice->QueryInterface(__uuidof(IDXGIDevice1), (void **)&m_pDXGI);
	if FAILED(hr){
		::MessageBox(m_hWnd, _T("QueryInterface"), _T("Error"), MB_ICONSTOP);
		exit(1);
	}

	//アダプター取得
	m_pAdapter = NULL;
	hr = m_pDXGI->GetAdapter(&m_pAdapter);
	if FAILED(hr){
		::MessageBox(m_hWnd, _T("GetAdapter"), _T("Error"), MB_ICONSTOP);
		exit(1);
	}

	//ファクトリー取得
	hr = m_pAdapter->GetParent(__uuidof(IDXGIFactory), (void **)&m_pFactory);
	if FAILED(hr){
		::MessageBox(m_hWnd, _T("GetParent"), _T("Error"), MB_ICONSTOP);
		exit(1);
	}

	DXGI_SWAP_CHAIN_DESC desc;
	desc.BufferDesc.Width = DisplayWidth;
	desc.BufferDesc.Height = DisplayHeight;
	desc.BufferDesc.RefreshRate.Numerator = 0;
	desc.BufferDesc.RefreshRate.Denominator = 1;
	desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
	desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
	desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
	desc.SampleDesc.Count = 1;
	desc.SampleDesc.Quality = 0;
	desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
	desc.BufferCount = 1;
	desc.OutputWindow = m_hWnd;
	desc.Windowed = true;
	desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
	desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;

	hr = m_pFactory->CreateSwapChain(m_pDevice, &desc, &m_pSwapChain);
	if FAILED(hr){
		::MessageBox(m_hWnd, _T("Create SwapChain"), _T("Error"), MB_ICONSTOP);
		exit(1);
	}

	m_pSwapChain->SetFullscreenState(true, 0);

	hr = m_pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void **)&m_pBackBuffer);
	if FAILED(hr){
		::MessageBox(m_hWnd, _T("GetBackBuffer"), _T("Error"), MB_ICONSTOP);
		exit(1);
	}

	hr = m_pDevice->CreateRenderTargetView(m_pBackBuffer, NULL, &m_pRenderTargetView);
	if FAILED(hr){
		::MessageBox(m_hWnd, _T("Create RenderTargetView"), _T("Error"), MB_ICONSTOP);
		exit(1);
	}

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

	D3D11_TEXTURE2D_DESC desc_texture_2d;
	ZeroMemory(&desc_texture_2d, sizeof(D3D11_TEXTURE2D_DESC));
	desc_texture_2d.Width = DisplayWidth;
	desc_texture_2d.Height = DisplayHeight;
	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 | D3D11_BIND_RENDER_TARGET;
	desc_texture_2d.CPUAccessFlags = 0;
	desc_texture_2d.MiscFlags = D3D11_RESOURCE_MISC_GDI_COMPATIBLE;

	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_TEXTURE2DMS;
	desc_shader_resource.Texture2D.MipLevels = desc_texture_2d.MipLevels;
	desc_shader_resource.Texture2D.MostDetailedMip = 0;

	///////////////////////////////////////////////////////////////////////
	// ディフーズテクスチャ作成

	hr = m_pDevice->CreateTexture2D(&desc_texture_2d, NULL, &m_pDiffuseTexture);
	if FAILED(hr){
		::MessageBox(m_hWnd, _T("Create Diffuse Texture"), _T("Error"), MB_ICONSTOP);
		exit(1);
	}

	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_TEXTURE2DMS;
	desc_shader_resource.Texture2D.MipLevels = desc_texture_2d.MipLevels;
	desc_shader_resource.Texture2D.MostDetailedMip = 0;
	hr = m_pDevice->CreateShaderResourceView(m_pDiffuseTexture, &desc_shader_resource, &m_pDiffuseShaderResourceView);
	if FAILED(hr){
		::MessageBox(m_hWnd, _T("Create Diffuse Shader Reource View"), _T("Error"), MB_ICONSTOP);
		exit(1);
	}

	hr = m_pDevice->CreateRenderTargetView(m_pDiffuseTexture, NULL, &m_pDiffuseRenderTargetView);
	if FAILED(hr){
		::MessageBox(m_hWnd, _T("Create Diffuse Render Target View"), _T("Error"), MB_ICONSTOP);
		exit(1);
	}

	/*-----------------------------------------------------*/
	//HDC描画用のテクスチャ作成

	hr = m_pDevice->CreateTexture2D(&desc_texture_2d, NULL, &m_pGDITexture);
	if FAILED(hr){
		::MessageBox(m_hWnd, _T("Create GDI Texture"), _T("Error"), MB_ICONSTOP);
		exit(1);
	}

	hr = m_pDevice->CreateShaderResourceView(m_pGDITexture, &desc_shader_resource, &m_pGDIShaderResourceView);
	if FAILED(hr){
		::MessageBox(m_hWnd, _T("Create GDI Shader Reource View"), _T("Error"), MB_ICONSTOP);
		exit(1);
	}

	hr = m_pDevice->CreateRenderTargetView(m_pGDITexture, NULL, &m_pGDIRenderTargetView);
	if FAILED(hr){
		::MessageBox(m_hWnd, _T("Create GDI Render Target View"), _T("Error"), MB_ICONSTOP);
		exit(1);
	}

	m_pGDITexture->QueryInterface(__uuidof(IDXGISurface1), (void **)&m_pSurface);

	///////////////////////////////////////////////////////////////////////
	// 深度バッファ生成

	ZeroMemory(&desc_texture_2d, sizeof(D3D11_TEXTURE2D_DESC));
	desc_texture_2d.Width = DisplayWidth;
	desc_texture_2d.Height = DisplayHeight;
	desc_texture_2d.MipLevels = 1;
	desc_texture_2d.ArraySize = 1;
	desc_texture_2d.Format = DXGI_FORMAT_R32_TYPELESS;
	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_DEPTH_STENCIL | D3D11_BIND_SHADER_RESOURCE;
	desc_texture_2d.CPUAccessFlags = 0;
	desc_texture_2d.MiscFlags = 0;

	hr = m_pDevice->CreateTexture2D(&desc_texture_2d, NULL, &m_pDepthBuffer);
	if FAILED(hr){
		::MessageBox(m_hWnd, _T("Create Depth Buffer"), _T("Error"), MB_ICONSTOP);
		exit(1);
	}

	D3D11_DEPTH_STENCIL_VIEW_DESC desc_stencil_view;
	ZeroMemory(&desc_stencil_view, sizeof(D3D11_DEPTH_STENCILOP_DESC));
	desc_stencil_view.Format = DXGI_FORMAT_D32_FLOAT;
	desc_stencil_view.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
	desc_stencil_view.Texture2D.MipSlice = 0;

	m_pDepthStencilView = NULL;
	hr = m_pDevice->CreateDepthStencilView(m_pDepthBuffer, &desc_stencil_view, &m_pDepthStencilView);
	if FAILED(hr){
		::MessageBox(m_hWnd, _T("Create Depth Stencil View"), _T("Error"), MB_ICONSTOP);
		exit(1);
	}

	/*-----------------------------------------------------*/
	//シャドウマップ用の深度テクスチャ生成

	desc_texture_2d.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
	desc_texture_2d.Width = DisplayWidth;
	desc_texture_2d.Height = DisplayHeight;
	desc_texture_2d.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
	hr = m_pDevice->CreateTexture2D(&desc_texture_2d, NULL, &m_pDepthTexture);
	if FAILED(hr){
		::MessageBox(m_hWnd, _T("Create Depth Texture"), _T("Error"), MB_ICONSTOP);
		exit(1);
	}

	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_TEXTURE2DMS;
	desc_shader_resource.Texture2D.MipLevels = desc_texture_2d.MipLevels;
	desc_shader_resource.Texture2D.MostDetailedMip = 0;
	hr = m_pDevice->CreateShaderResourceView(m_pDepthTexture, &desc_shader_resource, &m_pDepthShaderResourceView);
	if FAILED(hr){
		::MessageBox(m_hWnd, _T("Create Depth Shader Reource View"), _T("Error"), MB_ICONSTOP);
		exit(1);
	}

	hr = m_pDevice->CreateRenderTargetView(m_pDepthTexture, NULL, &m_pDepthRenderTargetView);
	if FAILED(hr){
		::MessageBox(m_hWnd, _T("Create Depth Render Target View"), _T("Error"), MB_ICONSTOP);
		exit(1);
	}

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

	D3D11_BUFFER_DESC desc_buffer;
	m_pConstantBuffer1 = NULL;
	ZeroMemory(&desc_buffer, sizeof(D3D11_BUFFER_DESC));
	desc_buffer.ByteWidth = sizeof(ConstantBuffer1);
	desc_buffer.Usage = D3D11_USAGE_DEFAULT;
	desc_buffer.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
	desc_buffer.CPUAccessFlags = 0;
	desc_buffer.MiscFlags = 0;
	desc_buffer.StructureByteStride = sizeof(float);
	hr = m_pDevice->CreateBuffer(&desc_buffer, NULL, &m_pConstantBuffer1);
	if FAILED(hr){
		::MessageBox(m_hWnd, _T("Create Constant Buffer"), _T("Error"), MB_ICONSTOP);
		exit(1);
	}

	////////////////////////////////////////////////////////////////////////////////////////
	// シェーダインプットレイアウト作成

	D3D11_INPUT_ELEMENT_DESC desc_input_element[] = {

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

		{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
		{ "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 4 * 3, D3D11_INPUT_PER_VERTEX_DATA, 0 },
		{ "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 4 * 3 + 4 * 3, D3D11_INPUT_PER_VERTEX_DATA, 0 },
		{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 4 * 3 + 4 * 3 + 4 * 4, D3D11_INPUT_PER_VERTEX_DATA, 0 },
		{ "TEXCOORD", 1, DXGI_FORMAT_R32G32_FLOAT, 0, 4 * 3 + 4 * 3 + 4 * 4 + 4 * 2, D3D11_INPUT_PER_VERTEX_DATA, 0 },
		{ "TEXCOORD", 2, DXGI_FORMAT_R32G32_FLOAT, 0, 4 * 3 + 4 * 3 + 4 * 4 + 4 * 4, D3D11_INPUT_PER_VERTEX_DATA, 0 },
		{ "TEXCOORD", 3, DXGI_FORMAT_R32G32_FLOAT, 0, 4 * 3 + 4 * 3 + 4 * 4 + 4 * 6, D3D11_INPUT_PER_VERTEX_DATA, 0 },
		{ "TEXCOORD", 4, DXGI_FORMAT_R32G32_FLOAT, 0, 4 * 3 + 4 * 3 + 4 * 4 + 4 * 8, D3D11_INPUT_PER_VERTEX_DATA, 0 },
		{ "TEXCOORD", 5, DXGI_FORMAT_R32G32_FLOAT, 0, 4 * 3 + 4 * 3 + 4 * 4 + 4 * 10, D3D11_INPUT_PER_VERTEX_DATA, 0 },
		{ "TEXCOORD", 6, DXGI_FORMAT_R32G32_FLOAT, 0, 4 * 3 + 4 * 3 + 4 * 4 + 4 * 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
		{ "TEXCOORD", 7, DXGI_FORMAT_R32G32_FLOAT, 0, 4 * 3 + 4 * 3 + 4 * 4 + 4 * 14, D3D11_INPUT_PER_VERTEX_DATA, 0 },
		{ "TEXCOORD", 8, DXGI_FORMAT_R32G32_FLOAT, 0, 4 * 3 + 4 * 3 + 4 * 4 + 4 * 16, D3D11_INPUT_PER_VERTEX_DATA, 0 },
	};

	hr = m_pDevice->CreateInputLayout(desc_input_element, ARRAYSIZE(desc_input_element), &g_vs_main1, sizeof(g_vs_main1), &m_pLayout);
	if FAILED(hr){
		::MessageBox(m_hWnd, _T("Create Input Layout(1)"), _T("Error"), MB_ICONSTOP);
		exit(1);
	}

	///////////////////////////////////////////////////////////////////////////////////////////////////////////
	// vertex shader

	hr = m_pDevice->CreateVertexShader(&g_vs_main1, sizeof(g_vs_main1), NULL, &m_pVtxShader1);
	if FAILED(hr){
		::MessageBox(m_hWnd, _T("Compile Vertex Shader1"), _T("Error"), MB_ICONSTOP);
		exit(1);
	}

	hr = m_pDevice->CreateVertexShader(&g_vs_main2, sizeof(g_vs_main2), NULL, &m_pVtxShader2);
	if FAILED(hr){
		::MessageBox(m_hWnd, _T("Compile Vertex Shader2"), _T("Error"), MB_ICONSTOP);
		exit(1);
	}

	//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	// pixel shader

	hr = m_pDevice->CreatePixelShader(&g_ps_main1, sizeof(g_ps_main1), NULL, &m_pPxShader1);
	if FAILED(hr){
		::MessageBox(m_hWnd, _T("Compile Pixel Shader1"), _T("Error"), MB_ICONSTOP);
		exit(1);
	}

	hr = m_pDevice->CreatePixelShader(&g_ps_main2, sizeof(g_ps_main2), NULL, &m_pPxShader2);
	if FAILED(hr){
		::MessageBox(m_hWnd, _T("Compile Pixel Shader2"), _T("Error"), MB_ICONSTOP);
		exit(1);
	}

	//////////////////////////////////////////////////////////////////////////////////
	// サンプルステート

	D3D11_SAMPLER_DESC sample_desc;
	ZeroMemory(&sample_desc, sizeof(sample_desc));
	sample_desc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
	sample_desc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
	sample_desc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
	sample_desc.AddressW = D3D11_TEXTURE_ADDRESS_BORDER;
	sample_desc.MaxLOD = D3D11_FLOAT32_MAX;
	sample_desc.MinLOD = 0;
	sample_desc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;

	m_pDevice->CreateSamplerState(&sample_desc, &m_pSampleState);

	///////////////////////////////////////////////////////////////////////////////////////////
	//ラスタライズ

	D3D11_RASTERIZER_DESC raster_desc;
	ZeroMemory(&raster_desc, sizeof(raster_desc));
	raster_desc.MultisampleEnable = false;
	raster_desc.ScissorEnable = false;
	raster_desc.AntialiasedLineEnable = false;
	raster_desc.DepthClipEnable = true;
	raster_desc.CullMode = D3D11_CULL_NONE;
	raster_desc.FillMode = D3D11_FILL_SOLID;
	raster_desc.DepthBiasClamp = 0;
	raster_desc.SlopeScaledDepthBias = 0;

	m_pDevice->CreateRasterizerState(&raster_desc, &m_pRasterizeState);

	////////////////////////////////////////////////////////////////////
	// ブレンドステイト

	D3D11_BLEND_DESC desc_blend;
	ZeroMemory(&desc_blend, sizeof(D3D11_BLEND_DESC));
	desc_blend.AlphaToCoverageEnable = true;
	desc_blend.IndependentBlendEnable = false;
	desc_blend.RenderTarget[0].BlendEnable = true;
	desc_blend.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
	desc_blend.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
	desc_blend.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
	desc_blend.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
	desc_blend.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
	desc_blend.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
	desc_blend.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
	m_pDevice->CreateBlendState(&desc_blend, &m_pBlendState);

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

	CVertex vtx[4];

	vtx[0].Pos.x = -1;
	vtx[0].Pos.y = 1;
	vtx[0].Pos.z = 0;
	vtx[0].Normal.x = 0;
	vtx[0].Normal.y = 0;
	vtx[0].Normal.z = 1;
	vtx[0].Color.x = 0;
	vtx[0].Color.y = 0;
	vtx[0].Color.z = 0;
	vtx[0].Color.w = 0;
	vtx[0].UV.x = 0;
	vtx[0].UV.y = 0;

	vtx[1].Pos.x = 1;
	vtx[1].Pos.y = 1;
	vtx[1].Pos.z = 0;
	vtx[1].Normal.x = 0;
	vtx[1].Normal.y = 0;
	vtx[1].Normal.z = 1;
	vtx[1].Color.x = 0;
	vtx[1].Color.y = 0;
	vtx[1].Color.z = 0;
	vtx[1].Color.w = 0;
	vtx[1].UV.x = 1;
	vtx[1].UV.y = 0;

	vtx[2].Pos.x = -1;
	vtx[2].Pos.y = -1;
	vtx[2].Pos.z = 0;
	vtx[2].Normal.x = 0;
	vtx[2].Normal.y = 0;
	vtx[2].Normal.z = 1;
	vtx[2].Color.x = 0;
	vtx[2].Color.y = 0;
	vtx[2].Color.z = 0;
	vtx[2].Color.w = 0;
	vtx[2].UV.x = 0;
	vtx[2].UV.y = 1;

	vtx[3].Pos.x = 1;
	vtx[3].Pos.y = -1;
	vtx[3].Pos.z = 0;
	vtx[3].Normal.x = 0;
	vtx[3].Normal.y = 0;
	vtx[3].Normal.z = 1;
	vtx[3].Color.x = 0;
	vtx[3].Color.y = 0;
	vtx[3].Color.z = 0;
	vtx[3].Color.w = 0;
	vtx[3].UV.x = 1;
	vtx[3].UV.y = 1;

	ZeroMemory(&desc_buffer, sizeof(D3D11_BUFFER_DESC));
	desc_buffer.ByteWidth = sizeof(CVertex)* 4;
	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 = &vtx[0];
	ID3D11Buffer *vertex_buffer = NULL;
	hr = m_pDevice->CreateBuffer(&desc_buffer, &res_data_buffer, &VertexBuffer);

	return true;
}

bool CDispWindow::ReleaseD3D(){

	SAFE_RELEASE(m_pDevice);
	SAFE_RELEASE(m_pDeviceContext);
	SAFE_RELEASE(m_pDXGI);
	SAFE_RELEASE(m_pAdapter);
	SAFE_RELEASE(m_pFactory);
	SAFE_RELEASE(m_pSwapChain);
	SAFE_RELEASE(m_pBackBuffer);
	SAFE_RELEASE(m_pDiffuseTexture);
	SAFE_RELEASE(m_pGDITexture);
	SAFE_RELEASE(m_pRenderTargetView);
	SAFE_RELEASE(m_pDiffuseRenderTargetView);
	SAFE_RELEASE(m_pGDIRenderTargetView);
	SAFE_RELEASE(m_pDepthStencilView);
	SAFE_RELEASE(m_pDepthBuffer);
	SAFE_RELEASE(m_pDepthTexture);
	SAFE_RELEASE(m_pDiffuseShaderResourceView);
	SAFE_RELEASE(m_pGDIShaderResourceView);
	SAFE_RELEASE(m_pDepthShaderResourceView);
	SAFE_RELEASE(m_pDepthRenderTargetView);
	SAFE_RELEASE(m_pLayout);
	SAFE_RELEASE(m_pVtxShader1);
	SAFE_RELEASE(m_pVtxShader2);
	SAFE_RELEASE(m_pPxShader1);
	SAFE_RELEASE(m_pPxShader2);
	SAFE_RELEASE(m_pConstantBuffer1);
	SAFE_RELEASE(m_pSampleState);
	SAFE_RELEASE(m_pRasterizeState);
	SAFE_RELEASE(m_pBlendState);
	SAFE_RELEASE(VertexBuffer);
	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, (UINT_PTR) this);

	::ShowWindow(m_hWnd, SW_SHOW);

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

	InitD3D();

	SetParam(theApp->MainWindow->Config);

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

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

	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(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(){

	D3D11_VIEWPORT vp;
	vp.Width = (float)DisplayWidth;
	vp.Height = (float)DisplayHeight;
	vp.TopLeftX = (float)(DisplayWidth - vp.Width) / 2.00f;
	vp.TopLeftY = (float)(DisplayHeight - vp.Height) / 2.00f;
	vp.MinDepth = 0.0f;
	vp.MaxDepth = 1.0f;
	m_pDeviceContext->RSSetViewports(1, &vp);

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

	Eye.x = cos(RotationZ) * sin(RotationX) * Zoom;
	Eye.y = sin(RotationZ) * sin(RotationX) * Zoom;
	Eye.z = 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(ToRadian(45.00), 1.0f / wh, 1., 100.0);

	ConstantBuffer1 constant_buffer1;
	XMStoreFloat4x4(&constant_buffer1.MatWorld, XMMatrixTranspose(matWorld));
	XMStoreFloat4x4(&constant_buffer1.MatView, XMMatrixTranspose(matView));
	XMStoreFloat4x4(&constant_buffer1.MatProj, XMMatrixTranspose(matProj));
	constant_buffer1.Light = XMFLOAT4(Eye.x + LightPosX, Eye.y + LightPosY, Eye.z + LightPosZ, 1.0f);

	m_pDeviceContext->UpdateSubresource(m_pConstantBuffer1, 0, NULL, &constant_buffer1, 0, 0);

	m_pDeviceContext->RSSetState(m_pRasterizeState);
	m_pDeviceContext->OMSetBlendState(m_pBlendState, NULL, 0xffffffff);
	m_pDeviceContext->VSSetShader(m_pVtxShader1, NULL, 0);
	m_pDeviceContext->IASetInputLayout(m_pLayout);

	m_pDeviceContext->VSSetConstantBuffers(0, 1, &m_pConstantBuffer1);
	m_pDeviceContext->PSSetConstantBuffers(0, 1, &m_pConstantBuffer1);
	m_pDeviceContext->PSSetSamplers(1, 1, &m_pSampleState);
	m_pDeviceContext->PSSetSamplers(0, 1, &m_pSampleState);
	m_pDeviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

	//Depth Texture
	float clear_color[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
	m_pDeviceContext->ClearDepthStencilView(m_pDepthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0, 0);
	m_pDeviceContext->ClearRenderTargetView(m_pDepthRenderTargetView, clear_color);
	m_pDeviceContext->ClearRenderTargetView(m_pDiffuseRenderTargetView, clear_color);

	ID3D11RenderTargetView *rtview[2] = { m_pDiffuseRenderTargetView, m_pDepthRenderTargetView };
	m_pDeviceContext->OMSetRenderTargets(2, rtview, m_pDepthStencilView);
	m_pDeviceContext->PSSetShader(m_pPxShader1, NULL, 0);

	if (ChaResourceObject != NULL){
		ChaResourceObject->UpdateTransform(m_pDevice, ChaDataObject);
		ChaResourceObject->Draw(m_pDeviceContext); 
	}

	if (IsTransparent == false){
		float clear_color2[4] = { BKColor.x, BKColor.y, BKColor.z, 1.0f };
		m_pDeviceContext->OMSetRenderTargets(1, &m_pGDIRenderTargetView, NULL);
		m_pDeviceContext->ClearRenderTargetView(m_pGDIRenderTargetView, clear_color2);
		m_pDeviceContext->OMSetRenderTargets(1, &m_pRenderTargetView, NULL);
		m_pDeviceContext->ClearRenderTargetView(m_pRenderTargetView, clear_color2);
	}
	else{
		float clear_color2[4] = { (float)TransparentR / 255.0f, (float)TransparentG / 255.0f, (float)TransparentB / 255.0f , 1.0f };
		m_pDeviceContext->OMSetRenderTargets(1, &m_pGDIRenderTargetView, NULL);
		m_pDeviceContext->ClearRenderTargetView(m_pGDIRenderTargetView, clear_color2);
	}

	m_pDeviceContext->VSSetShader(m_pVtxShader2, NULL, 0); 
	m_pDeviceContext->PSSetShader(m_pPxShader2, NULL, 0);
	m_pDeviceContext->PSSetShaderResources(0, 1, &m_pDiffuseShaderResourceView);
	m_pDeviceContext->PSSetShaderResources(1, 1, &m_pDepthShaderResourceView);
	m_pDeviceContext->PSSetSamplers(1, 1, &m_pSampleState);
	m_pDeviceContext->PSSetSamplers(0, 1, &m_pSampleState);

	UINT stride = sizeof(CVertex);
	UINT offset = 0;
	m_pDeviceContext->IASetVertexBuffers(0, 1, &VertexBuffer, &stride, &offset);
	m_pDeviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);

	m_pDeviceContext->Draw(4, 0);

	return true;
}

void CDispWindow::OnPaint(){

	Rock = false;

	PAINTSTRUCT ps;
	HDC hdc = ::BeginPaint(m_hWnd, &ps);
	if (m_pDevice != NULL && Rock == false && ReloadRock == false ){

		static bool prev_transparent = false;

		if (IsTransparent == false){
			Rock = true;
			Render(); 
			m_pSwapChain->Present(0, 0);
			Rock = false;

			if (prev_transparent == true){
				prev_transparent = false;

				HDC hDC = NULL;
				m_pSurface->GetDC(false, &hDC);
				BitBlt(hdc, 0, 0, DisplayWidth, DisplayHeight, hDC, 0, 0, SRCCOPY);
				m_pSurface->ReleaseDC(NULL);
			}
		}
		else{
			prev_transparent = true;

			Rock = true;
			Render();

			::SetWindowPos(theApp->MainWindow->m_hWnd, HWND_TOPMOST, 0, 0, DisplayWidth, DisplayHeight, SWP_SHOWWINDOW);

			HDC hDC = NULL;
			m_pSurface->GetDC(false, &hDC);
			BitBlt(hdc, 0, 0, DisplayWidth, DisplayHeight, hDC, 0, 0, SRCCOPY);
			m_pSurface->ReleaseDC(NULL);

			Rock = false;
		}
	}
	::EndPaint(m_hWnd, &ps);
}
 
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 = cos(RotationZ) * sin(RotationX);
		float eye_y = sin(RotationZ) * sin(RotationX);
		float eye_z = 1.0;

		float m_x = move_x;
		float m_y = 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);
}