/***********************************************************************\
* --------------------------------------------------------------------- *
*							Author's note								*
*					  Fabrice Fournet "Shingo-Y"						*
*						 shingo_yab@msn.com								*
*					http://fabrice-fournet.sup.fr						*
*																		*
*   For MSN contact acceptance, send me an e-mail before with object:	*
*   @ "Demo name" or anything sufficient to distinguish you from a bot	*
*																		*
* ---------------------------------------------------------------------	*
*																		*
* These files are a part of the work done by Fabrice Fournet "Shingo-Y"	*
* You are free to use the code in any way you like, modified (or not)	*
* or copy&pasted into your own work. However, I expect you to respect	*
* these points:															*
* @ If you use this project and its contents unmodified, or use a major	*
*   part of this project, please credit the author and leave this note.	*
* @ For use in anything commercial, please request my approval.			*
* @ Share your work and ideas too, as much as you can.					*
\***********************************************************************/


// Standard includes
#include "dxstdafx.h"
#include "resource.h"

// 3D Objects
#include "XObject.h"
#include "SkyBox.h"

// Effects
#include "CelShading.h"
#include "SimpleLighting.h"
#include "ZPrePass.h"

// Managers
#include "PostProcManager.h"
#include "TransformMatrixesManager.h"
#include "PostProcFXFilesManager.h"

// Effect handlers
#include "PostProcFXChain.h"
#include "PPEffectsCommon.h"
#include "ScaledPPEffect.h"
#include "EffectParam.h"

#pragma once // Only once dammit!


//--------------------------------------------------------------------------------------
// UI control IDs
//--------------------------------------------------------------------------------------
// The classic "Full screen" and "Change device"
#define IDC_TOGGLEFULLSCREEN			1
#define IDC_CHANGEDEVICE				2

// The always visible controls
#define IDC_AVAILABLELIST				3
#define IDC_ACTIVELIST					4
#define IDC_AVAILABLELISTLABEL			5
#define IDC_ACTIVELISTLABEL				6
#define IDC_MOVEUP						7
#define IDC_MOVEDOWN					8
#define IDC_CLEAR						9

// The per-effect (only appear when one is selected) controls
#define IDC_XSCALERSTATIC				10
#define IDC_YSCALERSTATIC				11
#define IDC_XSCALERSLIDER				12
#define IDC_YSCALERSLIDER				13
#define IDC_PARAM0NAME					14
#define IDC_PARAM0						15
#define IDC_PARAM1NAME					16
#define IDC_PARAM1						17

// RealTime Shaders selection
#define IDC_SELECTRTSHADER				18

// Preset buttons
#define IDC_PRESETLABEL					19
#define IDC_PREBLUR						20	// downfilter4x(0.25) + 2*complete gaussian blur + copyresult(4.0)
#define IDC_PREBLOOM					21	// 2*downfilter4x(0.25) + brightpass + 2*complete bloom + copyresult(4.0) + addresult(4.0)
#define IDC_PREBLOOM2					22	// dilation(0.25) + downfilter4x(0.25) + complete bloom + copyresult(4.0) + addresult(4.0) = faster bloom (but would need a brightpass adjustment to be the same as PREBLOOM)
#define IDC_PREDOF						23	// downfilter4x(0.25) + 2*complete gaussian blur + DOFCombine(4.0)
#define IDC_PREEDGE						24	// normal edge detection + downfilter4x(0.25) + complete bloom + add result(4.0)
#define IDC_PRECELSHADING				25	// switch to cel-shading realtime shader + normal edge detection + substract result


//--------------------------------------------------------------------------------------
// RealTime shaders IDs --- !!! NULL (0) is forbidden !!!
//--------------------------------------------------------------------------------------
#define IDS_SIMPLELIGHTING				1
#define IDS_CELSHADING					2


//--------------------------------------------------------------------------------------
// MACROS
//--------------------------------------------------------------------------------------
#define IN_FLOAT_CHARSET(c) ((c)==L'-' || (c)==L'.' || ((c)>=L'0' && (c)<=L'9'))	// True if c is a numerical character set


//--------------------------------------------------------------------------------------
// Global variables
//--------------------------------------------------------------------------------------
ID3DXFont * g_pFont = NULL;							// Font for drawing text
ID3DXSprite * g_pTextSprite = NULL;					// Sprite for batching draw text calls
CDXUTDialogResourceManager g_DialogResourceManager;	// Manager for shared resources of dialogs
CD3DSettingsDlg g_SettingsDlg;						// Device settings dialog
CDXUTDialog g_HUD;									// Dialog for standard controls
CDXUTDialog g_SampleUI;								// Dialog for sample specific controls
bool g_bShowHelp = true;							// Show/hide help and statistics

CModelViewerCamera g_Camera;						// A model viewing camera
CDXUTDirectionWidget g_LightControl;				// A light with its representation

#define RT_NUMBERS 3											// The number of MRT to create
PostProcFXChain * g_pPostProcFXChain = NULL;					// The Active PP FX Chain
PostProcManager * g_pPPManager = NULL;							// The post-processing manager
PostProcFXFilesManager * g_pFXFilesManager = NULL;				// PostProcManager use a FX file manager that compiles and lists the availables FX
TransformMatrixesManager * g_pTransformMatrixManager = NULL;	// The matrix manager

SimpleLighting * g_pSimpleLighting = NULL;			// The lighthing effect
CelShading * g_pCelShading = NULL;					// The cel-shading effect
ZPrePass * g_pZPrePass = NULL;
RTEffectsCommon * g_pCurrentEffect = NULL;			// A generic effect pointer on the current effect

SkyBox * g_pSkyBox = NULL;							// The scene skybox

XObject * g_pXObject = NULL;						// The X Object with mesh data, textures, materials and shaders
D3DXVECTOR3 g_vObjectCenter;						// Center of bounding sphere of object
FLOAT g_fObjectRadius;								// Radius of bounding sphere of object


//--------------------------------------------------------------------------------------
// Forward Declarations
//--------------------------------------------------------------------------------------
// Application init & clean
void InitApp();		// Init application data
void CleanApp();	// Clean application data

// Renderers
HRESULT RenderGUI(LPDIRECT3DDEVICE9 pd3dDevice, float fElapsedTime);		// Draw the GUI
HRESULT RenderObjects(LPDIRECT3DDEVICE9 pd3dDevice, bool bZPrePass=false);	// Draw the scene objects
void RenderText();															// To render our text data

void InsertEffect(DXUTListBoxItem * pItem, const UINT nAvailableEffectIndex
				, const float fScaleX=1.0f, const float fScaleY=1.0f);				// Insert a new postprocess effect
void InsertEffectByFilename(LPCWSTR pFilename, const UINT nAvailableEffectIndex
							, const float fScaleX=1.0f, const float fScaleY=1.0f);	// Insert a new postprocess effect from it name
void RemoveEffect(const int nIndex);												// Remove a postprocess effect
void ClearActiveEffectsList();														// Clear the active effects list
void MoveActiveEffect(const bool bMoveUp);											// Move an effect up or down

void InitGUI();																		// Create the GUI controls		
void ActivateNeededControls(ScaledPPEffect * pEffect);								// Activates the slider, edit boxes and other controls to modify the effect
void DesactivateModificationControls();												// Desactivates the all controls to modify effects
void ParseFloatList(const WCHAR *pwszText, FLOAT * pFloatArray);					// extract up to 4 float numbers from a string

void SelectRealTimeShaderFromData(void * pData);									// Select a Realtime shader from pData

void CALLBACK KeyboardProc( UINT nChar, bool bKeyDown, bool bAltDown, void* pUserContext );			// Manage keyboard events
void CALLBACK OnGUIEvent(UINT nEvent, int nControlID, CDXUTControl * pControl, void* pUserContext); // Manage GUI events


