#include "DeferredShadowConfidence.h"

#include "ShadowApp.h"
#include "ShadowScene.h"
#include "DirectionalLight.h"

#include "..\DXFunctions\FontManager.h"
#include "..\GameGUI\MenuManager.h"
#include "..\GameGUI\Menu.h"
#include "..\GameGUI\Panel.h"
#include "..\GameGUI\Label.h"
#include "..\GameGUI\CheckBox.h"
#include "..\GameGUI\ComboBox.h"
#include "..\GameGUI\Slider.h"

DeferredShadowConfidence::DeferredShadowConfidence(ShadowApp* const pApp) : DeferredShadowTechnique(pApp)
{
	m_FXConfShadow = m_pApp->GetDevice()->GetShaderManager()->CreateFX("Shaders\\ConfidenceShadow.fx");

	m_FXConfTest = m_pApp->GetDevice()->GetShaderManager()->CreateFX("Shaders\\ConfidenceTest.fx");

	m_Method = CM_B2FFOCUS;
	m_bPCFPreTest = false;
	m_ConfT[CM_SIMPLE] = 0.8f;
	m_ConfT[CM_ADAPTED] = 1;
	m_ConfT[CM_B2FFOCUSDYNAMIC] = 1;
	m_ConfT[CM_B2FFOCUS] = 1;
	m_MaxJitter = 50;
	m_Threshold = 1000;
	m_FramesBelow = 2;
	m_B2FFocusScale = 0.45f;
	m_JitterType = SMJT_HALTON;

	CreateMenu();
}

DeferredShadowConfidence::~DeferredShadowConfidence(void)
{
	SAFERELEASE(m_FXConfShadow);
}

