EffectTranslucency::EffectTranslucency( Texture2D& _RTTarget ) : m_ErrorCode( 0 ), m_RTTarget( _RTTarget )
{
	//////////////////////////////////////////////////////////////////////////
	// Create the materials
	CHECK_MATERIAL( m_pMatDisplay = CreateMaterial( IDR_SHADER_TRANSLUCENCY_DISPLAY, "./Resources/Shaders/TranslucencyDisplay.hlsl", VertexFormatP3N3G3T2::DESCRIPTOR, "VS", NULL, "PS" ), 1 );
	CHECK_MATERIAL( m_pMatBuildZBuffer = CreateMaterial( IDR_SHADER_TRANSLUCENCY_BUILD_ZBUFFER, "./Resources/Shaders/TranslucencyBuildZBuffer.hlsl", VertexFormatP3N3G3T2::DESCRIPTOR, "VS", NULL, "PS" ), 2 );

	D3D_SHADER_MACRO	pMacros[2] = { { "TARGET_SIZE", "128" }, { NULL, NULL } };
	CHECK_MATERIAL( m_pMatDiffusion = CreateMaterial( IDR_SHADER_TRANSLUCENCY_DIFFUSION, "./Resources/Shaders/TranslucencyDiffusion.hlsl", VertexFormatPt4::DESCRIPTOR, "VS", NULL, "PS", pMacros ), 3 );

	//////////////////////////////////////////////////////////////////////////
	// Build some sphere primitives
	{
		Noise	N( 1 );

		m_pPrimTorusInternal = new Primitive( gs_Device, VertexFormatP3N3G3T2::DESCRIPTOR );
		GeometryBuilder::BuildTorus( 80, 50, 1.0f, 0.2f, *m_pPrimTorusInternal, NULL, TweakTorusInternal, &N );

		m_pPrimSphereExternal = new Primitive( gs_Device, VertexFormatP3N3G3T2::DESCRIPTOR );
		GeometryBuilder::MapperSpherical	Mapper( 4.0f, 2.0f );
		GeometryBuilder::BuildSphere( 80, 50, *m_pPrimSphereExternal, &Mapper, TweakSphereExternal, &N );
	}

	//////////////////////////////////////////////////////////////////////////
	// Build textures & render targets
	m_pRTZBuffer = new Texture2D( gs_Device, DIFFUSION_SIZE, DIFFUSION_SIZE, 1, PixelFormatRGBA16F::DESCRIPTOR, 1, NULL );
	m_pDepthStencil = new Texture2D( gs_Device, DIFFUSION_SIZE, DIFFUSION_SIZE, DepthStencilFormatD32F::DESCRIPTOR );

	m_ppRTDiffusion[0] = new Texture2D( gs_Device, DIFFUSION_SIZE, DIFFUSION_SIZE, 1, PixelFormatRGBA16F::DESCRIPTOR, 1, NULL );
	m_ppRTDiffusion[1] = new Texture2D( gs_Device, DIFFUSION_SIZE, DIFFUSION_SIZE, 1, PixelFormatRGBA16F::DESCRIPTOR, 1, NULL );


	//////////////////////////////////////////////////////////////////////////
	// Create the constant buffers
	m_pCB_Object = new CB<CBObject>( gs_Device, 10 );
	m_pCB_Diffusion = new CB<CBDiffusion>( gs_Device, 10 );
	m_pCB_Pass = new CB<CBPass>( gs_Device, 11 );
}
EffectParticles::EffectParticles() : m_ErrorCode( 0 )
{
	//////////////////////////////////////////////////////////////////////////
	// Create the materials
	CHECK_MATERIAL( m_pMatCompute = CreateMaterial( IDR_SHADER_PARTICLES_COMPUTE, "./Resources/Shaders/ParticlesCompute.hlsl", VertexFormatPt4::DESCRIPTOR, "VS", NULL, "PS" ), 1 );
	CHECK_MATERIAL( m_pMatDisplay = CreateMaterial( IDR_SHADER_PARTICLES_DISPLAY, "./Resources/Shaders/ParticlesDisplay.hlsl", VertexFormatPt4::DESCRIPTOR, "VS", "GS", "PS" ), 2 );
	CHECK_MATERIAL( m_pMatDebugVoronoi = CreateMaterial( IDR_SHADER_PARTICLES_DISPLAY, "./Resources/Shaders/ParticlesDisplay.hlsl", VertexFormatPt4::DESCRIPTOR, "VS_DEBUG", NULL, "PS_DEBUG" ), 3 );


	//////////////////////////////////////////////////////////////////////////
	// Build the awesome particle primitive
// 	{
// 		VertexFormatP3	Vertices;
// 		m_pPrimParticle = new Primitive( gs_Device, 1, &Vertices, 0, NULL, D3D11_PRIMITIVE_TOPOLOGY_POINTLIST, VertexFormatP3::DESCRIPTOR );
// 	}

	//////////////////////////////////////////////////////////////////////////
	// Build our voronoï texture & our initial positions & data
	NjFloat2*	pCellCenters = new NjFloat2[EFFECT_PARTICLES_COUNT*EFFECT_PARTICLES_COUNT];
	{
		TextureBuilder		TB( 1024, 1024 );
		VertexFormatPt4*	pVertices = new VertexFormatPt4[EFFECT_PARTICLES_COUNT*EFFECT_PARTICLES_COUNT];
		BuildVoronoiTexture( TB, pCellCenters, pVertices );

		TextureBuilder::ConversionParams	Conv =
		{
			0,		// int		PosR;
			1,		// int		PosG;
			-1,		// int		PosB;
			-1,		// int		PosA;
			false,

					// Position of the height & roughness fields
			-1,		// int		PosHeight;
			-1,		// int		PosRoughness;

					// Position of the Material ID
			-1,		// int		PosMatID;

					// Position of the normal fields
//			1.0f,	// float	NormalFactor;	// Factor to apply to the height to generate the normals
			true,
			-1,		// int		PosNormalX;
			-1,		// int		PosNormalY;
			-1,		// int		PosNormalZ;

					// Position of the AO field
//			1.0f,	// float	AOFactor;		// Factor to apply to the height to generate the AO
			-1,		// int		PosAO;
		};

		m_pTexVoronoi = TB.CreateTexture( PixelFormatRG32F::DESCRIPTOR, Conv );


		m_pPrimParticle = new Primitive( gs_Device, EFFECT_PARTICLES_COUNT*EFFECT_PARTICLES_COUNT, pVertices, 0, NULL, D3D11_PRIMITIVE_TOPOLOGY_POINTLIST, VertexFormatPt4::DESCRIPTOR );

		// Build cell centers
		for ( int ParticleIndex=0; ParticleIndex < EFFECT_PARTICLES_COUNT*EFFECT_PARTICLES_COUNT; ParticleIndex++ )
			pCellCenters[ParticleIndex].Set( 0.5f * (pVertices[ParticleIndex].Pt.x + pVertices[ParticleIndex].Pt.z), 0.5f * (pVertices[ParticleIndex].Pt.y + pVertices[ParticleIndex].Pt.w) );

		delete[] pVertices;
	}

	//////////////////////////////////////////////////////////////////////////
	// Build the initial positions & orientations of the particles from the surface of a torus
	PixelFormatRGBA32F*	pInitialPositions = new PixelFormatRGBA32F[EFFECT_PARTICLES_COUNT*EFFECT_PARTICLES_COUNT];
	PixelFormatRGBA32F*	pInitialNormals = new PixelFormatRGBA32F[EFFECT_PARTICLES_COUNT*EFFECT_PARTICLES_COUNT];
	PixelFormatRGBA32F*	pInitialTangents = new PixelFormatRGBA32F[EFFECT_PARTICLES_COUNT*EFFECT_PARTICLES_COUNT];
	PixelFormatRGBA32F*	pScanlinePosition = pInitialPositions;
	PixelFormatRGBA32F*	pScanlineNormal = pInitialNormals;
	PixelFormatRGBA32F*	pScanlineTangent = pInitialTangents;

	int		TotalCount = EFFECT_PARTICLES_COUNT*EFFECT_PARTICLES_COUNT;
	int		ParticlesPerDimension = U32(floorf(powf( float(TotalCount), 1.0f/3.0f )));
	float	R = 0.5f;	// Great radius of the torus
	float	r = 0.2f;	// Small radius of the torus

	for ( int Y=0; Y < EFFECT_PARTICLES_COUNT; Y++ )
		for ( int X=0; X < EFFECT_PARTICLES_COUNT; X++, pScanlinePosition++, pScanlineNormal++, pScanlineTangent++ )
		{
			NjFloat2&	CellCenter = pCellCenters[EFFECT_PARTICLES_COUNT*Y+X];
			float		Alpha = TWOPI * X / EFFECT_PARTICLES_COUNT;	// Angle on the great circle
			float		Beta = TWOPI * Y / EFFECT_PARTICLES_COUNT;	// Angle on the small circle

			NjFloat3	T( cosf(Alpha), 0.0f, -sinf(Alpha) );		// Gives the direction to the center on the great circle in the Z^X plane
			NjFloat3	Center = NjFloat3( 0, 0.8f, 0 ) + R * T;	// Center on the great circle
			NjFloat3	Ortho( T.z, 0, -T.x );						// Tangent to the great circle in the Z^X plane
			NjFloat3	B( 0, 1, 0 );								// Bitangent is obviously, always the Y vector

			NjFloat3	Normal = cosf(Beta) * T + sinf(Beta) * B;	// The normal to the small circle, also the direction to the point on the surface
			NjFloat3	Tangent = Ortho;
			NjFloat3	Pos = Center + r * Normal;					// Position on the surface of the small circle

			float		Radius = R + r * cosf(Beta);				// Radius of the circle where the particle is standing
			float		Perimeter = TWOPI * Radius;					// Perimeter of that circle
			float		ParticleSize = 0.5f * Perimeter;			// Size of a single particle on that circle

			float		ParticleLife = -1.0f - 4.0f * (1.0f - Normal.y);	// Start with a negative life depending on height
 
// DEBUG Generate on a plane for verification
// Pos.x = 2.0f * (CellCenter.x - 0.5f);
// Pos.y = 0.5f;
// Pos.z = -2.0f * (CellCenter.y - 0.5f);
// Normal.Set( 0, 1, 0 );	// Facing up
// Tangent.Set( 1, 0, 0 );	// Right
// ParticleSize = 1.0f;// / EFFECT_PARTICLES_COUNT;	// Size of a single particle on that circle
// DEBUG


			pScanlinePosition->R = Pos.x;
			pScanlinePosition->G = Pos.y;
			pScanlinePosition->B = Pos.z;
			pScanlinePosition->A = ParticleLife;

			pScanlineNormal->R = Normal.x;
			pScanlineNormal->G = Normal.y;
			pScanlineNormal->B = Normal.z;
//			pScanlineNormal->A = (0.025f + 0.002f) * EFFECT_PARTICLES_COUNT;	// Half size + a little epsilon to make the tiles join correctly
//			pScanlineNormal->A = (0.1f + 0*0.002f) * EFFECT_PARTICLES_COUNT;	// Half size + a little epsilon to make the tiles join correctly
			pScanlineNormal->A = ParticleSize;

			pScanlineTangent->R = Tangent.x;
			pScanlineTangent->G = Tangent.y;
			pScanlineTangent->B = Tangent.z;
			pScanlineTangent->A = Normal.y > 0.0f ? 1.0f : -1.0f;	// Determines the particle's behavior...
		}

	delete[]	pCellCenters;

	// Unfortunately, we need to create Textures to initialize our RenderTargets
	void*		ppContentPositions[1];
				ppContentPositions[0] = (void*) pInitialPositions;
	Texture2D*	pTempPositions = new Texture2D( gs_Device, EFFECT_PARTICLES_COUNT, EFFECT_PARTICLES_COUNT, 1, PixelFormatRGBA32F::DESCRIPTOR, 1, ppContentPositions );
	delete[]	pInitialPositions;

	void*		ppContentNormals[1];
				ppContentNormals[0] = (void*) pInitialNormals;
	Texture2D*	pTempNormals = new Texture2D( gs_Device, EFFECT_PARTICLES_COUNT, EFFECT_PARTICLES_COUNT, 1, PixelFormatRGBA32F::DESCRIPTOR, 1, ppContentNormals );
	delete[]	pInitialNormals;

	void*		ppContentTangents[1];
				ppContentTangents[0] = (void*) pInitialTangents;
	Texture2D*	pTempTangents = new Texture2D( gs_Device, EFFECT_PARTICLES_COUNT, EFFECT_PARTICLES_COUNT, 1, PixelFormatRGBA32F::DESCRIPTOR, 1, ppContentTangents );
	delete[]	pInitialTangents;

	// Finally, create the render targets and initialize them
	m_ppRTParticlePositions[0] = new Texture2D( gs_Device, EFFECT_PARTICLES_COUNT, EFFECT_PARTICLES_COUNT, 1, PixelFormatRGBA32F::DESCRIPTOR, 1, NULL );
	m_ppRTParticlePositions[1] = new Texture2D( gs_Device, EFFECT_PARTICLES_COUNT, EFFECT_PARTICLES_COUNT, 1, PixelFormatRGBA32F::DESCRIPTOR, 1, NULL );
	m_ppRTParticlePositions[2] = new Texture2D( gs_Device, EFFECT_PARTICLES_COUNT, EFFECT_PARTICLES_COUNT, 1, PixelFormatRGBA32F::DESCRIPTOR, 1, NULL );
	m_ppRTParticlePositions[0]->CopyFrom( *pTempPositions );
	m_ppRTParticlePositions[1]->CopyFrom( *pTempPositions );
	m_ppRTParticlePositions[2]->CopyFrom( *pTempPositions );
	delete	pTempPositions;

	m_ppRTParticleNormals[0] = new Texture2D( gs_Device, EFFECT_PARTICLES_COUNT, EFFECT_PARTICLES_COUNT, 1, PixelFormatRGBA32F::DESCRIPTOR, 1, NULL );
	m_ppRTParticleNormals[1] = new Texture2D( gs_Device, EFFECT_PARTICLES_COUNT, EFFECT_PARTICLES_COUNT, 1, PixelFormatRGBA32F::DESCRIPTOR, 1, NULL );
	m_ppRTParticleNormals[0]->CopyFrom( *pTempNormals );
	m_ppRTParticleNormals[1]->CopyFrom( *pTempNormals );
	delete pTempNormals;

	m_ppRTParticleTangents[0] = new Texture2D( gs_Device, EFFECT_PARTICLES_COUNT, EFFECT_PARTICLES_COUNT, 1, PixelFormatRGBA32F::DESCRIPTOR, 1, NULL );
	m_ppRTParticleTangents[1] = new Texture2D( gs_Device, EFFECT_PARTICLES_COUNT, EFFECT_PARTICLES_COUNT, 1, PixelFormatRGBA32F::DESCRIPTOR, 1, NULL );
	m_ppRTParticleTangents[0]->CopyFrom( *pTempTangents );
	m_ppRTParticleTangents[1]->CopyFrom( *pTempTangents );
	delete pTempTangents;


	//////////////////////////////////////////////////////////////////////////
	// Create the constant buffers
	m_pCB_Render = new CB<CBRender>( gs_Device, 10 );
	m_pCB_Render->m.DeltaTime.Set( 0, 1 );
}