//--------------------------------------------------------------------------------------
// Rejects any devices that aren't acceptable by returning false
//--------------------------------------------------------------------------------------
bool CALLBACK IsDeviceAcceptable(D3DCAPS9* pCaps, D3DFORMAT AdapterFormat, D3DFORMAT BackBufferFormat, bool bWindowed, void* pUserContext)
{
	IDirect3D9* pD3D = DXUTGetD3DObject(); 

	// Skip backbuffer formats that don't support alpha blending
	if( FAILED(pD3D->CheckDeviceFormat(pCaps->AdapterOrdinal, pCaps->DeviceType, AdapterFormat, D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING, D3DRTYPE_TEXTURE, BackBufferFormat)) )
		return false;

	// Also need post pixel processing support
	if( FAILED(pD3D->CheckDeviceFormat(pCaps->AdapterOrdinal, pCaps->DeviceType, AdapterFormat, D3DUSAGE_RENDERTARGET | D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING, D3DRTYPE_SURFACE, BackBufferFormat)) )
		return false;

    // We must have SM2.0 support for this sample to run. We don't need to worry about the VS version
    if(pCaps->PixelShaderVersion<D3DPS_VERSION(2,0))
        return false;

	// Check 32 bit integer format support
	if(FAILED(pD3D->CheckDeviceFormat(pCaps->AdapterOrdinal, pCaps->DeviceType, AdapterFormat, D3DUSAGE_RENDERTARGET, D3DRTYPE_CUBETEXTURE, D3DFMT_A8R8G8B8)))
		return false;

	return true;
}


//--------------------------------------------------------------------------------------
// Before a device is created, modify the device settings as needed
//--------------------------------------------------------------------------------------
bool CALLBACK ModifyDeviceSettings(DXUTDeviceSettings* pDeviceSettings, const D3DCAPS9* pCaps, void* pUserContext)
{
	// If device doesn't support HW T&L or doesn't support 1.1 vertex shaders in HW 
	// then switch to SWVP.
	if( (pCaps->DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT)==0
		|| pCaps->VertexShaderVersion < D3DVS_VERSION(1,1) )
	{
		pDeviceSettings->BehaviorFlags = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
	}

	// If the hardware cannot do vertex blending, use software vertex processing.
	if( pCaps->MaxVertexBlendMatrices < 2 )
		pDeviceSettings->BehaviorFlags = D3DCREATE_SOFTWARE_VERTEXPROCESSING;

	// This application is designed to work on a pure device (not using Get* functions)
    if ((pCaps->DevCaps & D3DDEVCAPS_PUREDEVICE) != 0 && (pDeviceSettings->BehaviorFlags & D3DCREATE_HARDWARE_VERTEXPROCESSING) != 0)
		pDeviceSettings->BehaviorFlags |= D3DCREATE_PUREDEVICE;

	// Debugging vertex shaders requires either REF or software vertex processing 
	// and debugging pixel shaders requires REF.  
	#ifdef DEBUG_VS
		if( pDeviceSettings->DeviceType != D3DDEVTYPE_REF )
		{
			pDeviceSettings->BehaviorFlags &= ~D3DCREATE_HARDWARE_VERTEXPROCESSING;
			pDeviceSettings->BehaviorFlags &= ~D3DCREATE_PUREDEVICE;
			pDeviceSettings->BehaviorFlags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;
		}
	#endif

	#ifdef DEBUG_PS
		pDeviceSettings->DeviceType = D3DDEVTYPE_REF;
	#endif

	// For the first device created if its a REF device, optionally display a warning dialog box
	static bool s_bFirstTime = true;
	if( s_bFirstTime )
	{
		s_bFirstTime = false;
		if( pDeviceSettings->DeviceType == D3DDEVTYPE_REF )
			DXUTDisplaySwitchingToREFWarning();
	}

    return true;
}


//--------------------------------------------------------------------------------------
// Create any D3DPOOL_MANAGED resources here 
//--------------------------------------------------------------------------------------
HRESULT CALLBACK OnCreateDevice(IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc, void* pUserContext)
{
	HRESULT hr;

	//------------------------- GETTING THE MANAGERS FIRSTS INSTANCES -------------------------//
	// Precompiling every post process effects and list them
	g_pFXFilesManager = PostProcFXFilesManager::GetInstance();
	g_pFXFilesManager->ListAvailablePostProcEffects(RT_NUMBERS);
	
	// Instanciate the post-process manager
	g_pPPManager = PostProcManager::GetInstance();

	// And the transformation matrix manager
	g_pTransformMatrixManager = TransformMatrixesManager::GetInstance();


	//--------------------------------- REAL-TIME EFFECTS -----------------------------------//
	g_pSimpleLighting = new SimpleLighting();		// A simple lighting effect
	g_pCelShading = new CelShading();				// A cel-shading effect
	g_pZPrePass = new ZPrePass();					// An effect to do a Z prepass


	//---------------------------------- SCENE OBJECTS -----------------------------------//
	// The skybox
	g_pSkyBox = new SkyBox();

	// The mesh
	g_pXObject = new XObject(L"./Models/Dwarf/Dwarf.x");
	g_pXObject->ComputeBoundingSphere(&g_vObjectCenter, &g_fObjectRadius);

	// Setup the camera's view parameters
    g_Camera.SetRadius( g_fObjectRadius*3.0f, g_fObjectRadius*0.5f, g_fObjectRadius*500.0f );

	// Fiat Lux!
	CDXUTDirectionWidget::StaticOnCreateDevice(pd3dDevice);
	g_LightControl.SetRadius(g_fObjectRadius);

	// Building the mesh world center matrix
	D3DXMatrixTranslation(&g_pTransformMatrixManager->m_matMeshWorldCenter, -g_vObjectCenter.x, -g_vObjectCenter.y, -g_vObjectCenter.z);


	//---------------------------------------- GUI ------------------------------------------//
	V_RETURN(g_DialogResourceManager.OnCreateDevice(pd3dDevice));
    V_RETURN(g_SettingsDlg.OnCreateDevice(pd3dDevice));

    // Initialize the font
    V_RETURN(D3DXCreateFont( pd3dDevice, 15, 0, FW_BOLD, 0, FALSE, DEFAULT_CHARSET
							,OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE
							,L"Arial", &g_pFont) );

	// Display the available effects list
	if(g_pFXFilesManager)
	{
		// Filling the list
		CDXUTListBox * pPPEffectListBox = g_SampleUI.GetListBox(IDC_AVAILABLELIST);
		if(pPPEffectListBox)
		{
			// Cleaning the list
			pPPEffectListBox->RemoveAllItems();

			// Populate ListBox items
			g_pFXFilesManager->FillListBox(pPPEffectListBox);
		}

		// Now check if the active list is filled with something...
		CDXUTListBox * pActiveListBox = g_SampleUI.GetListBox(IDC_ACTIVELIST);
		if(pActiveListBox)
		{
			// Does it contains something more than the special insertion space?
			int nNbActiveEffects = pActiveListBox->GetSize()-1;
			if(nNbActiveEffects>0)
			{
				// Yes!
				for(int i=0; i<nNbActiveEffects; ++i)
				{
					// Rebind the chain effects to the reloaded effects
					ScaledPPEffect * pScaledEffect = g_pPostProcFXChain->GetEffect(i);							// Retrieve the chain effect
					UINT nEffectID = *((UINT*)(pActiveListBox->GetItem(i)->pData));								// Retrieve the effectID
					pScaledEffect->SetEffect((PPEffectsCommon*)(pPPEffectListBox->GetItem(nEffectID)->pData));	// Rebind the effect
				}
			}
		}
	}

	// Assign the selected shader in combobox as current shader
	CDXUTComboBox * pShadersComboBox = g_SampleUI.GetComboBox(IDC_SELECTRTSHADER);
	void * pItemData = pShadersComboBox->GetSelectedData();
	SelectRealTimeShaderFromData(pItemData);

    return S_OK;
}