void DeferredShadowConfidence::RenderShadowMask(void)
{
	if (m_FXConfShadow->IsCompiled() && m_FXConfTest->IsCompiled())
	{
		m_FXConfShadow->SetMatrix("g_matInvProj", DXMatrix::InvertMatrix(m_pApp->GetActiveCam().GetProjMatrix()));
		m_FXConfShadow->SetMatrix("g_matInvView", DXMatrix::InvertMatrix(m_pApp->GetActiveCam().GetViewMatrix()));
		m_FXConfShadow->SetMatrix("g_matInvViewProj",  DXMatrix::InvertMatrix(m_pApp->GetActiveCam().GetViewProjMatrix()));

		m_FXConfShadow->SetTexture("g_texNormal", m_pApp->m_DSNormal->GetSurface());
		m_FXConfShadow->SetTexture("g_texDiffuse", m_pApp->m_DSDiffuse->GetSurface());

		if (m_pApp->GetWorldPosType() == WPT_WORLDPOS)
			m_FXConfShadow->SetTexture("g_texWorld", m_pApp->m_DSWorld->GetSurface());
		else
			m_FXConfShadow->SetTexture("g_texDepth", m_pApp->m_DSDepth->GetSurface());

		if (m_pApp->GetUseIDBuffer())
			m_FXConfShadow->SetTexture("g_texID", m_pApp->m_DSID->GetSurface());
		
		m_FXConfShadow->SetTexture("SM_ShadowMap", m_pApp->m_SM->GetShadowMap());
		m_FXConfShadow->SetTexture("SM_IDBuffer", m_pApp->m_SM->GetIDBuffer());
		m_FXConfShadow->SetFloat("SM_ShadowMapSize", m_pApp->m_SM->GetShadowMapSize());
		m_FXConfShadow->SetMatrix("SM_matSM", m_pApp->m_SM->GetSMMatrix());

		m_FXConfShadow->SetFloat("SM_DetphBias", m_pApp->GetConstBias());
		m_FXConfShadow->SetFloat("SM_SlopeBias", m_pApp->GetSlopeBias());

		float rtsize[2] = {m_pApp->GetDevice()->GetViewPort()->GetWidth(), m_pApp->GetDevice()->GetViewPort()->GetHeight()};
		m_FXConfShadow->SetFloatArray("g_RTSize", rtsize, 2);
		
		m_FXConfShadow->SetFloatArray("g_LightDir", m_pApp->GetActiveScene()->GetLight()->GetDirection(), 3);
		
		//m_FXConfShadow->SetFloat("g_ConfScale", 1);
		
		//RenderOptConf();

		m_FXConfShadow->SetFloat("g_MaxPasses", m_pApp->m_Config.MaxJitter + 1);

		m_pApp->GetDevice()->SetStencilEnalbe(false);

		if(m_Method != CM_SIMPLE)
		{
			m_pApp->RenderOptConf(1);
		}

		m_FXConfShadow->SetFloat("g_ShadowConfT", m_ConfT[m_Method]);

		m_FXConfShadow->SetTexture("g_texOptConf", m_pApp->m_OptConf->GetSurface());
		m_FXConfShadow->SetFloat("g_ConfScale", 1);

		//			m_DSDepthStencil->StartRender(0);
		
		float shadowfarstart = m_pApp->GetActiveScene()->GetLight()->GetShadowFar();
		float currfar = m_pApp->GetActiveScene()->GetLight()->GetShadowFar();
		float smworldsizestart = m_pApp->m_SM->GetSMWorldSize();

		IDirect3DQuery9* pOcclusionQuery;
		m_pApp->GetDevice()->GetDevice()->CreateQuery(D3DQUERYTYPE_OCCLUSION, &pOcclusionQuery);

		m_pApp->m_SM->SetJitterType(m_JitterType);

		if(m_pApp->m_VisType == VIS_SAMPLE && (m_Method == CM_SIMPLE || m_Method == CM_ADAPTED))
		{
			m_pApp->GetActiveScene()->GetLight()->RenderShadowMap();
			m_pApp->DrawSampleVis();
		}

		unsigned nochange = 0;
		unsigned cnt = 0;
		unsigned ijitter = 0;

		while(true)
		{
			m_pApp->m_SM->Jitter(ijitter++);

			
			//m_Device->SetStencilEnalbe(false);

			m_pApp->GetActiveScene()->GetLight()->RenderShadowMap();

			if(m_Method != CM_SIMPLE && m_JitterType == SMJT_LISPSMN && cnt > 0) //pass gets rendered anyway
			{
				m_pApp->RenderOptConf(1);
			}

			//m_Device->SetStencilEnalbe(true);
			
			//m_FXDS->SetMatrix("SM_matSMTex", m_SM->GetSMTexMatrix());

			//needs  to be set each iteration, because of jitter
			m_FXConfShadow->SetMatrix("SM_matSM", m_pApp->m_SM->GetSMMatrix());

			//if(!cnt && m_SampleVis)
			if(m_pApp->m_VisType == VIS_SAMPLE && (m_Method == CM_B2FFOCUS || m_Method == CM_B2FFOCUSDYNAMIC))
			{
				//m_Device->SetStencilEnalbe(false);

				m_pApp->DrawSampleVis();
/*
				m_pApp->m_DSSampleVis->StartRender(0);

				m_pApp->GetDevice()->Clear(D3DCLEAR_TARGET, 0, 0, 0);

				m_pApp->m_FXDS->SetTechnique("RenderTest");

				m_pApp->RenderQuad(m_pApp->GetDevice()->GetViewPort()->GetWidth(),m_pApp->GetDevice()->GetViewPort()->GetHeight(), m_pApp->m_FXDS);
				
				m_pApp->m_DSSampleVis->EndRender();*/

				//m_Device->SetStencilEnalbe(true);
			}

			//D3DXSaveTextureToFile("bla.dds",D3DXIFF_DDS,m_DSTest->GetSurface()->GetSurface(),NULL);

			if(m_pApp->m_BenchType == BT_CONVERGENCE && m_pApp->m_RenderRef)
				m_pApp->m_DSShadowRef->StartRender(0);
			else
				m_pApp->m_DSShadow[0]->StartRender(0);

			//m_DSPass->StartRender(1);

			//if(!optconfup2date)
			//{
			//	RenderOptConf();
			//	optconfup2date = true;
			//}

			if (!cnt)
			{
				m_pApp->GetDevice()->Clear(D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER | D3DCLEAR_STENCIL, 0, 0, 0);
			}

			XString tech = "RenderShadow";

			/*if (m_Method == CM_B2FFOCUS || m_Method == CM_B2FFOCUSDYNAMIC)
			{
				tech.appand("_Adapted");
			}
			else*/
			{
				if(m_Method == CM_SIMPLE)
				{
					tech.appand("_Simple");

					if (m_pApp->GetSMFiltering())
						tech.appand("_Filter");
				}
				else
				{
					if (m_pApp->GetSMFiltering())
						tech.appand("_Accumulate");
					else
						tech.appand("_Adapted");
				}

				if(!cnt) 
				{
					if(m_bPCFPreTest)
						tech.appand("_PreTest");
				}

				if (m_Method == CM_B2FFOCUS || m_Method == CM_B2FFOCUSDYNAMIC)
				{
					tech.appand("_Clip");
				}
			}

			if (m_pApp->GetWorldPosType() == WPT_DEPTH)
				tech.appand("_Depth");
			else if (m_pApp->GetWorldPosType() == WPT_LINEARDEPTH)
				tech.appand("_LinearDepth");
			else if (m_pApp->GetWorldPosType() == WPT_WORLDPOS)
				tech.appand("_World");

			if (m_pApp->GetUseIDBuffer())
				tech.appand("_ID");

			m_FXConfShadow->SetTechnique(tech);

			m_FXConfShadow->SetFloat("g_iPass", cnt);
			
			pOcclusionQuery->Issue(D3DISSUE_BEGIN);

			m_pApp->RenderFSQuad(m_FXConfShadow);

			pOcclusionQuery->Issue(D3DISSUE_END);

			// Force the driver to execute the commands from the command buffer.
			// Empty the command buffer and wait until the GPU is idle.
			while(S_FALSE == pOcclusionQuery->GetData(&m_pApp->m_LastPixelDrawed, sizeof(DWORD), D3DGETDATA_FLUSH ));

			if(m_pApp->m_LastPixelDrawed < m_Threshold)
				nochange++;
			else
				nochange = 0;
			m_pApp->m_PixelSet[cnt] = m_pApp->m_LastPixelDrawed;
		
			bool exit = false;

			if(m_Method == CM_B2FFOCUS || m_Method == CM_B2FFOCUSDYNAMIC)
			{
				Camera c = m_pApp->GetActiveScene()->GetCamera();
				c.SetPerspectiveProj(m_pApp->GetCurrentMode().Width, m_pApp->GetCurrentMode().Height, 1, currfar);

				float tfar;
				
				if (m_Method == CM_B2FFOCUSDYNAMIC)
					tfar = TestConfReached(1, currfar, 5, c);
				else
					tfar = currfar * m_B2FFocusScale;

				if(tfar < currfar && tfar > 1) 
				{
					currfar = tfar; 
					c.SetPerspectiveProj(m_pApp->GetCurrentMode().Width, m_pApp->GetCurrentMode().Height, 1, currfar);	
					ViewFrustum f(c);
					BoundingMesh b(f);
					b.ClipByAABB(m_pApp->GetActiveScene()->GetVisibleBound());
					m_pApp->GetShadowMapping()->Update(b.BuildAABB(), c, m_pApp->GetActiveScene()->GetLight()->GetDirection());	
					m_pApp->GetActiveScene()->GetLight()->UpdateShadowFarPlane(&b);
					ijitter = 0;

					//filter renderjobs
					D3DXPLANE p;
					float closertocam = shadowfarstart - currfar;
					//DXVector3 off = -m_Cam.GetViewDirVector() * closertocam;
					//D3DXPlaneFromPointNormal(&p, (D3DXVECTOR3*)&(m_ShadowFarPoint + off*0.95f), (D3DXVECTOR3*)&m_ShadowFarPlaneNormal);
					//D3DXPlaneFromPointNormal(&p, (D3DXVECTOR3*)&(m_pApp->GetActiveScene()->GetLight()->GetShadowFarPoint()), (D3DXVECTOR3*)&m_pApp->GetActiveScene()->GetLight()->GetShadowFarPlaneNormal());

					m_pApp->GetActiveScene()->GetLight()->CullShadowCasterRenderJobs(DXPlane::FromPointNormal(m_pApp->GetActiveScene()->GetLight()->GetShadowFarPoint(), m_pApp->GetActiveScene()->GetLight()->GetShadowFarPlaneNormal()));  

					if (m_pApp->GetActiveScene()->GetLight()->GetShadowCasterCount() == 0)
						exit = true;
					 
					//increase conf with focused shadow map
					//m_FXDS->SetFloat("g_ConfScale", shadowfarstart / currfar); 
					//float newconfscale = shadowfarstart / currfar;
					float actconfscale = smworldsizestart / m_pApp->GetShadowMapping()->GetSMWorldSize();
					/*if(newconfscale > 100)
					{
						optconfup2date = false; 
						m_FXDS->SetFloat("g_ConfScale", 1); 
						shadowfarstart = currfar;
					}
					else*/
					{
						m_FXConfShadow->SetFloat("g_ConfScale", actconfscale);
					}
					//m_FXDS->SetFloat("g_ConfScale", shadowfarstart / (currfar + closertocam * 0.02));
					//m_FXDS->SetFloat("g_ConfScale", 1);

				/*	if (1)
					{
						m_pApp->RenderOptConf(1);
						m_FXConfShadow->SetFloat("g_ConfScale", 1); 
					}*/
					//optconfup2date = false;  

					if (tfar < 0.1f)
						exit = true;

					if (m_pApp->m_LastPixelDrawed <= 0)
						exit = true;;
				}
			}

			//end rendering of dsshadowref after testconfidence because the depth surface is needed
			//m_DSPass->EndRender();
			if(m_pApp->m_BenchType == BT_CONVERGENCE && m_pApp->m_RenderRef)
				m_pApp->m_DSShadowRef->EndRender();
			else
				m_pApp->m_DSShadow[0]->EndRender();

			if (exit)
				break;
			
			//int ScreenPixels = m_Device->GetViewPort()->Width * m_Device->GetViewPort()->Height;
			if (cnt >= m_MaxJitter)
				break;

			//if(!usebrandnew)
			if(nochange >= m_FramesBelow)
				break;

			cnt++;
		}
		
		pOcclusionQuery->Release();
		
		//m_Device->SetStencilEnalbe(false);
	}
}

