#include "ShadowApp.h"
#include "..\DXFunctions\fontmanager.h"

#include "DeferredShadowConfidence.h"
#include "DeferredShadowZTiled.h"
#include "DeferredShadowSSTiled.h"
#include "DeferredShadowSMTiled.h"

#include "TerrainScene.h"
#include "PowerPlantScene.h"

#include "MainMenu.h"

#include <direct.h>

#include <time.h>

#include "DirectionalLight.h"

//int foo = _CrtSetBreakAlloc(7024);

extern long FAR PASCAL MainWndproc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam );

ShadowApp::ShadowApp(void) : m_DI(this)
{
//	m_NumAntiLightPlanes = 0;
//	m_VisibleMesh = NULL;

//	m_LightAngX = 0.5f;
//	m_LightAngZ = 0;

	m_SM = NULL;

	m_hWndMain = NULL;
	m_hInst = NULL;
	m_Font = NULL;
	m_bShowMenu = true;

	m_CaputreNextFrame = false;

//	m_Terrain = NULL;

	/*m_Arrow = NULL;
	m_Car = NULL;
	m_Tiger = NULL;
	m_Eifel = NULL;
	m_Oster = NULL;*/

	m_FXDS = NULL;

	m_DSWorld = NULL;

	m_DSDepth = NULL;
	m_DSNormal = NULL;
	m_DSDiffuse = NULL;
	m_DSShadow[0] = NULL;
	m_DSShadow[1] = NULL;
	m_DSSampleVis = NULL;
	m_OptConf = NULL;
	m_DSShadowRefDiff = NULL;	
	m_DSShadowRef = NULL;
//	m_DSDepthStencil = NULL;

	m_VDeclFSQuad = NULL;
	m_VBFSQuad = NULL;

	m_SelectBench = false;
	m_BenchType = BT_NONE;
	m_BenchStartFrames = 0;
	m_BenchStart = 0;

	m_pMenuManager = NULL;

	m_iScene = 0;

	m_UpdateTime = 0;
	m_RenderTime = 0;

	m_ShowSM = false;
	
	m_UseDebugCam = false;

	m_Config.Method = SM_COMMON;

	m_Config.UseIDBuffer = false;

	m_Config.DrawObjects = true;
	m_Config.UpdateDynamicObjects = true;

//	m_Config.ErodeOneLess = false;
//	m_Config.CloseSize = 0;
	
	m_Config.PCFPreTest = false;

//	m_Config.ConfT = 1;
	m_Config.MaxJitter = 20;

	m_Config.LambertScale = 0.75f;
	
//	m_Config.DrawT = 250;
//	m_Config.DrawTPasses = 3;

	m_Config.ShadowMapSize = 2048;
	m_Config.ConstBias = 1.5f;
	m_Config.SlopeBias = 3;

	m_Config.UseLispSM = false;

	m_Config.WorldPosType = WPT_LINEARDEPTH;

	m_Config.UseSSAO = false;

	m_Config.SMFiltering = false;

//	m_Config.JitterType = SMJT_HALTON;

	m_VisType = VIS_NONE;

	m_bDrawWireframe = false;

	m_PassesDone = 0;
	
	ZeroMemory(m_PixelSet, sizeof(unsigned) * (JITTERLIMIT + 1));
	
	ZeroMemory(m_Techniques, sizeof(DeferredShadowTechnique*) * SM_COUNT);

	/*DynamicStack<int> stk(100);
	wlog("InitArray:");
	for(int i=0;i<20;i++)
	{
		int v = rand();
		for(int j=rand()%5;j;j--)
			stk.Push(v);
	}

	stk.Sort();

	wlog("AfterSort:");
	for(int i=0;i<stk.GetElementCount();i++)
		wlog("%d", stk[i]);*/
}

ShadowApp::~ShadowApp(void)
{
	Invalidate();

	delete m_pScene[0];
	delete m_pScene[1];

	for (int i = 0; i < SM_COUNT; i++)
	{
		if (m_Techniques[i])
			delete m_Techniques[i];
	}

	delete m_pMenuManager;

	delete m_VDeclFSQuad;

	SAFERELEASE(m_FXDS);

	SAFERELEASE(m_VBFSQuad);

	SAFERELEASE(m_DynVB);

	delete m_SM;
}

HRESULT ShadowApp::Init(HINSTANCE hInstance)
{ 
	//jump from /debug or release to root directory
	_chdir("..");

	STSelMode mode;
	mode.SetDefault();
	//if(!mode.Open("Default.dpm"))
	//{
	//	if(!SelectDeviceSettings(0, true, &mode))
	//		return E_FAIL;
	//}
	mode.Width = 1280;
	mode.Height = 1024;
	mode.Windowed = true;
	mode.VSync = false;

	m_hInst = hInstance;

	if(FAILED(CoInitialize(NULL)))
	{
		CoUninitialize();
		return E_FAIL;
	}

	WNDCLASS		wc;

//	srand((unsigned)time( NULL ) );

	//lpGuid = (LPGUID) &GAME_GUID;

	wc.style = 0;
    wc.lpfnWndProc = MainWndproc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = hInstance;
    wc.hIcon = NULL;//LoadIcon(hInstance,MAKEINTRESOURCE(IDI_ICON1));
	wc.hCursor = NULL;//LoadCursor(NULL, IDC_ARROW);
	wc.hbrBackground = (HBRUSH)GetStockObject( BLACK_BRUSH );
    wc.lpszMenuName =  NULL;
    wc.lpszClassName = "ShadowClass";
    
	SetCursor(wc.hCursor);

    if(!RegisterClass( &wc ))
        return E_FAIL;
	
    m_hWndMain = CreateWindowEx(0,
        "ShadowClass",
        "Shadow",
        WS_VISIBLE|WS_EX_TOPMOST|WS_SYSMENU|WS_SIZEBOX,
		0,
        0,
        mode.Width,
        mode.Height,
        NULL,
        NULL,
        hInstance,
        NULL);
  
	UpdateWindow( m_hWndMain );

	Init3D((int)m_hWndMain,mode,false);

	m_DI.InitMouse((int)m_hWndMain,(int)hInstance);
	m_DI.SetCursor(wc.hCursor);
	m_DI.SetMouseVisible(true);
	m_DI.SetMouseSpeed(1);
	m_DI.InitKeyboard((int)m_hWndMain,(int)hInstance);
	m_DI.SetAcquire(true);
	m_DI.SetDeviceCursor(m_Device->GetTextureManager()->CreateTexture("GUI\\aero_arrow.png", FMT_A8R8G8B8, POOL_MANAGED), 0, 0);
	POINT pnt;
	GetCursorPos(&pnt);

	m_Run = true;
	
	m_Active = true;

	Restore();

	return S_OK;
}

const Camera& ShadowApp::GetActiveCam(void) const
{
	return m_UseDebugCam ? GetActiveScene()->GetDebugCamera() : GetActiveScene()->GetCamera();
}

void ShadowApp::RenderScene(void)
{
	m_PassesDone = 0;
	m_LastPixelDrawed = 0;
	ZeroMemory(m_PixelSet, sizeof(unsigned) * (JITTERLIMIT + 1));

	m_Clock.StartCapture(12415);

	if (GetActiveScene())
		GetActiveScene()->Render();

	m_Clock.EndCapture(12415);
	m_RenderTime = (double)m_Clock.GetCaptureTime(12415) * 1000 / (double)m_Clock.GetTicksPerSec();

	if (m_CaputreNextFrame) //save screenshot
	{
		char fn[50];
		time_t t;

		time(&t);
		strftime(fn, 50, "Screenshot_%d%m%Y_%H%M%S.png", localtime(&t)); // will be hh:mm:ss
			
		LPDIRECT3DSURFACE9 surf;
		m_Device->GetDevice()->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &surf);

		//LPDIRECT3DSURFACE9 syssurf;
		//m_Device->GetDevice()->CreateOffscreenPlainSurface(m_Device->GetViewPort()->GetWidth(), m_Device->GetViewPort()->GetHeight(), D3DFMT_A8R8G8B8, D3DPOOL_SCRATCH, &syssurf, NULL);
		//m_Device->GetDevice()->StretchRect(surf, NULL, syssurf, NULL, D3DTEXF_NONE);

		HRESULT hr = D3DXSaveSurfaceToFile(fn, D3DXIFF_PNG, surf, NULL, NULL);

		surf->Release();
		//syssurf->Release();

		m_CaputreNextFrame = false;
	}

	if(m_BenchType == BT_NONE && !m_SelectBench && GetActiveScene())
	{
		XString txt = "FPS: ";
		txt.appand(m_Clock.AvgFPS());
		txt.appand("   PrimitiveCount: ");
		txt.appand((int)m_Device->GetPrimitiveCount());
		m_Device->ResetPrimitiveCount();
		txt.appand("\nLightAngX/Z: ");
		txt.appand(GetActiveScene()->GetLightAngX());
		txt.appand(" / ");
		txt.appand(GetActiveScene()->GetLightAngZ());

		txt.appand("\nUpdateTime: ");
		txt.appand((int)m_UpdateTime);
		txt.appand("ms RenderTime: ");
		txt.appand((int)m_RenderTime);
		txt.appand("ms");
		txt.appand("\nPasses Done: ");
		txt.appand(GetActiveScene()->GetLight()->GetPassesDone());

		if(1)
		{			
			m_Font->Draw("PixelDrawed in last 30 passes:", 461, 31, 0xff000000);
			m_Font->Draw("PixelDrawed in last 30 passes:", 460, 30, 0xffffffff);

			XString pix;
			for(int k = GetActiveScene()->GetLight()->GetPassesDone()-_min(JITTERLIMIT,30); k < GetActiveScene()->GetLight()->GetPassesDone(); k++)
			{
				if(k >= 0)
				{
					pix.appand((int)m_PixelSet[k]);
					pix.appand("\n");
				}
			}
			m_Font->Draw(pix, 646, 31, 0xff000000);
			m_Font->Draw(pix, 645, 30, 0xffffffff);
			
		}
		m_Font->Draw(txt, 11, 11, 0xff000000);
		m_Font->Draw(txt, 10, 10, 0xffffffff);

	}
	else if(m_SelectBench)
	{
		XString txt;
		txt.appand("F1 ... Abort\n");
		txt.appand("F2 ... Performance\n");
		txt.appand("F3 ... Convergence");

		m_Font->Draw(txt, 11, 21, 0xff000000);
		m_Font->Draw(txt, 10, 20, 0xffffffff);
	}

	if (m_BenchType == BT_NONE && !m_SelectBench && GetActiveScene() && m_bShowMenu && m_pMenuManager)
		m_pMenuManager->Draw();
}