//--------------------------------------------------------------------------------------
// Create any D3DPOOL_DEFAULT resources here
//--------------------------------------------------------------------------------------
HRESULT CALLBACK OnResetDevice(IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc, void* pUserContext)
{
	HRESULT hr;
	
	// Reset the light
	V_RETURN(g_LightControl.OnResetDevice(pBackBufferSurfaceDesc));

	// Reset the object effect
	if(g_pSimpleLighting) V_RETURN(g_pSimpleLighting->OnResetDevice());
	if(g_pCelShading) V_RETURN(g_pCelShading->OnResetDevice());
	if(g_pZPrePass) V_RETURN(g_pZPrePass->OnResetDevice());

	// Reset the objects
	if(g_pSkyBox)
		V_RETURN(g_pSkyBox->OnResetDevice());

	// Reset all the available post-process effects
	if(g_pFXFilesManager)
		g_pFXFilesManager->OnResetDevice(pBackBufferSurfaceDesc->Width, pBackBufferSurfaceDesc->Height);

	// Reset the post process manager
	if(g_pPPManager)
	{
		// Then we init all the post process data
		g_pPPManager->Init(pBackBufferSurfaceDesc->Width, pBackBufferSurfaceDesc->Height, RT_NUMBERS);

		// Then explicitly calling its Reset() method
		g_pPPManager->OnResetDevice(pBackBufferSurfaceDesc->Width, pBackBufferSurfaceDesc->Height);
	}
	
	// Reseting the dialogs and controls
	V_RETURN(g_DialogResourceManager.OnResetDevice());
	V_RETURN(g_SettingsDlg.OnResetDevice());
	if(g_pFont) V_RETURN(g_pFont->OnResetDevice());

	// Setup the camera's projection parameters
    float fAspectRatio = pBackBufferSurfaceDesc->Width / (FLOAT)pBackBufferSurfaceDesc->Height;
    g_Camera.SetProjParams( D3DX_PI/4, fAspectRatio, 0.1f, 1000.0f );
    g_Camera.SetWindow( pBackBufferSurfaceDesc->Width, pBackBufferSurfaceDesc->Height );
    g_Camera.SetButtonMasks( MOUSE_LEFT_BUTTON, MOUSE_WHEEL, MOUSE_MIDDLE_BUTTON );

	// Create a sprite to help batch calls when drawing many lines of text
    V_RETURN(D3DXCreateSprite(pd3dDevice, &g_pTextSprite));

	// Reset de location of the HUD
	g_HUD.SetLocation(0, 100);
    g_HUD.SetSize(170, 170);

	// And of the sample GUI
    g_SampleUI.SetLocation(pBackBufferSurfaceDesc->Width-225, 5);
    g_SampleUI.SetSize(220, 510);

    return S_OK;
}


//--------------------------------------------------------------------------------------
// Handle updates to the scene
//--------------------------------------------------------------------------------------
void CALLBACK OnFrameMove(IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext)
{
	// Update the camera's position based on user input 
	g_Camera.FrameMove(fElapsedTime);
}


//--------------------------------------------------------------------------------------
// Render the scene 
//--------------------------------------------------------------------------------------
void CALLBACK OnFrameRender(IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext)
{
	HRESULT hr;

	// Clear the render target and the zbuffer 
	V(pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_ARGB(0, 200, 200, 200), 1.0f, 0));

	// If the settings dialog is being shown, then
	// render it instead of rendering the app's scene
	if(g_SettingsDlg.IsActive())
	{
		V(g_SettingsDlg.OnRender(fElapsedTime));
		return;
	}

	// Render the scene
	if(SUCCEEDED(pd3dDevice->BeginScene()))
	{
		// Update the transformation matrixes
		g_pTransformMatrixManager->UpdateMatrixes(&g_Camera);

		//----------------------------- Z-PREPASS -----------------------------//

		// TODO : render objects with only vertices
		// TODO : find the Z-Prepass special GPU path trigger (how to disable color output?)
		// IDEA : disable color output (if possible?) / ZEnable ON / Alpha OFF

		//----------------------------- CLASSIC RENDER -----------------------------//

		// If some postprocess effects are in the chain, init the render targets
		if(g_pPostProcFXChain->GetSize())
			V(g_pPPManager->SetupInitialRenderTargets());		// Setup RTs for postprocessing and clear the RTs (by default)

		// Draw the objects
		V(RenderObjects(pd3dDevice));

		// Draw the skybox
		if(g_pSkyBox){ V(g_pSkyBox->RenderSkyBox()); }

		// Rendering end
		V(pd3dDevice->EndScene());

		// Then we can perform post-processing
		V(g_pPPManager->PerformPostProcess(g_pPostProcFXChain, (float)fTime));

		// Finished rendering we backup the current WVP matrix for the next rendering (a must have for velocity buffers)
		g_pTransformMatrixManager->BackupCurrentMatrixes();
	}

	// finally, render the GUI elements
	V(RenderGUI(pd3dDevice, fElapsedTime));
}


//--------------------------------------------------------------------------------------
// Render the scene objects
//--------------------------------------------------------------------------------------
HRESULT RenderObjects(LPDIRECT3DDEVICE9 pd3dDevice, bool bZPrePass)
{
	//--------------------------------------------------------------------------------------
	// Render the objects
	//--------------------------------------------------------------------------------------
	// Rendering the objects
	if(g_pCurrentEffect)
	{
		// Setup generic effect data
		g_pCurrentEffect->SetupEffectLightAndObs(&g_LightControl, g_Camera.GetEyePt());		// Light and eye vectors
		g_pCurrentEffect->SetupCurrentEffectParameters();									// Updating the effect parameters
		g_pCurrentEffect->SetupEffectMatrixes();											// Effect transformation matrixes setup

		// TODO : a render manager which handles multiple objects list with Z/material properties/2dspace occupation/effects ordering...
		// Rendering the model
		if(g_pXObject)
		{
			pd3dDevice->SetVertexDeclaration(g_pXObject->getMeshVertDecl());	// Setup the device vertex declaration
			return g_pXObject->RenderMesh(g_pCurrentEffect);					// Render the mesh
		}
	}
	return S_OK;
}


//--------------------------------------------------------------------------------------
// Render the GUI elements
//--------------------------------------------------------------------------------------
HRESULT RenderGUI(LPDIRECT3DDEVICE9 pd3dDevice, float fElapsedTime)
{
	HRESULT hr;

	//--------------------------------------------------------------------------------------
	// Render the objects
	//--------------------------------------------------------------------------------------
	if(SUCCEEDED(pd3dDevice->BeginScene()))
	{
		// Rendering the light arrow
		D3DXCOLOR arrowColor = D3DXCOLOR(1.0, 1.0, 0.0, 1.0);
		V(g_LightControl.OnRender(arrowColor, &(g_pTransformMatrixManager->m_matView), &(g_pTransformMatrixManager->m_matProj), g_Camera.GetEyePt()) );

		// Rendering the UIs
		RenderText();						// Draw the statistic text and 
		g_HUD.OnRender(fElapsedTime);		// Draw the HUD

		g_SampleUI.OnRender(fElapsedTime);	// Draw the sample UI

		// Rendering end
		return pd3dDevice->EndScene();	
	}
	return S_OK;
}

//--------------------------------------------------------------------------------------
// Render the help and statistics text. This function uses the ID3DXFont interface for 
// efficient text rendering.
//--------------------------------------------------------------------------------------
void RenderText()
{
	// The helper object simply helps keep track of text position, and color
	// and then it calls pFont->DrawText( m_pSprite, strMsg, -1, &rc, DT_NOCLIP, m_clr );
	// If NULL is passed in as the sprite object, then it will work however the 
	// pFont->DrawText() will not be batched together.  Batching calls will improves performance.
	const D3DSURFACE_DESC* pd3dsdBackBuffer = DXUTGetBackBufferSurfaceDesc();
	CDXUTTextHelper txtHelper( g_pFont, g_pTextSprite, 15 );

	// Output statistics
	txtHelper.Begin();
	txtHelper.SetInsertionPos( 5, 5 );
	txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 1.0f, 0.0f, 1.0f ) );
	txtHelper.DrawTextLine(DXUTGetFrameStats(true)); // Activate FPS counter
	txtHelper.DrawTextLine(DXUTGetDeviceStats());

	// Draw help
	if(g_bShowHelp)
	{
		txtHelper.SetInsertionPos( 10, pd3dsdBackBuffer->Height-15 );
		txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 0.75f, 0.0f, 1.0f ) );
		txtHelper.DrawTextLine( L"Controls (F1 to hide):" );

		txtHelper.SetInsertionPos( 40, pd3dsdBackBuffer->Height-30 );
		txtHelper.DrawTextLine(L"Quit: ESC");
		
		txtHelper.End();
	}
}