float DeferredShadowConfidence::TestConfReached(const float vnear, const float vfar, const int maxsteps, const Camera& cam) const
{
	IDirect3DQuery9* pOcclusionQuery;
	m_pApp->GetDevice()->GetDevice()->CreateQuery(D3DQUERYTYPE_OCCLUSION, &pOcclusionQuery);

	//rendertarget, all textures needed and vertexbuffer for fullscreen quad already set
	DXVector4* StartEnd = new DXVector4[maxsteps];
	//LPDIRECT3DQUERY9* Queries = new LPDIRECT3DQUERY9[maxsteps];

	//init values
	float currnear = vnear;
	float currdist = (vfar - vnear) / 2; 
	float currfar = currdist;
	for(int i = 0; i < maxsteps; i++)
	{
		if(i == maxsteps - 1)
			currfar = vfar;

		D3DXVECTOR3 n(0, 0, currnear);
		D3DXVec3TransformCoord(&n, &n, (D3DXMATRIX*)&cam.GetProjMatrix());
		D3DXVECTOR3 f(0, 0, currfar);
		D3DXVec3TransformCoord(&f, &f, (D3DXMATRIX*)&cam.GetProjMatrix());

		StartEnd[i] = DXVector4(n.z, f.z, currnear, currfar);

		//m_Device->GetDevice()->CreateQuery(D3DQUERYTYPE_OCCLUSION, Queries+i);

		currnear = currfar;
		currdist *= 0.5f;
		currfar += currdist;
	}

	m_FXConfTest->SetTechnique("TestDepthConfReached");
	
	//test how many pixel havent reached depth value of 1
	m_pApp->GetDevice()->SetColorWriteEnable(0);

	m_FXConfTest->SetTexture("g_texDepth", m_pApp->m_DSDepth->GetSurface());

	//fullscreen quad has depth of 1 and zfunc == LESS, so only pixels where conf not reached are drawed

	int j;

	//m_Device->SetStencilZFail( D3DSTENCILOP_INCR );

	//TODO: test whats faster: do all queries and find distance; do until distance found
	for(j = maxsteps-1; j>=0; j--)
	{
		m_FXConfTest->SetFloat("g_fTCRNear", StartEnd[j].x);
		m_FXConfTest->SetFloat("g_fTCRFar", StartEnd[j].y);

		//m_FXDS->SetFloat("g_fTCRNear", 0.999); 
		//m_FXDS->SetFloat("g_fTCRFar", 1);

		pOcclusionQuery->Issue(D3DISSUE_BEGIN);

		m_pApp->RenderFSQuad(m_FXConfTest);

		pOcclusionQuery->Issue(D3DISSUE_END);

		unsigned pixels = 0;
		while(S_FALSE == pOcclusionQuery->GetData(&pixels, sizeof(DWORD), D3DGETDATA_FLUSH ));

		int drawT = 100;
		if (pixels > 100) 
		{
			break; 
		}

		//test: usually there are no more than 1 or max 2 iterations that will pass, so it should be most efficient to only check first and see if it is ok
		//j--;
		//break;
	}

	//m_Device->SetStencilZFail( D3DSTENCILOP_KEEP );

	m_pApp->GetDevice()->SetColorWriteEnable(D3DCOLORWRITEENABLE_ALPHA | D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_RED);

	float ret;

	//return near from last pass with pixels <= 30
	if(j < maxsteps-1)
		ret = StartEnd[j + 1].z; //camera near (new optimal camera far)
	else 
		ret = vfar;

	delete [] StartEnd;

	pOcclusionQuery->Release();

	return ret;
}