void ShadowApp::UpdateScene(void)
{
	m_DI.Update();

	if (m_bShowMenu && m_pMenuManager)
		m_pMenuManager->Update();

	if(m_BenchType == BT_NONE && !m_SelectBench)
	{
		if (m_Techniques[(int)m_Config.Method])
		{
			m_Techniques[(int)m_Config.Method]->UpdateInput();
		}

		if (m_bDrawWireframe)
			m_Device->SetFillmode(FILL_WIREFRAME);
		else
			m_Device->SetFillmode(FILL_SOLID);

		if(m_DI.GetKey(DIK_NUMPADMINUS) & KEY_DOWN || m_DI.GetKey(DIK_MINUS) & KEY_DOWN)
		{
			if(m_Config.MaxJitter > 200)
				m_Config.MaxJitter -= 50;
			else if(m_Config.MaxJitter > 100)
				m_Config.MaxJitter -= 20;
			else if(m_Config.MaxJitter > 50)
				m_Config.MaxJitter -= 10;
			else if(m_Config.MaxJitter > 5)
				m_Config.MaxJitter -= 5;
			else if(m_Config.MaxJitter > 0)
				m_Config.MaxJitter--;
		}
		else if(m_DI.GetKey(DIK_NUMPADPLUS) & KEY_DOWN || m_DI.GetKey(DIK_RBRACKET) & KEY_DOWN)
		{
			if(m_Config.MaxJitter < 5)
				m_Config.MaxJitter++;
			else if(m_Config.MaxJitter < 50)
				m_Config.MaxJitter += 5;
			else if(m_Config.MaxJitter < 100)
				m_Config.MaxJitter += 10;
			else if(m_Config.MaxJitter < 200)
				m_Config.MaxJitter += 20;
			else if(m_Config.MaxJitter < JITTERLIMIT)
				m_Config.MaxJitter += 50;

			if(m_Config.MaxJitter > JITTERLIMIT)
				m_Config.MaxJitter = JITTERLIMIT;
		}

		if (m_DI.GetKey(DIK_TAB) & KEY_UP)
		{
			m_bShowMenu = !m_bShowMenu;
		}

		/*if(m_DI.GetKey(DIK_Y) & KEY_UP)
		{
			if(m_Config.ConfT < 1)
				m_Config.ConfT += 0.05f;
		}
		else if(m_DI.GetKey(DIK_H) & KEY_UP)
		{
			if(m_Config.ConfT > 0)
				m_Config.ConfT -= 0.05f;
		}*/

		/*if(m_DI.GetKey(DIK_COMMA) & KEY_UP)
		{
			m_SM->SetShadowMapSize(((int)m_SM->GetShadowMapSize()) >> 1);
			m_Config.ShadowMapSize = m_SM->GetShadowMapSize();
		}
		else if(m_DI.GetKey(DIK_PERIOD) & KEY_DOWN)
		{
			m_SM->SetShadowMapSize(((int)m_SM->GetShadowMapSize()) << 1);
			m_Config.ShadowMapSize = m_SM->GetShadowMapSize();
		}*/

		if(m_DI.GetKey(DIK_U) & KEY_UP)
		{
			m_Config.CloseSize++;
		}
		else if(m_DI.GetKey(DIK_J) & KEY_UP)
		{
			if(m_Config.CloseSize > 0)
				m_Config.CloseSize--;
		}

		if (m_DI.GetKey(183) & KEY_UP) //druck -> take screenshot
		{
			m_CaputreNextFrame = true;
		}

		/*if(m_DI.GetKey(DIK_M) & KEY_UP)
		{
			m_Config.DrawTPasses++;
		}
		else if(m_DI.GetKey(DIK_N) & KEY_UP)
		{
			if(m_Config.DrawTPasses > 1)
				m_Config.DrawTPasses--;
		}*/

/*		if(m_DI.GetKey(DIK_I) & KEY_UP)
		{
			m_Config.DrawT += 5;
		}
		else if(m_DI.GetKey(DIK_K) & KEY_UP)
		{
			if(m_Config.DrawT > 0)
				m_Config.DrawT -= 5;
		}*/

		if (m_DI.GetKey(DIK_F10))
		{
			STSelMode mode = GetCurrentMode();
			if(SelectDeviceSettings(0, true, &mode))
			{
				Reset3D(mode);
			}
		}

		/*if(m_DI.GetKey(DIK_O) & KEY_UP)
		{
			int jt = m_SM->GetJitterType() + 1;
			if(jt >= SMJT_COUNT)
				jt = 0;
			m_SM->SetJitterType((SMJITTERTYPE)jt);
			m_Config.JitterType = m_SM->GetJitterType();
		}
		else if(m_DI.GetKey(DIK_L) & KEY_UP)
		{
			int jt = m_SM->GetJitterType() - 1;
			if(jt < 0)
				jt = SMJT_COUNT-1;
			m_SM->SetJitterType((SMJITTERTYPE)jt);
			m_Config.JitterType = m_SM->GetJitterType();
		}*/

		

		if(m_DI.GetKey(DIK_F3) & KEY_UP)
			m_Config.ErodeOneLess = !m_Config.ErodeOneLess;

		/*if (m_DI.GetKey(DIK_F5) & KEY_UP)
		{
			int vt = m_VisType - 1;
			if(vt < 0)
				vt = VIS_COUNT - 1;
			m_VisType = (VISTYPE)vt;
		}
		else if(m_DI.GetKey(DIK_F6) & KEY_UP)
		{
			int vt = m_VisType + 1;
			if(vt >= VIS_COUNT)
				vt = 0;
			m_VisType = (VISTYPE)vt;
		}*/

		if(m_DI.GetKey(DIK_F12) & KEY_UP)
			WlogCamPos();

		if(m_DI.GetKey(DIK_RETURN) & KEY_UP)
		{
			if(m_DI.GetKey(DIK_LMENU) & KEY_PRESS)
			{
				STSelMode mode;
				mode.SetDefault();

				mode.Width = 1024;
				mode.Height = 768;
				mode.Windowed = !GetCurrentMode().Windowed;
				mode.VSync = false;
				
				Reset3D(mode);

				//SetWindowState(m_hWnd, 0);
			}
			else
			{
				m_SelectBench = true;
			}
		}
		
		for(int i=0; i < CAMPOSITIONS; i++)
		{
			if(m_DI.GetKey(DIK_1 + i) & KEY_UP)
			{
				GetActiveScene()->SetCamPos(i);
				break;
			}
		}

		if (m_DI.GetMouseButton(MBTN_LEFT) & BUTTONDOWN || m_DI.GetMouseButton(MBTN_MID) & BUTTONDOWN || m_DI.GetMouseButton(MBTN_RIGHT) & BUTTONDOWN)
		{
			m_MouseDownPos = DXVector2(m_DI.GetScreenCursorX(), m_DI.GetScreenCursorY());
		}

		if (GetActiveScene() && (!m_bShowMenu || !m_pMenuManager->GetMouseOverElement() && !m_pMenuManager->GetDragStartElement()))
		{
			if(m_DI.GetMouseButton(MBTN_LEFT) & BUTTONPRESSED) //rotate light
			{
				GetActiveScene()->SetLightAngZ(GetActiveScene()->GetLightAngZ() + m_DI.GetMouseDX() * 0.002f);
				GetActiveScene()->SetLightAngX(_max(0, _min(GetActiveScene()->GetLightAngX() + m_DI.GetMouseDY() * 0.002f, 1)));

				m_DI.SetMousePos(m_MouseDownPos.x, m_MouseDownPos.y);
			}

			GetActiveScene()->MoveCam();
		}
	}
	else if(m_BenchType == BT_PERFORMANCE)// m_Benching == true
	{
		//LONGLONG TotalBenchTime = m_Clock.GetTicksPerSec() * CAMPOSITIONS * BENCHCAMPOSSTAY;
		LONGLONG BenchTime = m_Clock.RunTime() - m_BenchStart;
		int iCamPos = (int)(BenchTime / BENCHCAMPOSSTAY / 1000);
		m_BenchCamPos = iCamPos;
		if (m_BenchCamPos > m_LastCamPos)
		{
			m_CamFrames[m_LastCamPos] = m_Clock.FrameCounter() - m_BenchStartFrames - m_SumFrames;
			m_SumFrames += m_CamFrames[m_LastCamPos];

			m_LastCamPos++; 
		}
		if(iCamPos >= CAMPOSITIONS)
		{
			m_BenchType = BT_NONE;
			DWORD Frames = m_Clock.FrameCounter() - m_BenchStartFrames;
			//wirte benchresult
			wlog("Benchresult: %d Frames rendered; AvgFPS: %f", Frames, Frames / (float)BENCHCAMPOSSTAY / (float)CAMPOSITIONS);
			wlog("FrameProfile: %d %d %d %d %d %d %d %d %d %d", m_CamFrames[0], m_CamFrames[1], m_CamFrames[2], m_CamFrames[3], m_CamFrames[4], m_CamFrames[5], m_CamFrames[6], m_CamFrames[7], m_CamFrames[8], m_CamFrames[9]);
		}
		else
		{
			GetActiveScene()->SetCamPos(iCamPos);
		}
	}
	else if(m_BenchType == BT_CONVERGENCE)
	{
		if(m_RenderRef) //this is done first, now start increasing number of passes
		{
			m_RenderRef = false;
			m_Config.MaxJitter = 5;
		}
		else
		{
			if(m_iPixelDiff > 0)
				m_FPS[m_iPixelDiff-1] = m_Clock.GetTicksPerSec() / m_Clock.FrameTime();

			if(m_Config.MaxJitter < 5)
				m_Config.MaxJitter++;
			else if(m_Config.MaxJitter < 50)
				m_Config.MaxJitter += 5;
			else if(m_Config.MaxJitter < 100)
				m_Config.MaxJitter += 10;
			else if(m_Config.MaxJitter < 200)
				m_Config.MaxJitter += 20;
			else if(m_Config.MaxJitter < JITTERLIMIT)
				m_Config.MaxJitter += 50;

			if(m_Config.MaxJitter >= JITTERLIMIT)
			{
				XString Passes = "PassesDone = [";
				XString Diff = "PixelDiff = [";
				XString FPS = "FPS = [";
				for(unsigned i=0;i<m_iPixelDiff;i++)
				{				
					Passes.appand((int)m_Passes[i]);
					if(i < m_iPixelDiff-1)
						Passes.appand(",");
					Diff.appand((int)m_PixelDiff[i]);
					if(i < m_iPixelDiff-1)
						Diff.appand(",");
					FPS.appand((int)m_FPS[i]);
					if(i < m_iPixelDiff-1)
						FPS.appand(",");
				}
				Passes.appand("]");
				Diff.appand("]");
				FPS.appand("]");
				wlog("Diff/Passes at Cam %d: \n%s\n%s\n%s", m_BenchCamPos, Passes.getbuffer(), Diff.getbuffer(), FPS.getbuffer());
				m_iPixelDiff = 0;

				if(++m_BenchCamPos >= 1) //only use cam 0 so far
				{
					m_BenchType = BT_NONE;
					m_Config.MaxJitter = m_MaxJitterRestore;
					//write benchresult
				}
				else
				{
					GetActiveScene()->SetCamPos(m_BenchCamPos);
					m_Config.MaxJitter = JITTERLIMIT;
					m_RenderRef = true;
				}
			}
		}
	}
	else if(m_SelectBench)
	{
		if(m_DI.GetKey(DIK_F1) & KEY_UP)
		{
			m_SelectBench = false;
		}
		else if(m_DI.GetKey(DIK_F2) & KEY_UP)
		{
			m_SelectBench = false;
			m_BenchType = BT_PERFORMANCE;

			m_BenchStart = m_Clock.RunTime();
			m_BenchStartFrames = m_Clock.FrameCounter();
			m_CamStartFrames = m_Clock.FrameCounter();

			m_BenchCamPos = 0;
			m_LastCamPos = 0;
			m_SumFrames = 0;
			GetActiveScene()->SetCamPos(m_BenchCamPos);
		}
		else if(m_DI.GetKey(DIK_F3) & KEY_UP)
		{
			m_SelectBench = false;
			m_BenchType = BT_CONVERGENCE;
			m_RenderRef = true;
			m_iPixelDiff = 0;
			m_MaxJitterRestore = m_Config.MaxJitter;
			m_Config.MaxJitter = JITTERLIMIT;

			m_BenchCamPos = 0;
			m_LastCamPos = 0;
			m_SumFrames = 0;
			GetActiveScene()->SetCamPos(m_BenchCamPos);

//			wlog("Convergence BenchStart with:\nConfT = %f\nShadowMapSize = %d", m_Config.ConfT, m_Config.ShadowMapSize);
		}
	}

	m_Clock.StartCapture(12414);

	if (GetActiveScene())
		GetActiveScene()->Update();

	m_Clock.EndCapture(12414);
	m_UpdateTime = (double)m_Clock.GetCaptureTime(12414) * 1000 / (double)m_Clock.GetTicksPerSec();

	/*//float a = m_Daytime * D3DX_PI * 2;
	float a = m_LightAngX * D3DX_PI * 2;
	float b = m_LightAngZ * D3DX_PI * 2;
	m_SunDir = DXVector3(sin(a) * cos(b), sin(b) * sin(a), cos(a));
	m_AmbientColor = DXColor(0.2f, 0.2f, 0.2f, 1);
	m_SunColor = DXColor(0.8f, 0.8f, 0.8f, 1);
	if(m_SunDir.z > 0)
	{
		if(m_SunDir.z > 0.2)
			m_SunColor *= 0;
		else
			m_SunColor *= 1 - m_SunDir.z / 0.2f;
	}

	m_Cam.SetPerspectiveProj(GetCurrentMode().Width, GetCurrentMode().Height, 1, 2000);

	m_VisibleBound.SetVolume(DXVector3(FLT_MAX, FLT_MAX, FLT_MAX), -DXVector3(FLT_MAX, FLT_MAX, FLT_MAX));
	m_SceneBound.SetVolume(DXVector3(FLT_MAX, FLT_MAX, FLT_MAX), -DXVector3(FLT_MAX, FLT_MAX, FLT_MAX));

	if(m_Terrain)
	{
		m_Terrain->Update();
	}

	if(m_Config.DrawObjects)
	{
		FOREACH(obj, m_Objects, Object)
		{
			obj->GetInfo()->Update(m_Clock.AnimMultiplier());
		}

		if(!m_Config.DynamicObjects)
		{
			FOREACH(obj, m_AirPlanes, AirPlane)
			{
				obj->GetInfo()->Update(m_Clock.AnimMultiplier());
			}
		}
	}

	UpdateShadowBound();

	m_SM->Update(m_VisibleBound, m_Cam, m_SunDir);	

	UpdateShadowFarPlane(m_VisibleMesh);

	//if(!m_Config.UseDeferred && m_UseDebugCam)
	//{
	//	float currfar = m_ShadowFar;
	//	for(int i = 0; i < m_Config.MaxJitter; i++)
	//	{
	//		currfar = 67; 
	//		m_Cam.SetPerspectiveProj(GetCurrentMode().Width, GetCurrentMode().Height, 1, currfar);
 //
	//		Frustum f(m_Cam);
	//		BoundingMesh b(f);
	//		b.ClipByAABB(m_VisibleBound);
	//		m_SM->Update(b.BuildAABB(), m_Cam, m_SunDir);
	//		UpdateShadowFarPlane(&b);

	//		//m_Cam.SetPerspectiveProj(GetCurrentMode().Width, GetCurrentMode().Height, 1, currfar);
	//	}
	//}

	if(m_Terrain)
	{
		m_Terrain->UpdateShadow();
	}

	if(m_Config.DrawObjects)
	{
		FOREACH(obj, m_Objects, Object)
		{
			obj->GetInfo()->UpdateShadow();
		}

		//if(!m_Config.NoDynamicObjects)
		//{
		//	FOREACH(obj, m_AirPlanes, AirPlane)
		//	{
		//		obj->GetInfo()->Update(m_Clock.AnimMultiplier());
		//	}
		//}
	}
*/
	
}