//--------------------------------------------------------------------------------------
// Handle messages to the application 
//--------------------------------------------------------------------------------------
LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, 
                          bool* pbNoFurtherProcessing, void* pUserContext )
{
	// Always allow dialog resource manager calls to handle global messages
    // so GUI state is updated correctly
    *pbNoFurtherProcessing = g_DialogResourceManager.MsgProc( hWnd, uMsg, wParam, lParam );
    if( *pbNoFurtherProcessing )
        return 0;

    // Give the dialogs a chance to handle the message first
    *pbNoFurtherProcessing = g_HUD.MsgProc( hWnd, uMsg, wParam, lParam );		// the HUD
    if( *pbNoFurtherProcessing )
        return 0;
	
	// Give the sample dialog a chance to handle the message first
	*pbNoFurtherProcessing = g_SampleUI.MsgProc( hWnd, uMsg, wParam, lParam );	// The sample UI
    if( *pbNoFurtherProcessing )
        return 0;

	// Msg for the device settings
    if( g_SettingsDlg.IsActive() )
    {
        g_SettingsDlg.MsgProc( hWnd, uMsg, wParam, lParam );
        return 0;
    }

	// Handle the mesh orbital light messages
	g_LightControl.HandleMessages(hWnd,uMsg,wParam,lParam);

	// Pass all remaining windows messages to camera so it can respond to user input
    g_Camera.HandleMessages( hWnd, uMsg, wParam, lParam );

    return 0;
}


//--------------------------------------------------------------------------------------
// As a convenience, DXUT inspects the incoming windows messages for
// keystroke messages and decodes the message parameters to pass relevant keyboard
// messages to the application.  The framework does not remove the underlying keystroke 
// messages, which are still passed to the application's MsgProc callback.
//--------------------------------------------------------------------------------------
void CALLBACK KeyboardProc( UINT nChar, bool bKeyDown, bool bAltDown, void* pUserContext )
{
    if( bKeyDown )
    {
        switch( nChar )
        {
            case VK_F1: g_bShowHelp = !g_bShowHelp; break;
        }
    }
}