/*void DeferredShadowConfidence::DrawControls(void) 
{
	XString txt;
	XString controls;

	txt.appand("Method: ");
	txt.appand(m_Method == CM_SIMPLE ? "Simple" : m_Method == CM_ADAPTED ? "Adapted" : m_Method == CM_B2FFOCUSDYNAMIC ? "B2FFocus Dyn" : m_Method == CM_B2FFOCUS ? "B2FFocus" : "Unknown");
	controls.appand("[y/x]\n");

	txt.appand("\nConfidence: ");
	txt.appand(m_ConfT[m_Method]);
	controls.appand("[z/h]\n");

	txt.appand("\nMaxJitter: ");
	txt.appand(m_MaxJitter);
	controls.appand("[-/+]\n");

	txt.appand("\nPCFPreTest: ");
	txt.appand(m_bPCFPreTest ? "true" : "false");
	controls.appand("[F9]\n");

	if (m_Method == CM_B2FFOCUS)
	{
		txt.appand("\nB2FFocusScale: ");
		txt.appand(m_B2FFocusScale);
		controls.appand("[v/b]\n");
	}

	m_pApp->m_Font->Draw(txt, 251, 91, 0xff000000);
	m_pApp->m_Font->Draw(txt, 250, 90, 0xffffffff);
	
	m_pApp->m_Font->Draw(controls, 401, 91, 0xff000000);
	m_pApp->m_Font->Draw(controls, 400, 90, 0xffffffff);
}*/