void ShadowApp::Restore(void)
{
	if (m_pScene[0])
		m_pScene[0]->Restore();

	if (m_pScene[1])
		m_pScene[1]->Restore();

	float* buffer;
	m_VBFSQuad->GetBuffer()->Lock(0,0,(void**)&buffer, 0);

	int xl = m_Device->GetViewPort()->GetWidth();
	int yl = m_Device->GetViewPort()->GetHeight();

	//x,y,z,w,tu,tv
	*buffer++ = 0-0.5f; *buffer++ = 0-0.5f; *buffer++ = 0; *buffer++ = 1; *buffer++ = 0; *buffer++ = 0; 
	*buffer++ = xl-0.5f; *buffer++ = 0-0.5f; *buffer++ = 0; *buffer++ = 1; *buffer++ = 1; *buffer++ = 0;
	*buffer++ = 0-0.5f; *buffer++ = yl-0.5f; *buffer++ = 0; *buffer++ = 1; *buffer++ = 0; *buffer++ = 1;
	*buffer++ = xl-0.5f; *buffer++ = yl-0.5f; *buffer++ = 0; *buffer++ = 1; *buffer++ = 1; *buffer++ = 1;

	m_VBFSQuad->GetBuffer()->Unlock();

	//create vertexbuffer for pointslist of all screenspace fragments
	float screenxl = m_Device->GetViewPort()->GetWidth();
	float screenyl = m_Device->GetViewPort()->GetHeight();

	m_VBSSFrag = m_Device->GetBufferManager()->CreateVB(screenxl  * screenyl * sizeof(float) * 2, 0, D3DUSAGE_WRITEONLY, POOL_DEFAULT);
	float* vbdata;
	m_VBSSFrag->GetBuffer()->Lock(0, 0, (void**)&vbdata, 0);

	for(int y = 0; y < screenyl; y++)
	{
		for(int x = 0; x < screenxl; x++)
		{
			//sample at center, therefore + 0.5
			*vbdata++ = (x + 0.5f) / screenxl;
			*vbdata++ = (y + 0.5f) / screenyl;
		}
	}

	m_VBSSFrag->GetBuffer()->Unlock();

	m_DI.RestoreDeviceCursor();
}