//--------------------------------------------------------------------------------------
// Handles the GUI events
//--------------------------------------------------------------------------------------
void CALLBACK OnGUIEvent( UINT nEvent, int nControlID, CDXUTControl* pControl, void* pUserContext )
{
	switch(nControlID)
	{
		// Device Setting
		case IDC_TOGGLEFULLSCREEN: DXUTToggleFullScreen(); break;
		case IDC_CHANGEDEVICE:
		{
			// Display the settings changes dialog
			g_SettingsDlg.SetActive( !g_SettingsDlg.IsActive() );

			break;
		}

		// Available effects list
		case IDC_AVAILABLELIST:
		{
			switch(nEvent)
			{
				case EVENT_LISTBOX_ITEM_DBLCLK:
				{
					DXUTListBoxItem *pItem = ((CDXUTListBox*)pControl)->GetSelectedItem();
					if(pItem)
					{
						// Inserts the selected effect in available list to the active list
						InsertEffect(pItem, ((CDXUTListBox*)pControl)->GetSelectedIndex());
					}
					break;
				}
			}

			break;
		}

		// Active effects list
		case IDC_ACTIVELIST:
		{
			switch(nEvent)
			{
				// Simple clic = SELECTION
				case EVENT_LISTBOX_SELECTION:
				{
					// Retrieve the index of the selected element
					int nSelectedIndex = ((CDXUTListBox*)pControl)->GetSelectedIndex();

					// If its the special blank element, we disable every modification controls
					if(nSelectedIndex == ((CDXUTListBox*)pControl)->GetSize()-1)
					{
						DesactivateModificationControls();						
						break;
					}

					// Else we retrieve the parameters and setup the modification controls
					ScaledPPEffect * pScaledEffect = g_pPostProcFXChain->GetEffect(nSelectedIndex);
					ActivateNeededControls(pScaledEffect);

					break;
				}

				// Double clic = remove the effect
				case EVENT_LISTBOX_ITEM_DBLCLK:
				{
					// We retrieve the index of the selected item
					int nSelected = ((CDXUTListBox*)pControl)->GetSelectedIndex();
					RemoveEffect(nSelected);

					break;
				}
			}

			break;
		}

		// -------------------------- Effect and postprocess list modifications controls -------------------------//
		// The X scaling slider
		case IDC_XSCALERSLIDER:
		{
			// Retrieving the currently selected effect
			CDXUTListBox * pActiveListBox = g_SampleUI.GetListBox(IDC_ACTIVELIST);	// Retrieve the listbox
			int nSelectedIndex = pActiveListBox->GetSelectedIndex();				// Retrieve its selected position
			if(nSelectedIndex == pActiveListBox->GetSize()-1) break;				// Break if the insertion space is selected

			// Retrieving a pointer on the effect postprocess FX chain at nSelectedIndex
			ScaledPPEffect* pScaledEffect = g_pPostProcFXChain->GetEffect(nSelectedIndex);
			if(pScaledEffect)
			{
				// Computing the new scaling value
				float fXScaler = powf( 2.0f, (float)(((CDXUTSlider*)pControl)->GetValue()) );

				// And assiging it to the element
				pScaledEffect->SetScalerX(fXScaler);
			}

			break;
		}

		// The Y scaling slider
		case IDC_YSCALERSLIDER:
		{
			// Retrieving the currently selected effect
			CDXUTListBox * pActiveListBox = g_SampleUI.GetListBox(IDC_ACTIVELIST);	// Retrieve the listbox
			int nSelectedIndex = pActiveListBox->GetSelectedIndex();				// Retrieve its selected position
			if(nSelectedIndex == pActiveListBox->GetSize()-1) break;				// Break if the insertion space is selected

			// Retrieving a pointer on the effect postprocess FX chain at nSelectedIndex
			ScaledPPEffect* pScaledEffect = g_pPostProcFXChain->GetEffect(nSelectedIndex);
			if(pScaledEffect)
			{
				// Computing the new scaling value
				float fYScaler = powf( (float)2, (float)(((CDXUTSlider*)pControl)->GetValue()) );

				// And assiging it to the element
				pScaledEffect->SetScalerY(fYScaler);
			}

			break;
		}

		// We modify the values in the edit boxes
		case IDC_PARAM0:
        case IDC_PARAM1:
        {
			// If we detect a change in the edit box content
            if(nEvent == EVENT_EDITBOX_CHANGE)
            {
				// We retrieve the index of the parameter we're modifying
                int nParamIndex;
                switch(nControlID)
                {
                    case IDC_PARAM0: nParamIndex = 0; break;
                    case IDC_PARAM1: nParamIndex = 1; break;
                    default: return;
                }

				// We retrieve the effect index from the active list
				int nSelectedIndex = g_SampleUI.GetListBox(IDC_ACTIVELIST)->GetSelectedIndex();
                ScaledPPEffect * pScaledEffect = NULL;
				if(nSelectedIndex<0) return;

				// Then retrieve the ScaledPPEffect instance from the post processing list
				pScaledEffect = g_pPostProcFXChain->GetEffect(nSelectedIndex);
				
				// Checking pScaledEffect validity for the fun
				if(!pScaledEffect) return;

				// Let's do the same with the effect pointer
				PPEffectsCommon * pEffect = pScaledEffect->GetEffect();
				if(!pEffect) return;

				// And the parameter :P
				EffectParam * pParam = pEffect->getParameter(nParamIndex);
				if(!pParam) return;
				
				// Now we can retrieve the float list from the string in the edit box
				FLOAT aFloatList[4];
				ZeroMemory(aFloatList, 4*sizeof(FLOAT));
				ParseFloatList( ((CDXUTEditBox *)pControl)->GetText(), aFloatList );

				// We parsed the values. Now save them in the scaled effect own parameter list
				pScaledEffect->SetParamValues(aFloatList, nParamIndex, pParam->GetParamSize());
            }

            break;
		}

		// We pressed the move up button
		case IDC_MOVEUP:
		{
			// We move the effect UP
			MoveActiveEffect(true);

			break;
		}

		// We pressed the move down button
		case IDC_MOVEDOWN:
		{
			// We move the effect UP
			MoveActiveEffect(false);

			break;
		}

		// Clear the active list
		case IDC_CLEAR:
        {
			ClearActiveEffectsList();

            break;
        }

		// ---------------------------------- Real-Time Shader Selection Control ---------------------------------//
		case IDC_SELECTRTSHADER:
		{
			void * pItemData = ((CDXUTComboBox*)pControl)->GetSelectedData();
			SelectRealTimeShaderFromData(pItemData);			
			
			break;
		}

		// ------------------------------- Post-Process Effect Preselection Controls -----------------------------//
		case IDC_PREBLUR:
		{
			// We clear the current list
			ClearActiveEffectsList();
			
			// And insert the post process effects
			int i=0;
			InsertEffectByFilename(L"ColorDownFilter4X.fx"	, i++, 0.25f, 0.25f);
			InsertEffectByFilename(L"ColorGaussianBlurH.fx"	, i++);
			InsertEffectByFilename(L"ColorGaussianBlurV.fx"	, i++);
			InsertEffectByFilename(L"ColorGaussianBlurH.fx"	, i++);
			InsertEffectByFilename(L"ColorGaussianBlurV.fx"	, i++);
			InsertEffectByFilename(L"ColorCopyResult.fx"	, i++, 4.0f, 4.0f);

			// And finally we select the insertion item on IDC_ACTIVELIST
			CDXUTListBox * pActiveListBox = g_SampleUI.GetListBox(IDC_ACTIVELIST);	// Retrieve the listbox
			if(pActiveListBox) pActiveListBox->SelectItem(i);

			break;
		}

		case IDC_PREBLOOM:
		{
			// We clear the current list
			ClearActiveEffectsList();
			
			// And insert the post process effects
			int i=0;
			InsertEffectByFilename(L"ColorDownFilter4X.fx"	, i++, 0.25f, 0.25f);
			InsertEffectByFilename(L"ColorDownFilter4X.fx"	, i++, 0.25f, 0.25f);
			InsertEffectByFilename(L"ColorBrightPass.fx"	, i++);
			InsertEffectByFilename(L"ColorBloomH.fx"		, i++);
			InsertEffectByFilename(L"ColorBloomV.fx"		, i++);
			InsertEffectByFilename(L"ColorBloomH.fx"		, i++);
			InsertEffectByFilename(L"ColorBloomV.fx"		, i++);
			InsertEffectByFilename(L"ColorCopyResult.fx"	, i++, 4.0f, 4.0f);
			InsertEffectByFilename(L"ColorAddResult.fx"		, i++, 4.0f, 4.0f);

			// And finally we select the insertion item on IDC_ACTIVELIST
			CDXUTListBox * pActiveListBox = g_SampleUI.GetListBox(IDC_ACTIVELIST);	// Retrieve the listbox
			if(pActiveListBox) pActiveListBox->SelectItem(i);

			break;
		}

		case IDC_PREBLOOM2:
		{
			// We clear the current list
			ClearActiveEffectsList();
			
			// And insert the post process effects
			int i=0;
			InsertEffectByFilename(L"ColorDilation.fx"		, i++, 0.25f, 0.25f);
			InsertEffectByFilename(L"ColorDownFilter4X.fx"	, i++, 0.25f, 0.25f);
			InsertEffectByFilename(L"ColorBrightPass.fx"	, i++);
			InsertEffectByFilename(L"ColorBloomH.fx"		, i++);
			InsertEffectByFilename(L"ColorBloomV.fx"		, i++);
			InsertEffectByFilename(L"ColorCopyResult.fx"	, i++, 4.0f, 4.0f);
			InsertEffectByFilename(L"ColorAddResult.fx"		, i++, 4.0f, 4.0f);

			// And finally we select the insertion item on IDC_ACTIVELIST
			CDXUTListBox * pActiveListBox = g_SampleUI.GetListBox(IDC_ACTIVELIST);	// Retrieve the listbox
			if(pActiveListBox) pActiveListBox->SelectItem(i);

			break;
		}		

		case IDC_PREDOF:
		{
			// We clear the current list
			ClearActiveEffectsList();
			
			// And insert the post process effects
			int i=0;
			InsertEffectByFilename(L"ColorDownFilter4X.fx"	, i++, 0.25f, 0.25f);
			InsertEffectByFilename(L"ColorGaussianBlurH.fx"	, i++);
			InsertEffectByFilename(L"ColorGaussianBlurV.fx"	, i++);
			InsertEffectByFilename(L"ColorGaussianBlurH.fx"	, i++);
			InsertEffectByFilename(L"ColorGaussianBlurV.fx"	, i++);
			InsertEffectByFilename(L"DOFCombine.fx"			, i++, 4.0f, 4.0f);

			// And finally we select the insertion item on IDC_ACTIVELIST
			CDXUTListBox * pActiveListBox = g_SampleUI.GetListBox(IDC_ACTIVELIST);	// Retrieve the listbox
			if(pActiveListBox) pActiveListBox->SelectItem(i);

			break;
		}

		case IDC_PREEDGE:
		{
			// We clear the current list
			ClearActiveEffectsList();
			
			// And insert the post process effects
			int i=0;
			InsertEffectByFilename(L"NormalEdgeDetect.fx"	, i++);
			InsertEffectByFilename(L"ColorDownFilter4X.fx"	, i++, 0.25f, 0.25f);
			InsertEffectByFilename(L"ColorBloomH.fx"		, i++);
			InsertEffectByFilename(L"ColorBloomV.fx"		, i++);
			InsertEffectByFilename(L"ColorAddResult.fx"		, i++, 4.0f, 4.0f);

			// And finally we select the insertion item on IDC_ACTIVELIST
			CDXUTListBox * pActiveListBox = g_SampleUI.GetListBox(IDC_ACTIVELIST);	// Retrieve the listbox
			if(pActiveListBox) pActiveListBox->SelectItem(i);

			break;
		}

		case IDC_PRECELSHADING:
		{
			// We switch to the celshading shader
 			CDXUTComboBox * pShaderComboBox = g_SampleUI.GetComboBox(IDC_SELECTRTSHADER);
			if(!pShaderComboBox) return;
			pShaderComboBox->SetSelectedByData((LPVOID*)IDS_CELSHADING);
			SelectRealTimeShaderFromData((LPVOID*)IDS_CELSHADING);

			// We clear the current list
			ClearActiveEffectsList();
			
			// And insert the post process effects
			int i=0;
			InsertEffectByFilename(L"NormalEdgeDetect.fx"		, i++);
			InsertEffectByFilename(L"ColorDilation.fx"			, i++);
			InsertEffectByFilename(L"ColorBinarisation.fx"		, i++);
			InsertEffectByFilename(L"ColorSubstractResult.fx"	, i++);

			// And finally we select the insertion item on IDC_ACTIVELIST
			CDXUTListBox * pActiveListBox = g_SampleUI.GetListBox(IDC_ACTIVELIST);	// Retrieve the listbox
			if(pActiveListBox) pActiveListBox->SelectItem(i);

			break;
		}
	}
}


//--------------------------------------------------------------------------------------
// Insert a new scaled post process effect to the post process manager processing list
// And list it to the correct index of IDC_ACTIVELIST
//--------------------------------------------------------------------------------------
void InsertEffect(DXUTListBoxItem * pItem, const UINT nAvailableEffectIndex, const float fScaleX, const float fScaleY)
{
	// We retrieve the insertion index for the ACTIVELIST listbox
	CDXUTListBox * pActiveListBox = g_SampleUI.GetListBox(IDC_ACTIVELIST);	// Retrieve the listbox
	int nInsertPos = pActiveListBox->GetSelectedIndex();					// Retrieve its selected position
	nInsertPos=(nInsertPos<0)?0:nInsertPos;									// If none we push back the effect

	// We add the selected effect to the post processing list
	g_pPostProcFXChain->InsertEffect((PPEffectsCommon*)(pItem->pData), nInsertPos, fScaleX, fScaleY);
	
	// And we also add it to the active list along with its scalers values
	UINT * nEffectIndex = new UINT;
	*nEffectIndex = nAvailableEffectIndex;
	pActiveListBox->InsertItem(nInsertPos, pItem->strText, nEffectIndex);
	pActiveListBox->SelectItem(nInsertPos+1);
}