void DeferredShadowConfidence::UpdateInput(void) 
{
	if (m_pApp->m_DI.GetKey(DIK_X) & KEY_UP)
	{
		int m = m_Method + 1;
		if(m >= CM_COUNT)
			m = 0;
		m_Method = (CONFMETHOD)m;
	}
	else if (m_pApp->m_DI.GetKey(DIK_Z) & KEY_UP)
	{
		int m = m_Method - 1;
		if(m < 0)
			m = CM_COUNT - 1;
		m_Method = (CONFMETHOD)m;
	}

	if (m_pApp->m_DI.GetKey(DIK_F9) & KEY_UP)
	{
		((CheckBox*)m_pMenu->GetChildByID(99871))->SetChecked(!m_bPCFPreTest);
	}

	float confstep = m_Method == CM_SIMPLE ? 0.05f : 0.01f;
	if (m_pApp->m_DI.GetKey(DIK_Y) & KEY_UP)
	{
		if (m_ConfT[m_Method] < 1)
			m_ConfT[m_Method] += confstep;
	}
	else if (m_pApp->m_DI.GetKey(DIK_H) & KEY_UP)
	{
		if (m_ConfT[m_Method] > 0)
			m_ConfT[m_Method] -= confstep;
	}

	if (m_pApp->m_DI.GetKey(DIK_NUMPADMINUS) & KEY_DOWN || m_pApp->m_DI.GetKey(DIK_MINUS) & KEY_DOWN)
	{
		if (m_MaxJitter > 200)
			m_MaxJitter -= 50;
		else if (m_MaxJitter > 100)
			m_MaxJitter -= 20;
		else if (m_MaxJitter > 50)
			m_MaxJitter -= 10;
		else if (m_MaxJitter > 5)
			m_MaxJitter -= 5;
		else if (m_MaxJitter > 0)
			m_MaxJitter--;

		((Slider*)m_pMenu->GetChildByID(987))->SetValue(m_MaxJitter);
	}
	else if (m_pApp->m_DI.GetKey(DIK_NUMPADPLUS) & KEY_DOWN || m_pApp->m_DI.GetKey(DIK_RBRACKET) & KEY_DOWN)
	{
		if (m_MaxJitter < 5)
			m_MaxJitter++;
		else if (m_MaxJitter < 50)
			m_MaxJitter += 5;
		else if (m_MaxJitter < 100)
			m_MaxJitter+= 10;
		else if (m_MaxJitter < 200)
			m_MaxJitter += 20;
		else if (m_MaxJitter < JITTERLIMIT)
			m_MaxJitter += 50;

		if(m_MaxJitter > JITTERLIMIT)
			m_MaxJitter = JITTERLIMIT;

		((Slider*)m_pMenu->GetChildByID(987))->SetValue(m_MaxJitter);
	}

	if (m_Method == CM_B2FFOCUS)
	{
		if (m_pApp->m_DI.GetKey(DIK_B) & KEY_UP)
		{
			if (m_B2FFocusScale < 1)
				m_B2FFocusScale += 0.1f;
		}
		else if (m_pApp->m_DI.GetKey(DIK_V) & KEY_UP)
		{
			if (m_B2FFocusScale > 0)
				m_B2FFocusScale -= 0.1f;
		}
	}
}

void DeferredShadowConfidence::SetMethod(const CONFMETHOD m) 
{
	m_Method = m;
	Slider* slConf = (Slider*)m_pMenu->GetChilds()[0]->GetInfo()->GetChilds().GetElement(345)->GetInfo();
	slConf->SetValue((int)(m_ConfT[m_Method] * 100));
}