void ShadowApp::Invalidate(void)
{
	if (m_pScene[0])
		m_pScene[0]->Invalidate();

	if (m_pScene[1])
		m_pScene[1]->Invalidate();
}

void ShadowApp::OnCreateDevice(void)
{
	m_SM = new ShadowMapping(m_Device);
	m_SM->SetLispSMEnable(false);
	m_SM->SetJitterType((SMJITTERTYPE)2);
	m_SM->SetIDBufferEnable(m_Config.UseIDBuffer);
	m_SM->SetShadowMapSize(m_Config.ShadowMapSize);

	m_FXDS = m_Device->GetShaderManager()->CreateFX("Shaders\\Deferred.fx");

	m_FXOptConf = m_Device->GetShaderManager()->CreateFX("Shaders\\OptConf.fx");

	m_FXSSAO = m_Device->GetShaderManager()->CreateFX("Shaders\\SSAO.fx");

	m_FXMat = m_Device->GetShaderManager()->CreateFX("Shaders\\Materials.fx");

	//else
	//	wlog("%s", m_FXDS->GetDisassembly().getbuffer());

	D3DVERTEXELEMENT9 declFullScreen[] =
    {
        { 0, 0, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITIONT, 0 },  
		{ 0, 16, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 }, 
		//{ 0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 1 }, 
        D3DDECL_END()
    };
	m_VDeclFSQuad = new VertexDeclaration(m_Device, declFullScreen);

	m_VBFSQuad = m_Device->GetBufferManager()->CreateVB(sizeof(float)*9*4, 0, D3DUSAGE_WRITEONLY, POOL_DEFAULT);

	m_DynVB = m_Device->GetBufferManager()->CreateDynamicVB(sizeof(float)*1024); //space for 5 tiles

	/*m_Terrain = new Terrain(this, 5, 0.0042f, 4, "heightfield513.raw", 512);
	//m_Terrain = new Terrain(this, 5, 0.0042f, 1, "heightfield2049.raw", 2048);

	for(int i=0; i < g_iMeshTypes; i++)
	{
		g_pMeshes[i] = new CMesh(m_Device, XString(g_strMeshes[i]), XString("Objects\\"));
		g_pMeshes[i]->BuildDrawCalls();
		for(unsigned j= 0; j<g_pMeshes[i]->GetMaterialCount(); j++)
			g_pMeshes[i]->GetMaterials()[j].SetAmbient(D3DXCOLOR(0.2f, 0.2f, 0.2f, 1));

		for(int j=0; j<g_iMeshCount[i];j++)
		{
			DXMatrix matScale;
			D3DXMatrixScaling((D3DXMATRIX*)&matScale, g_fMeshScale[i], g_fMeshScale[i], g_fMeshScale[i]);

			DXMatrix matRotate;
			D3DXMatrixRotationX((D3DXMATRIX*)&matRotate, g_fMeshRot[i]);
		
			float x = frand() * 2048;
			float y = frand() * 2048;
			float z = m_Terrain ? m_Terrain->GetHeight(x, y) : 0;

			DXMatrix matTrans;
			D3DXMatrixTranslation((D3DXMATRIX*)&matTrans, x, y, z + g_fMeshZOff[i]);
			Object* obj = new Object(this, g_pMeshes[i], matScale * matRotate * matTrans);

			m_Objects.AddTail(obj, 0);
		}
	}*/

	m_iScene = 0;

	m_pScene[0] = new TerrainScene(this);
	m_pScene[1] = new PowerPlantScene(this);

	m_DSDiffuse = m_Device->GetViewPort()->CreateViewPortRenderTexture(1, FMT_A8R8G8B8);
	m_DSDiffuse->CreateDepthStencil(FMT_D24X8);

	m_DSNormal = m_Device->GetViewPort()->CreateViewPortRenderTexture(1, FMT_G16R16F);

	m_DSDepth = m_Device->GetViewPort()->CreateViewPortRenderTexture(1, FMT_R32F);
	
	m_DSWorld = m_Device->GetViewPort()->CreateViewPortRenderTexture(1, FMT_A32B32G32R32F);

	m_DSID = m_Device->GetViewPort()->CreateViewPortRenderTexture(1, FMT_R32F);

	m_DSSSAO = m_Device->GetViewPort()->CreateViewPortRenderTexture(1, FMT_R32F);
	
	m_DSShadow[0] = m_Device->GetViewPort()->CreateViewPortRenderTexture(1, FMT_A8R8G8B8);
	m_DSShadow[0]->CreateDepthStencil(FMT_D24S8);

	m_DSShadow[1] = m_Device->GetViewPort()->CreateViewPortRenderTexture(1, FMT_A8R8G8B8);

	m_DSShadowRef = m_Device->GetViewPort()->CreateViewPortRenderTexture(1, FMT_A8R8G8B8);
	m_DSShadowRefDiff = m_Device->GetViewPort()->CreateViewPortRenderTexture(1, FMT_A8R8G8B8);
	m_DSSampleVis = m_Device->GetViewPort()->CreateViewPortRenderTexture(1, FMT_R32F);
	m_OptConf = m_Device->GetViewPort()->CreateViewPortRenderTexture(1, FMT_R32F);

	m_pMenuManager = new MenuManager(m_Device, &m_DI);

	m_Techniques[SM_CONFIDENCE] = new DeferredShadowConfidence(this);
	m_Techniques[SM_ZTILED] = new DeferredShadowZTiled(this);
	m_Techniques[SM_SSTILED] = new DeferredShadowSSTiled(this);
	m_Techniques[SM_SMTILED] = new DeferredShadowSMTiled(this);

	PromptShaderErrors();

	SetupSSAO();

	FontParam fp;
	fp.m_Height = 16;
	m_Font = m_Device->GetFontManager()->Create(fp);

	//CreateMenu();
	m_pMenuManager->AddMenu(new MainMenu(m_pMenuManager, this));
	
	if (m_Techniques[(int)m_Config.Method])
		m_pMenuManager->AddMenu(m_Techniques[(int)m_Config.Method]->GetMenu());
}

void ShadowApp::SetActive(const bool act)
{	
	if(m_Active == act)
		return;

	m_Active = act;

	if(m_Active)
		m_DI.SetAcquire(true);
}