//--------------------------------------------------------------------------------------
// Search the effect from its name in the IDC_AVAILABLELIST
// If found, add it to the post process manager processing list
// And list it to the correct index of IDC_ACTIVELIST
//--------------------------------------------------------------------------------------
void InsertEffectByFilename(LPCWSTR pFilename, const UINT nAvailableEffectIndex, const float fScaleX, const float fScaleY)
{
	// Retrieve the available effect listbox
	CDXUTListBox * pAvailableListBox = g_SampleUI.GetListBox(IDC_AVAILABLELIST);

	// Searching for the item by its name
	int i=pAvailableListBox->GetSize();
	bool bFound = false;
	DXUTListBoxItem * pItem = NULL;
	while(!bFound || i>-1)
	{
		i--;

		pItem = pAvailableListBox->GetItem(i);
		if(pItem)
		{
			if( wcscmp(pItem->strText, pFilename)==0 )
			{
				// We add the selected effect to the post processing list
				g_pPostProcFXChain->InsertEffect((PPEffectsCommon*)(pItem->pData), nAvailableEffectIndex, fScaleX, fScaleY);

				// Insert the new item in the activelist too
				CDXUTListBox * pActiveListBox = g_SampleUI.GetListBox(IDC_ACTIVELIST);	// Retrieve the active listbox
				UINT * nEffectIndex = new UINT;
				*nEffectIndex = i;
				pActiveListBox->InsertItem(nAvailableEffectIndex, pItem->strText, nEffectIndex);

				// We found it!
				bFound = true;
			}
		}
	}
}


//--------------------------------------------------------------------------------------
// Remove the effect at nIndex
//--------------------------------------------------------------------------------------
void RemoveEffect(const int nIndex)
{
	// We retrieve the insertion index for the ACTIVELIST listbox
	CDXUTListBox * pActiveListBox = g_SampleUI.GetListBox(IDC_ACTIVELIST);	// Retrieve the listbox

	// We can't remove the special element at the end of the active list
	if(nIndex == pActiveListBox->GetSize()-1) return;
	
	// And we remove it from the active list
	delete ((UINT*)(pActiveListBox->GetItem(nIndex)->pData));	// Taking care of destroying the effect encapsulator...
	pActiveListBox->RemoveItem(nIndex);							// Before whipping out the item from the list

	// We also from the post processing list
	g_pPostProcFXChain->RemoveEffect(nIndex);
}


//--------------------------------------------------------------------------------------
// Clear the active effect list
//--------------------------------------------------------------------------------------
void ClearActiveEffectsList()
{
	// We clear the active effet list
	CDXUTListBox * pActiveListBox = g_SampleUI.GetListBox(IDC_ACTIVELIST);
	int nTrueListSize = pActiveListBox->GetSize()-1;
	for(int i=0; i<nTrueListSize; ++i)
	{
		//pActiveListBox->SelectItem(0);
		RemoveEffect(0);	// Off, with his heaaaad!
	}

	pActiveListBox->SelectItem(0);	
}


//--------------------------------------------------------------------------------------
// Move an effect up or down
//--------------------------------------------------------------------------------------
void MoveActiveEffect(const bool bMoveUp)
{
	// We retrieve the currently selected effect index
	CDXUTListBox * pListBox = g_SampleUI.GetListBox(IDC_ACTIVELIST);
	int nSelected = pListBox->GetSelectedIndex();
	
	// Checking the item selection validity...
	if(nSelected == pListBox->GetSize()-1) return;			// Is the special blank item selected?
	if(bMoveUp && nSelected<1) return;						// If we move up, is the selected item the first one (or an invalid one)?
	if(!bMoveUp && nSelected>pListBox->GetSize()-3) return;	// If we move down, is the selected item the last one (or the blank space)?

	// Now we know we can move the effect
	int nNeighborEffect = nSelected + (bMoveUp?-1:1);		// Retrieve the neighbor effect index
	
	// Now we retrieve pointers on the list item we must swap
	DXUTListBoxItem *pItem = pListBox->GetItem(nSelected);
	DXUTListBoxItem *pNeighborItem = pListBox->GetItem(nNeighborEffect);

	// And we can swap them
	DXUTListBoxItem tempItem = *pItem;
	*pItem = *pNeighborItem;
	*pNeighborItem = tempItem;

	// We also have to move the effect in the chain
	ScaledPPEffect * pScaledEffect = g_pPostProcFXChain->GetEffect(nSelected);
	ScaledPPEffect * pNeighborScaledEffect = g_pPostProcFXChain->GetEffect(nNeighborEffect);
	
	//ScaledPPEffect *tempEffect = new ScaledPPEffect(pScaledEffect);
	ScaledPPEffect tempEffect = pScaledEffect;
	*pScaledEffect = *pNeighborScaledEffect;
	*pNeighborScaledEffect = tempEffect;

	// We reselect the effect we moved
	pListBox->SelectItem(nNeighborEffect);
}


//--------------------------------------------------------------------------------------
// Activates the slider, edit boxes and other controls to modify the effect
//--------------------------------------------------------------------------------------
void ActivateNeededControls(ScaledPPEffect * pEffect)
{
	if(!pEffect) return;

	// Effect Scaling static and sliders
	g_SampleUI.GetControl(IDC_XSCALERSTATIC)->SetEnabled(true);
	g_SampleUI.GetControl(IDC_XSCALERSTATIC)->SetVisible(true);
	g_SampleUI.GetControl(IDC_YSCALERSTATIC)->SetEnabled(true);
	g_SampleUI.GetControl(IDC_YSCALERSTATIC)->SetVisible(true);

	// Enabling the sliders and setting them to the effect value
	D3DXVECTOR2 scalingVector = pEffect->GetScaler();

	CDXUTSlider * pSlider = (CDXUTSlider*)(g_SampleUI.GetControl(IDC_XSCALERSLIDER));	
	pSlider->SetEnabled(true);
	pSlider->SetVisible(true);
	pSlider->SetValue( (int)(log(scalingVector.x)/log(2.0f)) );

	pSlider = (CDXUTSlider*)(g_SampleUI.GetControl(IDC_YSCALERSLIDER));
	pSlider->SetEnabled(true);
	pSlider->SetVisible(true);
	pSlider->SetValue( (int)(log(scalingVector.y)/log(2.0f)) );

	// Enabling the edit box if needed
	EffectParam * pParameter = NULL;

	// Check parameters availability
	PPEffectsCommon * pSourceEffect = pEffect->GetEffect();
	if(!pEffect) return;
	for(int nParamIndex=0; nParamIndex<MAX_NUM_PARAM; ++nParamIndex)
	{
		// Compute the controls IDC knowing that :
		// - The first control is IDC_PARAM0NAME
		// - We've got 2 controls : a static name and the associated edit box
		int nStaticTextIDC = IDC_PARAM0NAME + 2*nParamIndex;
		int nEditBoxIDC = nStaticTextIDC + 1;

		// Retrieve the first parameter
		pParameter = pSourceEffect->getParameter(nParamIndex);
		if(pParameter)
		{
			// Enable the edit box label
			g_SampleUI.GetStatic(nStaticTextIDC)->SetText(pParameter->GetParamName());
			g_SampleUI.GetStatic(nStaticTextIDC)->SetEnabled(true);
			g_SampleUI.GetStatic(nStaticTextIDC)->SetVisible(true);

			// Enable the edit box and its content
			WCHAR wszParamText[512] = L"";
			FLOAT * pParamDef = pEffect->GetParamValues(nParamIndex);	// !The values are from the scaled effect not the effect!
			for(int nComponentIndex=0; nComponentIndex<pParameter->GetParamSize(); ++nComponentIndex)
			{
				WCHAR wsz[512];
				StringCchPrintf(wsz, 512, L"%.5f ", pParamDef[nComponentIndex]);
				StringCchCat(wszParamText, 512, wsz);
			}

			// Remove trailing space
			if(wszParamText[lstrlenW(wszParamText)-1] == L' ')
				wszParamText[lstrlenW(wszParamText)-1] = L'\0';
			g_SampleUI.GetEditBox(nEditBoxIDC)->SetText( wszParamText );
			
			g_SampleUI.GetEditBox(nEditBoxIDC)->SetEnabled(true);
			g_SampleUI.GetEditBox(nEditBoxIDC)->SetVisible(true);
		}
		else
		{
			g_SampleUI.GetStatic(nStaticTextIDC)->SetEnabled(false);
			g_SampleUI.GetStatic(nStaticTextIDC)->SetVisible(false);
			g_SampleUI.GetEditBox(nEditBoxIDC)->SetEnabled(false);
			g_SampleUI.GetEditBox(nEditBoxIDC)->SetVisible(false);
		}
	}
}