void DeferredShadowConfidence::CreateMenu(void)
{
	m_pMenu = new Menu(m_pApp->GetMenuManager(), 122);

	Panel* pnBack = new Panel(m_pApp->GetMenuManager(), 1111);
	pnBack->SetPosition(300, 85);
	pnBack->SetSize(250, 380);
	pnBack->SetOpacity(0.8f);
	pnBack->SetTexture(m_pApp->GetDevice()->GetTextureManager()->CreateTexture("GUI\\ck.png", FMT_A8R8G8B8, POOL_MANAGED));
	pnBack->SetAlphaBlend(true);
	pnBack->SetFixedBorder(4);

	m_pMenu->AddChild(pnBack);

	FontParam fp;
	fp.m_Height = 16;
	Font* font = m_pApp->GetDevice()->GetFontManager()->Create(fp);

	int y = 20;
	Label *lbtech = new Label(m_pApp->GetMenuManager(), 2);
	lbtech->SetPosition(20, y);
	lbtech->SetSize(100, 20);
	lbtech->SetText("ConfTech: ");
	lbtech->SetFont(font);

	pnBack->AddChild(lbtech);

	ComboBox* cbConfTech = new ComboBox(m_pApp->GetMenuManager(), 0);
	cbConfTech->SetUserData(this);
	cbConfTech->SetPosition(100, y);
	cbConfTech->SetSize(130, 22);
	cbConfTech->SetDropDownHeight(83);
	cbConfTech->SetDropDownItemHeight(19);
	cbConfTech->AddItem("Simple");
	cbConfTech->AddItem("Adapted");
	cbConfTech->AddItem("Reduction Dyn");
	cbConfTech->AddItem("Reduction");
	cbConfTech->SetTexture(m_pApp->GetDevice()->GetTextureManager()->CreateTexture("GUI\\input.png", FMT_A8R8G8B8, POOL_MANAGED), false, 3, 
					m_pApp->GetDevice()->GetTextureManager()->CreateTexture("GUI\\combo.png", FMT_A8R8G8B8, POOL_MANAGED), true,
					m_pApp->GetDevice()->GetTextureManager()->CreateTexture("GUI\\list.png", FMT_A8R8G8B8, POOL_MANAGED), 
					m_pApp->GetDevice()->GetTextureManager()->CreateTexture("GUI\\listsel.png", FMT_A8R8G8B8, POOL_MANAGED), false, 4);
	cbConfTech->SetTextColor(D3DXCOLOR(0,0,0,1), D3DXCOLOR(1,1,1,1));
	cbConfTech->SetFont(font);
	cbConfTech->SetClientBorder(5);
	cbConfTech->SetSelectedIndex((int)m_Method);
	cbConfTech->SetEventHandler(GE_VALUECHANGED, OnConfTechChanged);

	

	y += 30;

	Label *lbjitter = new Label(m_pApp->GetMenuManager(), 2);
	lbjitter->SetPosition(10, y);
	lbjitter->SetSize(100, 20);
	lbjitter->SetText("Jitter Type: ");
	lbjitter->SetFont(font);
	
	pnBack->AddChild(lbjitter);


	ComboBox* cbJitterType = new ComboBox(m_pApp->GetMenuManager(), 12344);
	cbJitterType->SetUserData(this);
	cbJitterType->SetPosition(100, y);
	cbJitterType->SetSize(130, 22);
	cbJitterType->SetDropDownHeight(104);
	cbJitterType->SetDropDownItemHeight(19);
	cbJitterType->AddItem("None");
	cbJitterType->AddItem("Random");
	cbJitterType->AddItem("Halton");
	cbJitterType->AddItem("Rotation");
	cbJitterType->AddItem("LispSM N");
	cbJitterType->SetTexture(m_pApp->GetDevice()->GetTextureManager()->CreateTexture("GUI\\input.png", FMT_A8R8G8B8, POOL_MANAGED), false, 3, 
					m_pApp->GetDevice()->GetTextureManager()->CreateTexture("GUI\\combo.png", FMT_A8R8G8B8, POOL_MANAGED), true,
					m_pApp->GetDevice()->GetTextureManager()->CreateTexture("GUI\\list.png", FMT_A8R8G8B8, POOL_MANAGED), 
					m_pApp->GetDevice()->GetTextureManager()->CreateTexture("GUI\\listsel.png", FMT_A8R8G8B8, POOL_MANAGED), false, 4);
	cbJitterType->SetTextColor(D3DXCOLOR(0,0,0,1), D3DXCOLOR(1,1,1,1));
	cbJitterType->SetFont(font);
	cbJitterType->SetClientBorder(5);
	cbJitterType->SetSelectedIndex((int)m_JitterType);
	cbJitterType->SetEventHandler(GE_VALUECHANGED, OnJitterTypeChanged);

	y += 30;

	CheckBox* ckPCFPreTest = new CheckBox(m_pApp->GetMenuManager(), 99871);
	ckPCFPreTest->SetUserData(this);
	ckPCFPreTest->SetPosition(10, y);
	ckPCFPreTest->SetSize(100, 20);
	ckPCFPreTest->SetChecked(m_bPCFPreTest);
	ckPCFPreTest->SetText("PCF Pre-Test [F9]");
	ckPCFPreTest->SetTexture(m_pApp->GetDevice()->GetTextureManager()->CreateTexture("GUI\\ck.png", FMT_A8R8G8B8, POOL_MANAGED), 
					m_pApp->GetDevice()->GetTextureManager()->CreateTexture("GUI\\ckc.png", FMT_A8R8G8B8, POOL_MANAGED));
	ckPCFPreTest->SetAlphaBlend(true);
	ckPCFPreTest->SetFont(font);
	ckPCFPreTest->SetEventHandler(GE_VALUECHANGED, OnPCFPreTestCheck);

	pnBack->AddChild(ckPCFPreTest);

	y += 30;

	Label* lbConf = new Label(m_pApp->GetMenuManager(), 0);
	lbConf->SetSize(110, 20);
	lbConf->SetPosition(10, y);
	lbConf->SetFont(font);
	lbConf->SetText("Conf:");

	pnBack->AddChild(lbConf);

	Label* lbConfValue = new Label(m_pApp->GetMenuManager(), 0);
	lbConfValue->SetUserData(this);
	lbConfValue->SetSize(40, 20);
	lbConfValue->SetPosition(60, y);
	lbConfValue->SetFont(font);
	lbConfValue->SetText("x.xx");
	lbConfValue->SetTextAlign(AL_RIGHTBOTTOM);

	pnBack->AddChild(lbConfValue);

	Slider* slConf = new Slider(m_pApp->GetMenuManager(), 345);
	slConf->SetUserData(lbConfValue);
	slConf->SetPosition(100, y+2);
	slConf->SetSize(130, 20);
	slConf->SetRange(0, 100);
	slConf->SetSliderSize(10, 20, 20, 10);
	slConf->SetTexture(m_pApp->GetDevice()->GetTextureManager()->CreateTexture("GUI\\slider.png", FMT_A8R8G8B8, POOL_MANAGED), 
					m_pApp->GetDevice()->GetTextureManager()->CreateTexture("GUI\\nob.png", FMT_A8R8G8B8, POOL_MANAGED));
	slConf->SetAlphaBlend(true);

	pnBack->AddChild(slConf);
	slConf->SetEventHandler(GE_VALUECHANGED, OnConfTChanged);
	slConf->SetValue((int)(m_ConfT[m_Method] * 100));

	y += 30;

	Label* lbMaxPasses = new Label(m_pApp->GetMenuManager(), 0);
	lbMaxPasses->SetSize(110, 20);
	lbMaxPasses->SetPosition(10, y);
	lbMaxPasses->SetFont(font);
	lbMaxPasses->SetText("MaxPass:");

	pnBack->AddChild(lbMaxPasses);

	Label* lbMaxPassesValue = new Label(m_pApp->GetMenuManager(), 0);
	lbMaxPassesValue->SetUserData(this);
	lbMaxPassesValue->SetSize(40, 20);
	lbMaxPassesValue->SetPosition(60, y);
	lbMaxPassesValue->SetFont(font);
	lbMaxPassesValue->SetText("xxx");
	lbMaxPassesValue->SetTextAlign(AL_RIGHTBOTTOM);

	pnBack->AddChild(lbMaxPassesValue);

	Slider* slMaxPasses = new Slider(m_pApp->GetMenuManager(), 987);
	slMaxPasses->SetUserData(lbMaxPassesValue);
	slMaxPasses->SetPosition(100, y+2);
	slMaxPasses->SetSize(130, 20);
	slMaxPasses->SetRange(1, 300);
	slMaxPasses->SetSliderSize(10, 20, 20, 10);
	slMaxPasses->SetTexture(m_pApp->GetDevice()->GetTextureManager()->CreateTexture("GUI\\slider.png", FMT_A8R8G8B8, POOL_MANAGED), 
					m_pApp->GetDevice()->GetTextureManager()->CreateTexture("GUI\\nob.png", FMT_A8R8G8B8, POOL_MANAGED));
	slMaxPasses->SetAlphaBlend(true);

	pnBack->AddChild(slMaxPasses);
	slMaxPasses->SetEventHandler(GE_VALUECHANGED, OnMaxPassesChanged);
	slMaxPasses->SetValue(m_MaxJitter);

	y += 30;

	Label* lbAdaptedThreshold = new Label(m_pApp->GetMenuManager(), 0);
	lbAdaptedThreshold->SetSize(110, 20);
	lbAdaptedThreshold->SetPosition(10, y);
	lbAdaptedThreshold->SetFont(font);
	lbAdaptedThreshold->SetText("Stop t:");

	pnBack->AddChild(lbAdaptedThreshold);

	Label* lbAdaptedThresholdValue = new Label(m_pApp->GetMenuManager(), 0);
	lbAdaptedThresholdValue->SetUserData(this);
	lbAdaptedThresholdValue->SetSize(40, 20);
	lbAdaptedThresholdValue->SetPosition(60, y);
	lbAdaptedThresholdValue->SetFont(font);
	lbAdaptedThresholdValue->SetText("xxx");
	lbAdaptedThresholdValue->SetTextAlign(AL_RIGHTBOTTOM);

	pnBack->AddChild(lbAdaptedThresholdValue);

	Slider* slAdaptedThreshold = new Slider(m_pApp->GetMenuManager(), 987);
	slAdaptedThreshold->SetUserData(lbAdaptedThresholdValue);
	slAdaptedThreshold->SetPosition(100, y+2);
	slAdaptedThreshold->SetSize(130, 20);
	slAdaptedThreshold->SetRange(1, 3000);
	slAdaptedThreshold->SetSliderSize(10, 20, 20, 10);
	slAdaptedThreshold->SetTexture(m_pApp->GetDevice()->GetTextureManager()->CreateTexture("GUI\\slider.png", FMT_A8R8G8B8, POOL_MANAGED), 
					m_pApp->GetDevice()->GetTextureManager()->CreateTexture("GUI\\nob.png", FMT_A8R8G8B8, POOL_MANAGED));
	slAdaptedThreshold->SetAlphaBlend(true);

	pnBack->AddChild(slAdaptedThreshold);
	slAdaptedThreshold->SetEventHandler(GE_VALUECHANGED, OnAdaptedThresholdChanged);
	slAdaptedThreshold->SetValue(m_Threshold);


	y += 30;

	Label* lbAdaptedNumBelow = new Label(m_pApp->GetMenuManager(), 0);
	lbAdaptedNumBelow->SetSize(110, 20);
	lbAdaptedNumBelow->SetPosition(10, y);
	lbAdaptedNumBelow->SetFont(font);
	lbAdaptedNumBelow->SetText("Stop n:");

	pnBack->AddChild(lbAdaptedNumBelow);

	Label* lbAdaptedNumBelowValue = new Label(m_pApp->GetMenuManager(), 0);
	lbAdaptedNumBelowValue->SetUserData(this);
	lbAdaptedNumBelowValue->SetSize(40, 20);
	lbAdaptedNumBelowValue->SetPosition(60, y);
	lbAdaptedNumBelowValue->SetFont(font);
	lbAdaptedNumBelowValue->SetText("xxx");
	lbAdaptedNumBelowValue->SetTextAlign(AL_RIGHTBOTTOM);

	pnBack->AddChild(lbAdaptedNumBelowValue);

	Slider* slAdaptedNumBelow = new Slider(m_pApp->GetMenuManager(), 987);
	slAdaptedNumBelow->SetUserData(lbAdaptedNumBelowValue);
	slAdaptedNumBelow->SetPosition(100, y+2);
	slAdaptedNumBelow->SetSize(130, 20);
	slAdaptedNumBelow->SetRange(1, 10);
	slAdaptedNumBelow->SetSliderSize(10, 20, 20, 10);
	slAdaptedNumBelow->SetTexture(m_pApp->GetDevice()->GetTextureManager()->CreateTexture("GUI\\slider.png", FMT_A8R8G8B8, POOL_MANAGED), 
					m_pApp->GetDevice()->GetTextureManager()->CreateTexture("GUI\\nob.png", FMT_A8R8G8B8, POOL_MANAGED));
	slAdaptedNumBelow->SetAlphaBlend(true);

	pnBack->AddChild(slAdaptedNumBelow);
	slAdaptedNumBelow->SetEventHandler(GE_VALUECHANGED, OnAdaptedNumBelowChanged);
	slAdaptedNumBelow->SetValue(m_FramesBelow);

	pnBack->AddChild(cbJitterType);
	pnBack->AddChild(cbConfTech);

}