void ShadowApp::RenderSceneDS(void)
{
	if(m_FXDS->IsCompiled()) 
	{
		//clear depth/worldpos
		if (m_Config.WorldPosType == WPT_WORLDPOS)
			m_DSWorld->StartRender(0);
		else
			m_DSDepth->StartRender(0);	

		if (m_Config.WorldPosType == WPT_WORLDPOS)
			ClearFloat(DXColor(0, 0, 0, 0));
		else if (m_Config.WorldPosType == WPT_DEPTH)
			ClearFloat(DXColor(1, 0, 0, 0));
		else if (m_Config.WorldPosType == WPT_LINEARDEPTH)
			//ClearFloat(DXColor(GetActiveCam().GetFarPlane(), 0, 0, 0));
			ClearFloat(DXColor(-FLT_MAX, 0, 0, 0));

		if (m_Config.WorldPosType == WPT_WORLDPOS)
			m_DSWorld->EndRender();
		else
			m_DSDepth->EndRender();



		m_DSDiffuse->StartRender(0);
		m_DSNormal->StartRender(1);
		
		if (m_Config.WorldPosType == WPT_WORLDPOS)
			m_DSWorld->StartRender(2);
		else
			m_DSDepth->StartRender(2);		

		if (m_Config.UseIDBuffer && !m_Config.UsePrimID) //if primid should be used it will be rendered in an separate pass
			m_DSID->StartRender(3); 

		m_Device->Clear( D3DCLEAR_ZBUFFER, 0xffffffff, 1.0f, 0L );

		GetActiveScene()->m_RL.Render(m_Device);

		m_DSDiffuse->EndRender();
		m_DSNormal->EndRender();
		
		if (m_Config.WorldPosType == WPT_WORLDPOS)
			m_DSWorld->EndRender();
		else
			m_DSDepth->EndRender();

		if (m_Config.UseIDBuffer && !m_Config.UsePrimID)
			m_DSID->EndRender();


		//renderprimitive id if enables

		if (m_Config.UseIDBuffer && m_Config.UsePrimID && m_FXMat->IsCompiled()) // && fxterrain compiled
		{
			m_DSDiffuse->GetDepthStencil()->StartRender();
			m_DSID->StartRender(0); 

			//maually overwrite techniques
			RenderJob** jobs = GetActiveScene()->m_RL.GetJobs().GetStack();
			for (int i = 0; i < GetActiveScene()->m_RL.GetJobs().GetElementCount(); i++)
			{
				RenderJob* j = *jobs;
				j->Technique = "RenderDS_PrimID";
				jobs++;
			}

			GetActiveScene()->m_RL.Render(m_Device);

			//just reset all techniques
			m_pScene[0]->UpdateTechnique();
			m_pScene[1]->UpdateTechnique();

			m_DSDiffuse->GetDepthStencil()->EndRender();
			m_DSID->EndRender(); 
		}


		DXMatrix matInvProj;
		D3DXMatrixInverse((D3DXMATRIX*)&matInvProj, NULL, (D3DXMATRIX*)&(GetActiveCam().GetProjMatrix()));
		m_FXDS->SetMatrix("g_matInvProj", matInvProj);

		DXMatrix matInvViewProj;
		D3DXMatrixInverse((D3DXMATRIX*)&matInvViewProj, NULL, (D3DXMATRIX*)&(GetActiveCam().GetViewProjMatrix()));
		m_FXDS->SetMatrix("g_matInvViewProj", matInvViewProj);

		DXMatrix matInvView;
		D3DXMatrixInverse((D3DXMATRIX*)&matInvView, NULL, (D3DXMATRIX*)&(GetActiveCam().GetViewMatrix()));
		m_FXDS->SetMatrix("g_matInvView", matInvView);

		//1 - 2000

		//dd *= z;

		m_FXDS->SetFloat("SM_ShadowMapSize", m_SM->GetShadowMapSize());
		m_FXDS->SetFloat("SM_DetphBias", m_Config.ConstBias);
		m_FXDS->SetFloat("SM_SlopeBias", m_Config.SlopeBias);
		//m_FXDS->SetFloat("SM_rcpShadowMapSize", 1.f/m_SM->GetShadowMapSize());

		if (m_Config.WorldPosType == WPT_WORLDPOS)
			m_FXDS->SetTexture("g_texWorld", m_DSWorld->GetSurface());
		else
			m_FXDS->SetTexture("g_texDepth", m_DSDepth->GetSurface());
		
		m_FXDS->SetTexture("Diffuse", m_DSDiffuse->GetSurface());
		m_FXDS->SetTexture("SM_ShadowMap", m_SM->GetShadowMap());
		m_FXDS->SetTexture("SM_IDBuffer", m_SM->GetIDBuffer());
		m_FXDS->SetTexture("Normal", m_DSNormal->GetSurface());
		m_FXDS->SetFloatArray("LightDir", (float*)&GetActiveScene()->GetLight()->GetDirection(), 3);
		m_FXDS->SetFloatArray("CamPos", (float*)&(GetActiveCam().GetPosition()), 3);
		m_FXDS->SetMatrix("SM_matSM", m_SM->GetSMMatrix());
	
		m_FXDS->SetFloat("g_ConfScale", 1);

		float rtsize[2] = {m_Device->GetViewPort()->GetWidth(), m_Device->GetViewPort()->GetHeight()};
		m_FXDS->SetFloatArray("g_RTSize", rtsize, 2);
		
		//RenderOptConf();

		m_FXDS->SetTexture("OptConf", m_OptConf->GetSurface());

		m_FXDS->SetFloat("MaxPasses", m_Config.MaxJitter + 1);

		m_Device->SetStencilEnalbe(false);
	

//		bool optconfup2date = true;

		if(m_VisType == VIS_SAMPLE)
		{
			m_DSSampleVis->StartRender(0);
			m_Device->Clear(D3DCLEAR_TARGET, 0, 0, 0);
			m_DSSampleVis->EndRender();
		}

		if (m_Techniques[(int)m_Config.Method] && (m_VisType == VIS_SAMPLE || m_VisType == VIS_NONE || m_VisType == VIS_FINALCONF || m_VisType == VIS_PASS || m_VisType == VIS_REQRES && m_Config.Method == SM_SMTILED))
		{
			m_Techniques[(int)m_Config.Method]->RenderShadowMask();
		}
		else //SM_DEFERRED
		{
			//m_SM->Jitter(2);
			m_FXDS->SetMatrix("SM_matSM", m_SM->GetSMMatrix());

			if (m_VisType == VIS_NONE || m_VisType == VIS_SAMPLE)
				GetActiveScene()->GetLight()->RenderShadowMap();

			if(m_VisType == VIS_SAMPLE)
			{
				DrawSampleVis();
			}
			else if(m_VisType == VIS_OPTCONF)
			{
				RenderOptConf(1);
			}
		}
		if (m_Config.UseSSAO || m_VisType == VIS_SSAO)
		{
			RenderSSAO();

			m_FXDS->SetTexture("g_texSSAO", m_DSSSAO->GetSurface());
		}

		////

		int ish = 1;
		
		m_Device->SetStreamSource(0, m_VBFSQuad->GetBuffer(), 0, sizeof(float)*6);
		m_Device->SetVertexDeclaration(m_VDeclFSQuad);

		if(!(m_BenchType == BT_CONVERGENCE && m_RenderRef))
		{
			if(m_Config.Method != SM_DEFERRED)
			{
				m_FXDS->SetTechnique("RenderDilate");
				for(int k = 0; k < m_Config.CloseSize; k++)
				{
					m_DSShadow[ish]->StartRender(0);
					m_FXDS->SetTexture("ShadowMap", m_DSShadow[1-ish]->GetSurface());
					RENDERFX(m_FXDS, 
						m_Device->DrawPrimitive(PT_TRIANGLESTRIP, 0, 2);
					);
					m_DSShadow[ish]->EndRender();
					ish = 1-ish;
				}

				m_FXDS->SetTechnique("RenderErode");
				for(int k = 0; k < m_Config.CloseSize - (m_Config.ErodeOneLess?1:0); k++)
				{
					m_DSShadow[ish]->StartRender(0);
					m_FXDS->SetTexture("ShadowMap", m_DSShadow[1-ish]->GetSurface());
					RENDERFX(m_FXDS, 
						m_Device->DrawPrimitive(PT_TRIANGLESTRIP, 0, 2);
					);
					m_DSShadow[ish]->EndRender();
					ish = 1-ish;
				}
			}
		}
		
		if (m_BenchType == BT_CONVERGENCE && m_RenderRef)
			m_FXDS->SetTexture("ShadowMap", m_DSShadowRef->GetSurface());
		else
			m_FXDS->SetTexture("ShadowMap", m_DSShadow[1-ish]->GetSurface());

		if (m_Config.UseIDBuffer)
			m_FXDS->SetTexture("g_texID", m_DSID->GetSurface());

		XString technique = "RenderFinal";

		if (m_Config.Method == SM_DEFERRED && (m_VisType == VIS_NONE || m_VisType == VIS_SAMPLE))
		{
			technique.appand("Shadow");

			if (m_VisType == VIS_SAMPLE)
			{
				m_FXDS->SetTexture("SampleVis", m_DSSampleVis->GetSurface());
				technique.appand("_SampleVis");
			}
			else
			{
				if (m_Config.SMFiltering)
					technique.appand("_Filter");
				else if (m_Config.UseIDBuffer)
					technique.appand("_ID");
			}

			if (m_Config.WorldPosType == WPT_DEPTH)
				technique.appand("_Depth");
			else if (m_Config.WorldPosType == WPT_LINEARDEPTH)
				technique.appand("_LinearDepth");
			else if (m_Config.WorldPosType == WPT_WORLDPOS)
				technique.appand("_World");
		}
		else
		{
			technique.appand("_");

			if (m_VisType == VIS_SAMPLE)
			{
				m_FXDS->SetTexture("SampleVis", m_DSSampleVis->GetSurface());
				technique.appand("SampleVis");
			}
			else if (m_VisType == VIS_PASS)
			{
				technique.appand("PassVis");
			}
			else if (m_VisType == VIS_FINALCONF)
			{
				technique.appand("FinalConfVis");
			}
			else if (m_VisType == VIS_OPTCONF)
			{
				technique.appand("OptConfVis");
			}
			else if (m_VisType == VIS_ID)
			{
				technique.appand("IDVis");
			}
			else if (m_VisType == VIS_SSAO)
			{
				technique.appand("SSAOVis");
			}
			else if (m_VisType == VIS_REQRES)
			{
				technique.appand("ReqResVis");

				m_FXDS->SetTexture("g_texReqRes", ((DeferredShadowSMTiled*)m_Techniques[SM_SMTILED])->GetReqRes()->GetSurface());
			}
		}

		m_FXDS->SetTechnique(technique);

		m_FXDS->SetVector("g_LightColor", static_cast<DXVector4>(GetActiveScene()->GetLight()->GetColor()));
		m_FXDS->SetVector("g_AmbientColor", static_cast<DXVector4>(GetActiveScene()->m_AmbientColor));
		m_FXDS->SetFloat("g_LambertScale", m_Config.LambertScale);
		
		RenderFSQuad(m_FXDS);
		/*RENDERFX(m_FXDS, 
			m_Device->DrawPrimitive(PT_TRIANGLESTRIP, 0, 2);
		);*/

		if (m_Config.UseSSAO && m_VisType == VIS_NONE)
		{
			m_FXDS->SetTechnique("RenderSSAO");

			RenderFSQuad(m_FXDS);
		}

		if(m_BenchType == BT_CONVERGENCE && !m_RenderRef)
		{
			m_Passes[m_iPixelDiff] = m_PassesDone;
			m_PixelDiff[m_iPixelDiff++] = ShadowDiff(m_DSShadow[0], m_DSShadowRef);
		}
	}
}