//--------------------------------------------------------------------------------------
// Desactivates the all controls to modify effects
//--------------------------------------------------------------------------------------
void DesactivateModificationControls()
{
	if(g_SampleUI.GetControl(IDC_XSCALERSTATIC))
	{
		g_SampleUI.GetControl(IDC_XSCALERSTATIC)->SetEnabled(false);
		g_SampleUI.GetControl(IDC_XSCALERSTATIC)->SetVisible(false);
	}

	if(g_SampleUI.GetControl(IDC_YSCALERSTATIC))
	{
		g_SampleUI.GetControl(IDC_YSCALERSTATIC)->SetEnabled(false);
		g_SampleUI.GetControl(IDC_YSCALERSTATIC)->SetVisible(false);
	}


	if(g_SampleUI.GetControl(IDC_XSCALERSLIDER))
	{
		g_SampleUI.GetControl(IDC_XSCALERSLIDER)->SetEnabled(false);
		g_SampleUI.GetControl(IDC_XSCALERSLIDER)->SetVisible(false);
	}

	if(g_SampleUI.GetControl(IDC_YSCALERSLIDER))
	{
		g_SampleUI.GetControl(IDC_YSCALERSLIDER)->SetEnabled(false);
		g_SampleUI.GetControl(IDC_YSCALERSLIDER)->SetVisible(false);
	}

	if(g_SampleUI.GetControl(IDC_PARAM0NAME))
	{
		g_SampleUI.GetControl(IDC_PARAM0NAME)->SetEnabled(false);
		g_SampleUI.GetControl(IDC_PARAM0NAME)->SetVisible(false);
	}

	if(g_SampleUI.GetControl(IDC_PARAM0))
	{
		g_SampleUI.GetControl(IDC_PARAM0)->SetEnabled(false);
		g_SampleUI.GetControl(IDC_PARAM0)->SetVisible(false);
	}

	if(g_SampleUI.GetControl(IDC_PARAM1NAME))
	{
		g_SampleUI.GetControl(IDC_PARAM1NAME)->SetEnabled(false);
		g_SampleUI.GetControl(IDC_PARAM1NAME)->SetVisible(false);
	}

	if(g_SampleUI.GetControl(IDC_PARAM1))
	{
		g_SampleUI.GetControl(IDC_PARAM1)->SetEnabled(false);
		g_SampleUI.GetControl(IDC_PARAM1)->SetVisible(false);
	}
}

//--------------------------------------------------------------------------------------
// Parse a string that contains a list of floats separated by space, and store
// them in the array of float pointed to by pBuffer.
// Parses up to 4 floats.
//--------------------------------------------------------------------------------------
void ParseFloatList(const WCHAR *pwszText, FLOAT * pFloatArray)
{
	if(!pwszText || !pFloatArray) return;

	int nWritten = 0;  // Number of floats written
	const WCHAR *pToken, *pEnd;
	WCHAR wszToken[30];

	pToken = pwszText;
	while( nWritten < 4 && *pToken != L'\0' )
	{
		// Skip leading spaces
		while( *pToken == L' ' )
			++pToken;

		// Locate the end of number
		pEnd = pToken;
		while( IN_FLOAT_CHARSET(*pEnd) )
			++pEnd;

		// Copy the token to our buffer
		int nTokenLen = min( sizeof(wszToken) / sizeof(wszToken[0]), int(pEnd - pToken) + 1 );
		StringCchCopy( wszToken, nTokenLen, pToken );
		*pFloatArray = (float)_wtof( wszToken );
		++nWritten;
		++pFloatArray;
		pToken = pEnd;
	}
}


//--------------------------------------------------------------------------------------
// Select a Realtime shader from pData
//--------------------------------------------------------------------------------------
void SelectRealTimeShaderFromData(void * pData)
{
	if(!pData) return;

	switch((int)(size_t)pData)
	{
		case IDS_SIMPLELIGHTING:
			g_pCurrentEffect = g_pSimpleLighting;

			break;

		case IDS_CELSHADING:
			g_pCurrentEffect = g_pCelShading;

			break;
	}
}


//--------------------------------------------------------------------------------------
// Release resources created in the OnResetDevice callback here 
//--------------------------------------------------------------------------------------
void CALLBACK OnLostDevice( void* pUserContext )
{
	// The light arrow
	CDXUTDirectionWidget::StaticOnLostDevice();

	// The 3D objects
	if(g_pSkyBox) g_pSkyBox->OnLostDevice();

	// The demo shaders
	if(g_pSimpleLighting) g_pSimpleLighting->OnLostDevice();	
	if(g_pCelShading) g_pCelShading->OnLostDevice();
	if(g_pZPrePass) g_pZPrePass->OnLostDevice();
	
	// The managers
	if(g_pFXFilesManager) g_pFXFilesManager->OnLostDevice();
	if(g_pPPManager) g_pPPManager->OnLostDevice();	
	
	// The GUI
	g_DialogResourceManager.OnLostDevice();
	g_SettingsDlg.OnLostDevice();
	if(g_pFont) g_pFont->OnLostDevice();
	SAFE_RELEASE( g_pTextSprite );
}


//--------------------------------------------------------------------------------------
// Release resources created in the OnCreateDevice callback here
//--------------------------------------------------------------------------------------
void CALLBACK OnDestroyDevice( void* pUserContext )
{
	// Destroy the objects and effects interfaces
	CDXUTDirectionWidget::StaticOnDestroyDevice();
	
	if(g_pFXFilesManager) { PostProcFXFilesManager::Kill(); g_pFXFilesManager = NULL; }
	if(g_pPPManager) { PostProcManager::Kill(); g_pPPManager = NULL; }
	if(g_pTransformMatrixManager) { TransformMatrixesManager::Kill(); g_pTransformMatrixManager = NULL; }
	
	if(g_pSimpleLighting) { delete(g_pSimpleLighting); g_pSimpleLighting = NULL; }
	if(g_pCelShading) { delete(g_pCelShading); g_pCelShading = NULL; }
	if(g_pZPrePass) { delete(g_pZPrePass); g_pZPrePass = NULL; }
	g_pCurrentEffect = NULL;
	
	if(g_pXObject) { delete(g_pXObject); g_pXObject = NULL; }
	if(g_pSkyBox) { delete(g_pSkyBox); g_pSkyBox = NULL; }	

	g_DialogResourceManager.OnDestroyDevice();
	g_SettingsDlg.OnDestroyDevice();
	SAFE_RELEASE( g_pFont );
}


//--------------------------------------------------------------------------------------
// Initialize the app 
//--------------------------------------------------------------------------------------
void InitApp()
{
	//------------------------- DEVICE INDEPENDENT SCENE DATA --------------------------//
	// Init the camera
	D3DXVECTOR3 vecEye(0.0f, 0.0f, -15.0f);
    D3DXVECTOR3 vecAt (0.0f, 0.0f, -0.0f);
	g_Camera.SetViewParams( &vecEye, &vecAt );
	g_Camera.SetModelCenter( D3DXVECTOR3(0.0f, 0.0f, 0.0f) );

	// Init the light
	g_LightControl.SetLightDirection(D3DXVECTOR3(sinf(0.0), 0, -cosf(0.0)));

	// the post process effects chain
	g_pPostProcFXChain = new PostProcFXChain();

	//-------------------------------------- GUI ---------------------------------------//
	// Create the sample GUI controls
	InitGUI();	

	// Disable every per effect modification controls by default
	DesactivateModificationControls();
}