void DeferredShadowConfidence::OnConfTechChanged(GUIElement* const sender, const GUIEVENT evnt, void* pData)
{
	ComboBox* cb = dynamic_cast<ComboBox*>(sender);
	DeferredShadowConfidence* me = (DeferredShadowConfidence*)cb->GetUserData();

	if (me && cb && cb->GetSelectedIndex() >= 0)
	{
		me->SetMethod((CONFMETHOD)cb->GetSelectedIndex());
	}
}

void DeferredShadowConfidence::OnJitterTypeChanged(GUIElement* const sender, const GUIEVENT evnt, void* pData)
{
	ComboBox* cb = dynamic_cast<ComboBox*>(sender);
	DeferredShadowConfidence* me = (DeferredShadowConfidence*)cb->GetUserData();

	if (me && cb && cb->GetSelectedIndex() >= 0)
	{
		me->m_JitterType = ((SMJITTERTYPE)cb->GetSelectedIndex());
	}
}

void DeferredShadowConfidence::OnPCFPreTestCheck(GUIElement* const sender, const GUIEVENT evnt, void* pData)
{
	CheckBox* ck = dynamic_cast<CheckBox*>(sender);
	DeferredShadowConfidence* me = (DeferredShadowConfidence*)ck->GetUserData();

	if (me && ck)
	{
		me->m_bPCFPreTest = ck->IsChecked();
	}
}