void ShadowApp::DrawFrustum(const Camera& c, const D3DXCOLOR color)
{
	const ViewFrustum f(c);

	//if viewpos inside viewfrustum we have to toggle cullmode
	if(Intr_Point_ViewFrustum(GetActiveScene()->GetDebugCamera().GetPosition(),f)) 
		m_Device->SetCullmode(CULL_CW);
	else
		m_Device->SetCullmode(CULL_CCW);

	//m_Device->SetCullmode(D3DCULL_NONE);

	BoundingMesh m(f);
	//m->ClipByOBB(OBB(DXVector3(-1000,-1000,-80),DXVector3(1000,1000,80)));
	DrawBoundingMesh(m, color);
	//now draw edges lines

	LPDIRECT3DVERTEXBUFFER9 VertexBuffer;
	m_Device->GetDevice()->CreateVertexBuffer((24 + 2) * sizeof(DXVector3), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, D3DFVF_XYZ, D3DPOOL_DEFAULT, &VertexBuffer, NULL);

	DXVector3* VBData;
	VertexBuffer->Lock(0,0,(void**)&VBData,D3DLOCK_DISCARD);

	//front
	*VBData++ = f.FrustumPoints[0];
	*VBData++ = f.FrustumPoints[1];

	*VBData++ = f.FrustumPoints[1];
	*VBData++ = f.FrustumPoints[2];

	*VBData++ = f.FrustumPoints[2];
	*VBData++ = f.FrustumPoints[3];

	*VBData++ = f.FrustumPoints[3];
	*VBData++ = f.FrustumPoints[0];

	//back
	*VBData++ = f.FrustumPoints[4];
	*VBData++ = f.FrustumPoints[5];

	*VBData++ = f.FrustumPoints[5];
	*VBData++ = f.FrustumPoints[6];

	*VBData++ = f.FrustumPoints[6];
	*VBData++ = f.FrustumPoints[7];

	*VBData++ = f.FrustumPoints[7];
	*VBData++ = f.FrustumPoints[4];

	//center
	*VBData++ = f.FrustumPoints[0];
	*VBData++ = f.FrustumPoints[4];

	*VBData++ = f.FrustumPoints[1];
	*VBData++ = f.FrustumPoints[5];

	*VBData++ = f.FrustumPoints[2];
	*VBData++ = f.FrustumPoints[6];	

	*VBData++ = f.FrustumPoints[3];
	*VBData++ = f.FrustumPoints[7];

	//up-vector
	D3DXMATRIX mv = m_SM->GetLightView();
	D3DXMatrixInverse(&mv,NULL,&mv);
	DXVector3 v(0,0,1);
	D3DXVec3TransformNormal(v, v, &mv); 
	*VBData++ = c.GetPosition();
	*VBData++ = c.GetPosition() + v * 20;//+ c.GetViewUpVector() * 10;

	VertexBuffer->Unlock();

	m_Device->SetStreamSource(0, VertexBuffer, 0, sizeof(DXVector3));
	m_Device->SetAlphaBlendEnable(false);
	m_Device->SetTextureFactor(D3DXCOLOR(0xff000000));

	m_Device->DrawPrimitive(PT_LINELIST,0,12 + 1);

	m_Device->SetPointSize(4.f);

	m_Device->DrawPrimitive(PT_POINTLIST,24,1);

	m_Device->SetStreamSource(0, NULL, 0, 0);

	VertexBuffer->Release();
}

void ShadowApp::DrawBoundingMesh(const BoundingMesh &m, const D3DXCOLOR color)
{
	if(!m.GetTriangleCount())
		return;

	LPDIRECT3DVERTEXBUFFER9 VertexBuffer;
	m_Device->GetDevice()->CreateVertexBuffer(m.GetTriangleCount() * 3 * sizeof(DXVector3), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, D3DFVF_XYZ, D3DPOOL_DEFAULT, &VertexBuffer, NULL);

	DXVector3 *VBData;
	VertexBuffer->Lock(0,0,(void**)&VBData,D3DLOCK_DISCARD);

	memcpy(VBData, m.GetPoints(), m.GetTriangleCount() * 3 * sizeof(DXVector3));

	VertexBuffer->Unlock();

	m_Device->SetVertexShader((VertexShader*)NULL);
	m_Device->SetPixelShader((PixelShader*)NULL);

	D3DXMATRIX matIdentity;
	D3DXMatrixIdentity(&matIdentity);
	m_Device->SetWorldMatrix(matIdentity);
	m_Device->SetViewMatrix((D3DXMATRIX)GetActiveScene()->GetDebugCamera().GetViewMatrix());
	m_Device->SetProjMatrix((D3DXMATRIX)GetActiveScene()->GetDebugCamera().GetProjMatrix());
	
	m_Device->SetZFunc(CMP_LESS);
	m_Device->SetZEnable(ZB_TRUE);
	m_Device->SetZWriteEnable(false);
	m_Device->SetAlphaBlendEnable(true);
	m_Device->SetAlphaTestEnable(false);
	m_Device->SetLighting(false);
	m_Device->SetSrcBlend(BLEND_SRCALPHA);
	m_Device->SetDestBlend(BLEND_INVSRCALPHA);

	DWORD c = color;
	m_Device->SetTextureFactor(D3DXCOLOR(0x33000000 | 0xffffff & c));
	m_Device->SetStageColorOperation(0,D3DTA_TFACTOR,D3DTOP_SELECTARG1,D3DTA_CURRENT);
	m_Device->SetStageAlphaOperation(0,D3DTA_TFACTOR,D3DTOP_SELECTARG1,D3DTA_CURRENT);

	m_Device->SetStreamSource(0,VertexBuffer,0,sizeof(DXVector3));
	m_Device->SetFVF(D3DFVF_XYZ);

	m_Device->DrawPrimitive(PT_TRIANGLELIST,0,m.GetTriangleCount());

	VertexBuffer->Release();
}

void ShadowApp::DrawBoundingBox(const OBB& box)
{
	LPDIRECT3DVERTEXBUFFER9 VertexBuffer;
	m_Device->GetDevice()->CreateVertexBuffer((24 + 2) * sizeof(DXVector3), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, D3DFVF_XYZ, D3DPOOL_DEFAULT, &VertexBuffer, NULL);

	DXVector3* VBData;
	VertexBuffer->Lock(0,0,(void**)&VBData,D3DLOCK_DISCARD);

	//min side
	*VBData++ = DXVector3(box.GetMin().x, box.GetMin().y, box.GetMin().z);
	*VBData++ = DXVector3(box.GetMin().x, box.GetMax().y, box.GetMin().z);

	*VBData++ = DXVector3(box.GetMin().x, box.GetMax().y, box.GetMin().z);
	*VBData++ = DXVector3(box.GetMax().x, box.GetMax().y, box.GetMin().z);

	*VBData++ = DXVector3(box.GetMax().x, box.GetMax().y, box.GetMin().z);
	*VBData++ = DXVector3(box.GetMax().x, box.GetMin().y, box.GetMin().z);

	*VBData++ = DXVector3(box.GetMax().x, box.GetMin().y, box.GetMin().z);
	*VBData++ = DXVector3(box.GetMin().x, box.GetMin().y, box.GetMin().z);

	//max side
	*VBData++ = DXVector3(box.GetMin().x, box.GetMin().y, box.GetMax().z);
	*VBData++ = DXVector3(box.GetMin().x, box.GetMax().y, box.GetMax().z);

	*VBData++ = DXVector3(box.GetMin().x, box.GetMax().y, box.GetMax().z);
	*VBData++ = DXVector3(box.GetMax().x, box.GetMax().y, box.GetMax().z);

	*VBData++ = DXVector3(box.GetMax().x, box.GetMax().y, box.GetMax().z);
	*VBData++ = DXVector3(box.GetMax().x, box.GetMin().y, box.GetMax().z);

	*VBData++ = DXVector3(box.GetMax().x, box.GetMin().y, box.GetMax().z);
	*VBData++ = DXVector3(box.GetMin().x, box.GetMin().y, box.GetMax().z);

	//center
	*VBData++ = DXVector3(box.GetMin().x, box.GetMin().y, box.GetMin().z);
	*VBData++ = DXVector3(box.GetMin().x, box.GetMin().y, box.GetMax().z);

	*VBData++ = DXVector3(box.GetMin().x, box.GetMax().y, box.GetMin().z);
	*VBData++ = DXVector3(box.GetMin().x, box.GetMax().y, box.GetMax().z);

	*VBData++ = DXVector3(box.GetMax().x, box.GetMax().y, box.GetMin().z);
	*VBData++ = DXVector3(box.GetMax().x, box.GetMax().y, box.GetMax().z);

	*VBData++ = DXVector3(box.GetMax().x, box.GetMin().y, box.GetMin().z);
	*VBData++ = DXVector3(box.GetMax().x, box.GetMin().y, box.GetMax().z);

	//extreme points
	//*VBData++ = DXVector3(box.GetMin().x, box.GetMin().y, box.GetMin().z);
	//*VBData++ = DXVector3(box.GetMax().x, box.GetMax().y, box.GetMax().z);

	*VBData++ = GetActiveScene()->GetLight()->GetShadowFarPoint();
	*VBData++ = GetActiveScene()->GetLight()->GetShadowFarPoint() + GetActiveScene()->GetLight()->GetShadowFarPlaneNormal() * 20;

	/**VBData++ = DXVector3(box.GetMin().x, box.GetMin().y, box.GetMin().z);
	*VBData++ = DXVector3(box.GetMin().x, box.GetMin().y, box.GetMin().z) - DXVector3(10,0,0);
	*VBData++ = DXVector3(box.GetMin().x, box.GetMin().y, box.GetMin().z);
	*VBData++ = DXVector3(box.GetMin().x, box.GetMin().y, box.GetMin().z) - DXVector3(0,10,0);
	*VBData++ = DXVector3(box.GetMin().x, box.GetMin().y, box.GetMin().z);
	*VBData++ = DXVector3(box.GetMin().x, box.GetMin().y, box.GetMin().z) - DXVector3(0,0,10);

	*VBData++ = DXVector3(box.GetMax().x, box.GetMax().y, box.GetMax().z);
	*VBData++ = DXVector3(box.GetMax().x, box.GetMax().y, box.GetMax().z) + DXVector3(10,0,0);
	*VBData++ = DXVector3(box.GetMax().x, box.GetMax().y, box.GetMax().z);
	*VBData++ = DXVector3(box.GetMax().x, box.GetMax().y, box.GetMax().z) + DXVector3(0,10,0);
	*VBData++ = DXVector3(box.GetMax().x, box.GetMax().y, box.GetMax().z);
	*VBData++ = DXVector3(box.GetMax().x, box.GetMax().y, box.GetMax().z) + DXVector3(0,0,10);*/

	VertexBuffer->Unlock();

	m_Device->SetVertexShader((VertexShader*)NULL);
	m_Device->SetPixelShader((PixelShader*)NULL);

	m_Device->SetWorldMatrix(box.GetOrientation());
	m_Device->SetViewMatrix((D3DXMATRIX)GetActiveScene()->GetDebugCamera().GetViewMatrix());
	m_Device->SetProjMatrix((D3DXMATRIX)GetActiveScene()->GetDebugCamera().GetProjMatrix());
	
	m_Device->SetZFunc(CMP_LESS);
	m_Device->SetZEnable(ZB_TRUE);
	m_Device->SetZWriteEnable(false);
	m_Device->SetAlphaBlendEnable(false);
	m_Device->SetAlphaTestEnable(false);
	m_Device->SetLighting(false);

	//DWORD c = color;
	DWORD c = 0xff0000ff;
	m_Device->SetTextureFactor(D3DXCOLOR(0x33000000 | 0xffffff & c));
	m_Device->SetStageColorOperation(0,D3DTA_TFACTOR,D3DTOP_SELECTARG1,D3DTA_CURRENT);
	m_Device->SetStageAlphaOperation(0,D3DTA_TFACTOR,D3DTOP_SELECTARG1,D3DTA_CURRENT);

	m_Device->SetStreamSource(0,VertexBuffer,0,sizeof(DXVector3));
	m_Device->SetFVF(D3DFVF_XYZ);

	m_Device->SetPointSize(8);
	m_Device->SetAlphaBlendEnable(false);

	m_Device->DrawPrimitive(PT_LINELIST, 0, 12);

	m_Device->SetWorldMatrix(DXMatrix::IDENTITY());
	m_Device->DrawPrimitive(PT_POINTLIST, 24, 2);
 
	m_Device->SetStreamSource(0, NULL, 0, 0);

	VertexBuffer->Release();
}