//--------------------------------------------------------------------------------------
// Create the sample GUI
//--------------------------------------------------------------------------------------
void InitGUI()
{
	// Initialize dialogs
	g_SettingsDlg.Init(&g_DialogResourceManager);
	g_HUD.Init(&g_DialogResourceManager);
	g_SampleUI.Init(&g_DialogResourceManager);

	g_HUD.SetCallback(OnGUIEvent);

	int iY = 0;
	// Add the full screen and change device buttons
	g_HUD.AddButton(IDC_TOGGLEFULLSCREEN, L"Toggle full screen", 0, iY, 125, 22);
	g_HUD.AddButton(IDC_CHANGEDEVICE, L"Change device (F2)", 0, iY += 24, 125, 22, VK_F2);

	// Init the sample UI
	g_SampleUI.SetCallback(OnGUIEvent);
	iY = 5;
	g_SampleUI.EnableCaption(true);
	g_SampleUI.SetCaptionText(L"Effect Manager");
	g_SampleUI.SetBackgroundColors(D3DCOLOR_ARGB(100, 255, 255, 255));

	// Initialize sample-specific UI controls
	g_SampleUI.AddStatic(IDC_AVAILABLELISTLABEL, L"Available effects (Dbl click inserts effect):", 10, iY, 210, 16);
	g_SampleUI.GetStatic(IDC_AVAILABLELISTLABEL)->GetElement(0)->dwTextFormat = DT_LEFT|DT_TOP;
	CDXUTListBox *pListBox;
	g_SampleUI.AddListBox(IDC_AVAILABLELIST, 10, iY += 18, 200, 82, 0, &pListBox); // This box is filled at device creation
	
	g_SampleUI.AddStatic(IDC_ACTIVELISTLABEL, L"Active effects (Dbl click removes effect):", 10, iY += 87, 210, 16);
	g_SampleUI.GetStatic(IDC_ACTIVELISTLABEL)->GetElement( 0 )->dwTextFormat = DT_LEFT|DT_TOP;
	g_SampleUI.AddListBox(IDC_ACTIVELIST, 10, iY += 18, 200, 82, 0, &pListBox);
	if(pListBox)
	{
		// Add a blank entry for users to add effect to the end of list.
		pListBox->AddItem(L"", NULL);
		pListBox->SelectItem(0);
	}

	// Buttons to control the active effects list organisation
	g_SampleUI.AddButton(IDC_MOVEUP, L"Move Up", 5, iY += 92, 70, 22);
	g_SampleUI.AddButton(IDC_MOVEDOWN, L"Move Down", 75, iY, 75, 22);
	g_SampleUI.AddButton(IDC_CLEAR, L"Clear All", 150, iY, 65, 22);

	// Add sliders to control post-process scaling
	g_SampleUI.AddStatic(IDC_XSCALERSTATIC, L"Effect X Scaler", 15, iY += 25, 80, 15);
	g_SampleUI.AddStatic(IDC_YSCALERSTATIC, L"Effect Y Scaler", 120, iY, 80, 15);
	g_SampleUI.AddSlider(IDC_XSCALERSLIDER, 15, iY += 20, 80, 20, -2, 2, 0);
	g_SampleUI.AddSlider(IDC_YSCALERSLIDER, 120, iY, 80, 20, -2, 2, 0);	

	// Add two edit box controls for the effect parameters values
	g_SampleUI.AddStatic(IDC_PARAM0NAME, L"", 5, iY += 23, 215, 15);
	g_SampleUI.GetStatic(IDC_PARAM0NAME)->GetElement(0)->dwTextFormat = DT_LEFT|DT_TOP;
	CDXUTEditBox *pEditBox;
	g_SampleUI.AddEditBox(IDC_PARAM0, L"", 5, iY += 15, 210, 20, false, &pEditBox);
	if(pEditBox)
	{
		pEditBox->SetBorderWidth(1);
		pEditBox->SetSpacing(2);
	}
	g_SampleUI.AddStatic(IDC_PARAM1NAME, L"", 5, iY += 20, 215, 15);
	g_SampleUI.GetStatic(IDC_PARAM1NAME )->GetElement( 0 )->dwTextFormat = DT_LEFT|DT_TOP;
	g_SampleUI.AddEditBox(IDC_PARAM1, L"", 5, iY += 15, 210, 20, false, &pEditBox);
	if(pEditBox)
	{
		pEditBox->SetBorderWidth(1);
		pEditBox->SetSpacing(2);
	}

	// Add a combo box to change mesh
	CDXUTComboBox *pComboBox;
    g_SampleUI.AddComboBox(IDC_SELECTRTSHADER, 5, iY += 25, 210, 24, L'S', false, &pComboBox);
    if(pComboBox)
    {
        pComboBox->AddItem(L"(S)hader: SimpleLighting", (LPVOID)IDS_SIMPLELIGHTING);
        pComboBox->AddItem(L"(S)hader: CelShading", (LPVOID)IDS_CELSHADING);
    }

	// Adding a serie of preset buttons
	g_SampleUI.AddStatic(IDC_PRESETLABEL, L"Predefined post-process combinations:", 5, iY += 28, 210, 22);
    g_SampleUI.GetControl(IDC_PRESETLABEL)->GetElement(0)->dwTextFormat = DT_LEFT|DT_TOP;

    g_SampleUI.AddButton(IDC_PREBLUR		, L"Blur"			, 5		, iY += 25	, 100, 22);
    g_SampleUI.AddButton(IDC_PRECELSHADING	, L"Full CelShading", 115	, iY		, 100, 22);
    g_SampleUI.AddButton(IDC_PREDOF			, L"Depth of Field"	, 5		, iY += 25	, 100, 22);
    g_SampleUI.AddButton(IDC_PREEDGE		, L"Edge Glow"		, 115	, iY		, 100, 22);
    g_SampleUI.AddButton(IDC_PREBLOOM		, L"Bloom"			, 5		, iY += 25	, 100, 22);
    g_SampleUI.AddButton(IDC_PREBLOOM2		, L"Faster Bloom"	, 115	, iY	, 100, 22);	
}


//--------------------------------------------------------------------------------------
// Do the cleaning
//--------------------------------------------------------------------------------------
void CleanApp()
{
	// We clean the active effects list that might contains a few instanciated encapsulators
	ClearActiveEffectsList();

	// Delete the FX chain
	if(g_pPostProcFXChain)
	{
		delete(g_pPostProcFXChain);
		g_pPostProcFXChain = NULL;
	}
}


//--------------------------------------------------------------------------------------
// Initialize everything and go into a render loop
//--------------------------------------------------------------------------------------
INT WINAPI WinMain( HINSTANCE, HINSTANCE, LPSTR, int )
{
    // Enable run-time memory check for debug builds.
#if defined(DEBUG) | defined(_DEBUG)
    _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
#endif

    // Set the callback functions
    DXUTSetCallbackDeviceCreated(OnCreateDevice);
    DXUTSetCallbackDeviceReset(OnResetDevice);
    DXUTSetCallbackDeviceLost(OnLostDevice);
    DXUTSetCallbackDeviceDestroyed(OnDestroyDevice);
    DXUTSetCallbackMsgProc(MsgProc);
	DXUTSetCallbackKeyboard(KeyboardProc);
    DXUTSetCallbackFrameRender(OnFrameRender);
    DXUTSetCallbackFrameMove(OnFrameMove);
   
    // Perform any application-level initialization here
	InitApp();

    // Initialize DXUT and create the desired Win32 window and Direct3D device for the application
    DXUTInit(true, true, true);				// Parse the command line, handle the default hotkeys, and show msgboxes
    DXUTSetCursorSettings(true, true);		// Show the cursor and clip it when in full screen
    DXUTCreateWindow(L"Post Processing");
	DXUTSetMultimonSettings(true);

	// Launching fullscreen at current windows primary display resolution because of the GUI size
	//DXUTCreateDevice(D3DADAPTER_DEFAULT, false, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN), IsDeviceAcceptable, ModifyDeviceSettings);
	DXUTCreateDevice(D3DADAPTER_DEFAULT, true, 640, 480, IsDeviceAcceptable, ModifyDeviceSettings);

    // Start the render loop
    DXUTMainLoop();

    // Perform any application-level cleanup here
	CleanApp();

    return DXUTGetExitCode();
}