void DeferredShadowConfidence::OnConfTChanged(GUIElement* const sender, const GUIEVENT evnt, void* pData)
{
	Slider* sl = dynamic_cast<Slider*>(sender);
	Label* lb = (Label*)sl->GetUserData();
	DeferredShadowConfidence* me = (DeferredShadowConfidence*)lb->GetUserData();

	if (me && sl && lb)
	{
		float conf = sl->GetValue() / 100.0f;
		lb->SetText(XString(conf));
		me->m_ConfT[(int)(me->m_Method)] = conf;
	}
}

void DeferredShadowConfidence::OnMaxPassesChanged(GUIElement* const sender, const GUIEVENT evnt, void* pData)
{
	Slider* sl = dynamic_cast<Slider*>(sender);
	Label* lb = (Label*)sl->GetUserData();
	DeferredShadowConfidence* me = (DeferredShadowConfidence*)lb->GetUserData();

	if (me && sl && lb)
	{
		lb->SetText(XString(sl->GetValue()));
		me->m_MaxJitter = sl->GetValue();
	}
}

void DeferredShadowConfidence::OnAdaptedThresholdChanged(GUIElement* const sender, const GUIEVENT evnt, void* pData)
{
	Slider* sl = dynamic_cast<Slider*>(sender);
	Label* lb = (Label*)sl->GetUserData();
	DeferredShadowConfidence* me = (DeferredShadowConfidence*)lb->GetUserData();

	if (me && sl && lb)
	{
		lb->SetText(XString(sl->GetValue()));
		me->m_Threshold = sl->GetValue();
	}
}

void DeferredShadowConfidence::OnAdaptedNumBelowChanged(GUIElement* const sender, const GUIEVENT evnt, void* pData)
{
	Slider* sl = dynamic_cast<Slider*>(sender);
	Label* lb = (Label*)sl->GetUserData();
	DeferredShadowConfidence* me = (DeferredShadowConfidence*)lb->GetUserData();

	if (me && sl && lb)
	{
		lb->SetText(XString(sl->GetValue()));
		me->m_FramesBelow = sl->GetValue();
	}
}