void ShadowApp::WlogCamPos(void)
{
	wlog("Camera Orientation and Daytime:\nm_CamPos[] = DXVector3(%ff, %ff, %ff);\nm_CamDir[] = DXVector3(%ff, %ff, %ff);\nm_CamUp[] = DXVector3(%ff, %ff, %ff);\nm_CamLightAngX[] = %ff; m_CamLightAngZ[] = %ff;",
		GetActiveCam().GetPosition().x, GetActiveCam().GetPosition().y, GetActiveCam().GetPosition().z, GetActiveCam().GetViewDirVector().x, GetActiveCam().GetViewDirVector().y, GetActiveCam().GetViewDirVector().z,
		GetActiveCam().GetViewUpVector().x, GetActiveCam().GetViewUpVector().y, GetActiveCam().GetViewUpVector().z, GetActiveScene()->GetLightAngX(), GetActiveScene()->GetLightAngZ());
}

void ShadowApp::DrawSampleVis(void)
{
	m_DSSampleVis->StartRender(0);

	//m_Device->Clear(D3DCLEAR_TARGET, 0, 0, 0);

	m_FXDS->SetTexture("Depth", m_DSDepth->GetSurface());
	
	m_FXDS->SetTexture("SM_ShadowMap", m_SM->GetShadowMap());
	m_FXDS->SetTexture("SM_IDBuffer", m_SM->GetIDBuffer());
	m_FXDS->SetFloat("SM_ShadowMapSize", m_SM->GetShadowMapSize());
	m_FXDS->SetMatrix("SM_matSM", m_SM->GetSMMatrix());

	m_FXDS->SetMatrix("matInvViewProj", DXMatrix::InvertMatrix(GetActiveCam().GetViewProjMatrix()));

	XString tech = "RenderSampleVis";
	if (m_Config.WorldPosType == WPT_DEPTH)
		tech.appand("_Depth");
	else if (m_Config.WorldPosType == WPT_LINEARDEPTH)
		tech.appand("_LinearDepth");
	else if (m_Config.WorldPosType == WPT_WORLDPOS)
		tech.appand("_World");

	m_FXDS->SetTechnique(tech);

	RenderFSQuad(m_FXDS);
	
	m_DSSampleVis->EndRender();

}

unsigned ShadowApp::ShadowDiff(RenderTarget* rtsh, RenderTarget* rtref)
{
	unsigned pixeldiff = 0;

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

	m_Device->SetStreamSource(0, m_VBFSQuad->GetBuffer(), 0, sizeof(float)*6);
	m_Device->SetVertexDeclaration(m_VDeclFSQuad);

	m_FXDS->SetTechnique("RenderShadowDiff");
	m_FXDS->SetTexture("ShadowMap", rtsh->GetSurface());
	m_FXDS->SetTexture("ShadowMapRef", rtref->GetSurface());

	m_DSShadowRefDiff->StartRender(0);

	pOcclusionQuery->Issue(D3DISSUE_BEGIN);

	RENDERFX(m_FXDS, m_Device->DrawPrimitive(PT_TRIANGLESTRIP, 0, 2););

	pOcclusionQuery->Issue(D3DISSUE_END);

	while(S_FALSE == pOcclusionQuery->GetData(&pixeldiff, sizeof(DWORD), D3DGETDATA_FLUSH ));

	m_DSShadowRefDiff->EndRender();

	pOcclusionQuery->Release();

	return pixeldiff;
}

/*void ShadowApp::RenderOptConf(void)
{
	//m_Device->SetStencilEnalbe(false);

	m_OptConf->StartRender(0);
			
	m_FXDS->SetTechnique("RenderOptConf");

	m_Device->Clear(D3DCLEAR_TARGET, 0x00000000, 0, 0);

	m_Device->SetStreamSource(0, m_VBFSQuad->GetBuffer(), 0, sizeof(float)*6);
	m_Device->SetVertexDeclaration(m_VDeclFSQuad);

	RENDERFX(m_FXDS, 
		m_Device->DrawPrimitive(PT_TRIANGLESTRIP, 0, 2);
	);

	m_OptConf->EndRender();

	m_SMOptConfSize = m_SM->GetSMWorldSize();

	//m_Device->SetStencilEnalbe(true);
}*/

void ShadowApp::RenderOptConf(const float conf)
{
	//m_Device->SetStencilEnalbe(false);

	m_OptConf->StartRender(0);
			
	XString tech = "RenderOptConf";
	if (m_Config.WorldPosType == WPT_DEPTH)
		tech.appand("_Depth");
	else if (m_Config.WorldPosType == WPT_LINEARDEPTH)
		tech.appand("_LinearDepth");
	else if (m_Config.WorldPosType == WPT_WORLDPOS)
		tech.appand("_World");
	m_FXOptConf->SetTechnique(tech);

	if (m_Config.WorldPosType == WPT_WORLDPOS)
		m_FXOptConf->SetTexture("g_texWorld", m_DSWorld->GetSurface());
	else
		m_FXOptConf->SetTexture("g_texDepth", m_DSDepth->GetSurface()); 

	m_FXOptConf->SetTexture("g_texNormal", m_DSNormal->GetSurface());
	m_FXOptConf->SetTexture("g_texDiffuse", m_DSDiffuse->GetSurface());
	
	m_FXOptConf->SetTexture("SM_ShadowMap", m_SM->GetShadowMap());
	m_FXOptConf->SetTexture("SM_IDBuffer", m_SM->GetIDBuffer());
	m_FXOptConf->SetFloat("SM_ShadowMapSize", m_SM->GetShadowMapSize());
	m_FXOptConf->SetMatrix("SM_matSM", m_SM->GetSMMatrix());

	m_FXOptConf->SetMatrix("g_matInvViewProj", DXMatrix::InvertMatrix(GetActiveScene()->GetCamera().GetViewProjMatrix()));
	m_FXOptConf->SetMatrix("g_matInvView", DXMatrix::InvertMatrix(GetActiveScene()->GetCamera().GetViewMatrix()));
	m_FXOptConf->SetMatrix("g_matInvProj", DXMatrix::InvertMatrix(GetActiveScene()->GetCamera().GetProjMatrix()));
	m_FXOptConf->SetFloat("g_ShadowConfT", conf);
	m_FXOptConf->SetFloatArray("g_LightDir", GetActiveScene()->GetLight()->GetDirection(), 3);
	m_FXOptConf->SetFloatArray("g_RTSize", DXVector2(m_Device->GetViewPort()->GetWidth(), m_Device->GetViewPort()->GetHeight()), 2); 

	m_Device->Clear(D3DCLEAR_TARGET, 0x00000000, 0, 0);

	RenderFSQuad(m_FXOptConf);

	m_OptConf->EndRender();

	//m_Device->SetStencilEnalbe(true);
}

void ShadowApp::RenderFSQuad(ShaderEffect* const fx)
{
	RenderQuad(0, 0, m_Device->GetViewPort()->GetWidth(), m_Device->GetViewPort()->GetHeight(), fx, m_Device->GetViewPort()->GetWidth(), m_Device->GetViewPort()->GetHeight());
}

void ShadowApp::RenderQuad(const unsigned x, const unsigned y, const unsigned xl, const unsigned yl, ShaderEffect* const fx, const unsigned screenxl, const unsigned screenyl)
{
	float* buffer = (float*)m_DynVB->LockVB(sizeof(float)*9 * 4);

	//float screenxl = m_Device->GetViewPort()->GetWidth();
	//float screenyl = m_Device->GetViewPort()->GetHeight();

	//view vectors to corners
	DXVector3 vec0, vec1, vec2, vec3;
	
	vec0.x =  ( ( ( 2.0f * (x - 0.5f) ) / (float)screenxl ) - 1.f ) / GetActiveCam().GetProjMatrix()._11;
    vec0.y = -( ( ( 2.0f * (y - 0.5f) ) / (float)screenyl ) - 1.f ) / GetActiveCam().GetProjMatrix()._22;
    vec0.z =  1.0f;

	vec1.x =  ( ( ( 2.0f * (x + xl - 0.5f) ) / (float)screenxl) - 1.f ) / GetActiveCam().GetProjMatrix()._11;
    vec1.y = -( ( ( 2.0f * (y - 0.5f) ) / (float)screenyl ) - 1.f ) / GetActiveCam().GetProjMatrix()._22;
    vec1.z =  1.0f;

	vec2.x =  ( ( ( 2.0f * (x - 0.5f) ) / (float)screenxl ) - 1.f ) / GetActiveCam().GetProjMatrix()._11;
    vec2.y = -( ( ( 2.0f * (y + yl - 0.5f) ) / (float)screenyl ) - 1.f ) / GetActiveCam().GetProjMatrix()._22;
    vec2.z =  1.0f;

	vec3.x =  ( ( ( 2.0f * (x + xl - 0.5f) ) / (float)screenxl ) - 1.f ) / GetActiveCam().GetProjMatrix()._11;
    vec3.y = -( ( ( 2.0f * (y + yl - 0.5f) ) / (float)screenyl ) - 1.f ) / GetActiveCam().GetProjMatrix()._22;
    vec3.z =  1.0f;

	//x,y,z,w,tu,tv,viewvec_xyz
	*buffer++ = x-0.5f; *buffer++ = y-0.5f; *buffer++ = 0; *buffer++ = 1; *buffer++ = x/(float)screenxl; *buffer++ = y/(float)screenyl; 
	//*buffer++ = vec0.x; *buffer++ = vec0.y; *buffer++ = vec0.z;
	*buffer++ = x+xl-0.5f; *buffer++ = y-0.5f; *buffer++ = 0; *buffer++ = 1; *buffer++ = (x+xl)/(float)screenxl; *buffer++ = y/(float)screenyl;
	//*buffer++ = vec1.x; *buffer++ = vec1.y; *buffer++ = vec1.z;
	*buffer++ = x-0.5f; *buffer++ = y+yl-0.5f; *buffer++ = 0; *buffer++ = 1; *buffer++ = x/(float)screenxl; *buffer++ = (y+yl)/(float)screenyl;
	//*buffer++ = vec2.x; *buffer++ = vec2.y; *buffer++ = vec2.z;
	*buffer++ = x+xl-0.5f; *buffer++ = y+yl-0.5f; *buffer++ = 0; *buffer++ = 1; *buffer++ = (x+xl)/(float)screenxl; *buffer++ = (y+yl)/(float)screenyl;
	//*buffer++ = vec3.x; *buffer++ = vec3.y; *buffer++ = vec3.z;

	m_DynVB->UnlockVB();
	m_DynVB->SetVBStream(sizeof(float)*6, 0);

	m_Device->SetVertexDeclaration(m_VDeclFSQuad);

	RENDERFX(fx, 
		m_Device->DrawPrimitive(PT_TRIANGLESTRIP, 0, 2);
		);
}

void ShadowApp::PromptShaderErrors(void)
{
	FOREACH(el, m_Device->GetShaderManager()->GetShaders(), ShaderProgram)
	{
		if (!el->GetInfo()->IsCompiled())
		{
			XString t = "Shader Error in: ";
			t.appand(el->GetInfo()->GetFilename());
			MessageBox(m_hWndMain, el->GetInfo()->GetErrorMsgs().getbuffer(), t.getbuffer(), 0);
		}
	}
}

void ShadowApp::SetShadowMethod(const SHMETHOD sm)
{ 
	if (m_Techniques[(int)m_Config.Method])
		m_pMenuManager->RemoveMenu(m_Techniques[(int)m_Config.Method]->GetMenu());

	m_Config.Method = sm; 

	if (m_Techniques[(int)m_Config.Method])
		m_pMenuManager->AddMenu(m_Techniques[(int)m_Config.Method]->GetMenu());

	m_pScene[0]->UpdateTechnique();
	m_pScene[1]->UpdateTechnique();	
}

void ShadowApp::SetUseIDBuffer(const bool useid)
{ 
	m_Config.UseIDBuffer = useid; 

	m_SM->SetIDBufferEnable(useid); 

	m_pScene[0]->UpdateTechnique();
	m_pScene[1]->UpdateTechnique();
}

void ShadowApp::SetUsePrimID(const bool primid)
{
	m_Config.UsePrimID = primid; 

	m_pScene[0]->UpdateTechnique();
	m_pScene[1]->UpdateTechnique();
}

void ShadowApp::SetWorldPosType(const DSWORLDPOSTYPE wpt)
{ 
	m_Config.WorldPosType = wpt; 

	m_pScene[0]->UpdateTechnique();
	m_pScene[1]->UpdateTechnique();
}

void ShadowApp::SetSMFiltering(const bool filter)
{ 
	m_Config.SMFiltering = filter; 

	m_pScene[0]->UpdateTechnique();
	m_pScene[1]->UpdateTechnique();
}

void ShadowApp::SetupSSAO(void)
{
	//build sample rays in a sphere with radius 1

	for (int i = 0; i < 32; i++)
	{
		//sample pints inside sphere:
		DXVector3 p(2 * frand() - 1, 2 * frand() - 1, 2 * frand() - 1);
		float l = p.Length();

		if (l <= 1 && l > 0.25f)
		{
			m_SSAOSampleRays[i] = p;
		}
		else
		{
			i--;
		}
		
		//sample points on sphere:
		//float z = 2 * frand() - 1;
		//float t = 2 * D3DX_PI * frand();
		//float w = sqrt(1 - z * z);
		//float x = w * cos(t);
		//float y = w * sin(t);
		//m_SSAOSampleRays[i] = DXVector3(x, y, z);
	}
		
	//build noise normal texture
	//...

	m_SSAONoiseNormal = m_Device->GetTextureManager()->CreateTexture(128, 128, 1, 0, FMT_A8R8G8B8, POOL_MANAGED);

	const LOCKED_RECT* lr = m_SSAONoiseNormal->Lock();

	BYTE* prow = (BYTE*)(lr->pBits);

	for (int y = 0; y < 128; y++)
	{
		DWORD* pdst = (DWORD*)prow;

		for (int x = 0; x < 128; x++)
		{
			DXVector3 v(2 * frand() - 1, 2 * frand() - 1, 2 * frand() - 1);
			v.Normalize();
			v.add(DXVector3(1, 1, 1));
			v.mul(128);

			*pdst++ = ARGB32((BYTE)v.x, (BYTE)v.y, (BYTE)v.z, 0);
		}

		prow += lr->Pitch;
	}

	m_SSAONoiseNormal->Unlock();
}

void ShadowApp::RenderSSAO(void)
{
	if (!m_FXSSAO->IsCompiled())
		return;

	m_DSSSAO->StartRender(0);

	//m_Device->Clear(D3DCLEAR_TARGET, 0, 0, 0);
	
	if (m_Config.WorldPosType == WPT_WORLDPOS)
		m_FXSSAO->SetTexture("g_texWorld", m_DSWorld->GetSurface());
	else
		m_FXSSAO->SetTexture("g_texDepth", m_DSDepth->GetSurface());

	m_FXSSAO->SetTexture("g_texNoiseNormal", m_SSAONoiseNormal);
	
	m_FXSSAO->SetMatrix("g_matInvProj", DXMatrix::InvertMatrix(GetActiveCam().GetProjMatrix()));
	m_FXSSAO->SetMatrix("g_matView", GetActiveCam().GetViewMatrix());
	m_FXSSAO->SetMatrix("g_matProj", GetActiveCam().GetProjMatrix());
	m_FXSSAO->SetFloat("g_Radius", 4);
	m_FXSSAO->SetFloatArray("g_SamplePoints", (float*)m_SSAOSampleRays, sizeof(float)*3*32);

	float rtsize[2] = {m_Device->GetViewPort()->GetWidth(), m_Device->GetViewPort()->GetHeight()};
	m_FXSSAO->SetFloatArray("g_RTSize", rtsize, 2);

	XString tech = "RenderSSAO";
	if (m_Config.WorldPosType == WPT_DEPTH)
		tech.appand("_Depth");
	else if (m_Config.WorldPosType == WPT_LINEARDEPTH)
		tech.appand("_LinearDepth");
	else if (m_Config.WorldPosType == WPT_WORLDPOS)
		tech.appand("_World");

	m_FXSSAO->SetTechnique(tech);

	RenderFSQuad(m_FXSSAO);
	
	m_DSSSAO->EndRender();
}

void ShadowApp::ClearFloat(const DXColor& color)
{
	m_FXMat->SetVector("g_Color", *((const DXVector4*)&color));

	m_FXMat->SetTechnique("ClearColor"); 

	RenderFSQuad(m_FXMat);
}