///////////////////////////////////////////////////////////////////////  
//  LeafMesh.hlsl
//
//	This file contains the shaders used for the leaf mesh geometry.  These shaders 
//	will compile with HLSL and Cg compilers.
//
//
//	*** INTERACTIVE DATA VISUALIZATION (IDV) CONFIDENTIAL AND PROPRIETARY INFORMATION ***
//
//	This software is supplied under the terms of a license agreement or
//	nondisclosure agreement with Interactive Data Visualization, Inc. and
//  may not be copied, disclosed, or exploited except in accordance with 
//  the terms of that agreement.
//
//      Copyright (c) 2003-2010 IDV, Inc.
//      All rights reserved in all media.
//
//      IDV, Inc.
//      Web: http://www.idvinc.com

#ifndef SPEEDTREE_USING_EFFECTS
	#include "Global.hlsl"
	#include "UniformVariables.hlsl"
	#include "Utility.hlsl"
	#include "Wind.hlsl"
	#include "Lighting.hlsl"
#endif


///////////////////////////////////////////////////////////////////////  
//  Shader input/output structures
//
//	The cpp-level source code is setup to feed this vertex format to all of the
//	leaf mesh vertex shader variations.
//
//	Leaf mesh vertex input is currently the same as the branch

struct SLeafMeshVertex
{
	float4	m_vPosition		: SPEEDTREE_ATTR0;		// xyz = position, w = wind scalar
	float4	m_vLodPosition	: SPEEDTREE_ATTR8;		// xyz = LOD position, w = wind scalar mag
	float4  m_vNormal       : SPEEDTREE_ATTR9;		// xyz = normal, w = amb occ
	float4	m_vTangent		: SPEEDTREE_ATTR10;		// xyz = tangent, w = wind active flag
	float4	m_vWindData		: SPEEDTREE_ATTR11;		// xyz = wind direction, w = wind offset
	float2	m_vTexCoords	: SPEEDTREE_ATTR12;		// xy = diffuse texcoords
};


///////////////////////////////////////////////////////////////////////  
//  LeafMeshVertex

SStandardPixel LeafMeshVertex(SLeafMeshVertex sIn)
{
    // this will be fed to the branch pixel shader
    SStandardPixel sOut;

	// setup aliases (taken from global variables)
	const float  c_fTreeScale = g_vTreePosAndScale.w;
	const float3 c_vTreePos = g_vTreePosAndScale.xyz;
	const float  c_fLod = g_vTreeRotation.w;
	const float  c_fLodLerp = g_vTreeRotation.z;

	// setup aliases (taken from incoming vertex)
	const float3 c_vPos = sIn.m_vPosition.xyz;
	const float3 c_vLodPos = sIn.m_vLodPosition.xyz;
	const float2 c_vDiffuseTexCoords = sIn.m_vTexCoords.xy;
	const float4 c_vTangent = UncompressVector4(sIn.m_vTangent);
	const float4 c_vNormal = UncompressVector4(sIn.m_vNormal);
	const float  c_fAmbientOcclusion = c_vNormal.w;
	const float  c_fWindScalar = sIn.m_vPosition.w;
	const float  c_fWindActive = (c_vTangent.w > 0.0f);
	const float  c_fWindScalarMag = sIn.m_vLodPosition.w;
	const float4 c_vWindData = UncompressWindVector(sIn.m_vWindData, c_fWindScalarMag);

	// LOD interpolation; branches are shrunk & grown, depending on the LOD setting
	float3 vPosition = lerp(c_vLodPos, c_vPos, c_fLodLerp);

	// compensate for the instance's arbitrary rotation
	vPosition = AdjustForTreeRotation(vPosition);
	float3 vRotatedNormal = AdjustForTreeRotation(c_vNormal.xyz);
	float3 vRotatedTangent = AdjustForTreeRotation(c_vTangent.xyz);
	float3 vRotatedBinormal = cross(vRotatedNormal.xyz, vRotatedTangent.xyz);

	// move the branch vertex with wind
	#ifdef SPEEDTREE_BASIC_WIND
		if (c_fWindActive > 0.0f)
		{
			vPosition = LeafWindMotion(vPosition, vRotatedNormal, c_fWindScalar);

			float3 vWindOffset;
			vPosition = CommonWindMotion(vPosition, c_vWindData, vWindOffset);

			#ifdef SPEEDTREE_WIND_AFFECTS_LIGHTING
				vRotatedNormal += vWindOffset;
				vRotatedNormal = normalize(vRotatedNormal);
				vRotatedBinormal += vWindOffset;
				vRotatedBinormal = normalize(vRotatedBinormal);
				vRotatedTangent += vWindOffset;
				vRotatedTangent = normalize(vRotatedTangent);
			#endif
		}
	#endif

	// normal map based lighting
	sOut.m_vNormalVec.x = dot(g_vLightDir, vRotatedTangent);
    sOut.m_vNormalVec.y = dot(g_vLightDir, vRotatedBinormal);
    sOut.m_vNormalVec.z = dot(g_vLightDir, vRotatedNormal);

	// scale the whole tree
    vPosition *= c_fTreeScale;

	// move the instance into place
	vPosition += c_vTreePos;

	// compute half vector in tangent space for per-pixel specular lighting effect
	if (SPEEDTREE_SPECULAR_LIGHTING)
		sOut.m_vSpecularHalfVector = ComputeSpecularHalfVector(vRotatedNormal, vRotatedBinormal, vRotatedTangent, vPosition);
	else
		sOut.m_vSpecularHalfVector = float3(0,0,0);

	// final screen projection
	sOut.m_vPosition = ProjectToScreen(vPosition);

	// passthrough values
	sOut.m_vDiffuseTexCoords.xy = c_vDiffuseTexCoords;
	sOut.m_vDetailTexCoords.xy = float2(0.0f, 0.0f); // unused for leaf meshes
	sOut.m_vDetailTexCoords.w = c_fAmbientOcclusion;

	// compute alpha scalar based on LOD; will cross fade the 3D geometry with billboard images
	float fDistance;
	sOut.m_vDiffuseTexCoords.w = Compute3dFade(fDistance);
	sOut.m_vNormalVec.w = SpecialEffectFade(fDistance);

	// shadow projection
	#ifdef SPEEDTREE_SHADOWS_ENABLED
		for (int i = 0; i < SPEEDTREE_NUM_SHADOW_MAPS; ++i)
			sOut.m_av2dPosInLightSpace[i] = ProjectToLightSpace(vPosition, g_amLightViewProjs[i]);

		// need the depth to determine which shadow map to use
		sOut.m_vDetailTexCoords.z = sOut.m_vPosition.z / g_fFarClip;
	#else
		sOut.m_vDetailTexCoords.z = 0.0f;
	#endif

	// transmission computation
	#ifdef SPEEDTREE_TRANSMISSION_LIGHTING
		sOut.m_vDiffuseTexCoords.z = TransmissionBackContribution(vRotatedNormal);
	#else
		sOut.m_vDiffuseTexCoords.z = 0.0f;
	#endif

	// compute fog value
    sOut.m_vFogData = FogVertex(vPosition);

    return sOut;
}


///////////////////////////////////////////////////////////////////////  
//  LeafMeshPixel

float4 LeafMeshPixel(SStandardPixel sIn) : SPEEDTREE_PS_OUTPUT
{
	return StandardPixel(sIn,
						 SPEEDTREE_SPECULAR_LIGHTING, 
						 SPEEDTREE_TRANSMISSION_LIGHTING, 
						 SPEEDTREE_AMBIENT_CONTRAST, 
						 false,  // detail texture always off for leaf meshes
						 false,  // detail normal mapping always off for leaf meshes
						 false); // don't use smooth shadow filters here, too expensive for minimal effect
}


#ifdef SPEEDTREE_Z_PREPASS

	///////////////////////////////////////////////////////////////////////  
	//  LeafMeshVertex_Depth

	SStandardPixel_Depth LeafMeshVertex_Depth(SLeafMeshVertex sIn)
	{
		SStandardPixel_Depth sOut;

		// setup aliases (taken from global variables)
		const float  c_fTreeScale = g_vTreePosAndScale.w;
		const float3 c_vTreePos = g_vTreePosAndScale.xyz;
		const float  c_fLod = g_vTreeRotation.w;
		const float  c_fLodLerp = g_vTreeRotation.z;

		// setup aliases (taken from incoming vertex)
		const float3 c_vPos = sIn.m_vPosition.xyz;
		const float3 c_vLodPos = sIn.m_vLodPosition.xyz;
		const float2 c_vDiffuseTexCoords = sIn.m_vTexCoords.xy;
		const float4 c_vTangent = UncompressVector4(sIn.m_vTangent);
		const float4 c_vNormal = UncompressVector4(sIn.m_vNormal);
		const float  c_fAmbientOcclusion = c_vNormal.w;
		const float3 c_vBinormal = cross(c_vNormal.xyz, c_vTangent.xyz);
		const float  c_fWindScalar = sIn.m_vPosition.w;
		const float  c_fWindActive = (c_vTangent.w > 0.0f);
		const float  c_fWindScalarMag = sIn.m_vLodPosition.w;
		const float4 c_vWindData = UncompressWindVector(sIn.m_vWindData, c_fWindScalarMag);

		// LOD interpolation; branches are shrunk & grown, depending on the LOD setting
		float3 vPosition = lerp(c_vLodPos, c_vPos, c_fLodLerp);

		// rotation
		vPosition = AdjustForTreeRotation(vPosition);
		float3 vRotatedNormal = AdjustForTreeRotation(c_vNormal.xyz);

		// move the branch vertex with wind
		#ifdef SPEEDTREE_BASIC_WIND
			if (c_fWindActive > 0.0f)
			{
				vPosition = LeafWindMotion(vPosition, vRotatedNormal, c_fWindScalar);

				float3 vWindOffset;
				vPosition = CommonWindMotion(vPosition, c_vWindData, vWindOffset);
			}
		#endif

		// scale tree
		vPosition *= c_fTreeScale;

		// move the instance into place
		vPosition += c_vTreePos;

		// texcoords
		sOut.m_vDiffuseTexCoords.xy = c_vDiffuseTexCoords;
		sOut.m_vDiffuseTexCoords.z = Compute3dFade( );

		// final screen projection
		sOut.m_vPosition = ProjectToScreen(vPosition);

		return sOut;
	}


	///////////////////////////////////////////////////////////////////////  
	//  LeafMeshPixel_Depth

	float4 LeafMeshPixel_Depth(SStandardPixel_Depth sIn) : SPEEDTREE_PS_OUTPUT
	{
		return StandardPixel_Depth(sIn);
	}

#endif // SPEEDTREE_Z_PREPASS


#ifdef SPEEDTREE_SHADOWS_ENABLED

	///////////////////////////////////////////////////////////////////////  
	//  LeafMeshVertex_Shadow

	SStandardPixel_Shadow LeafMeshVertex_Shadow(SLeafMeshVertex sIn)
	{
		SStandardPixel_Shadow sOut;

		// setup aliases (taken from global variables)
		const float  c_fTreeScale = g_vTreePosAndScale.w;
		const float3 c_vTreePos = g_vTreePosAndScale.xyz;
		const float  c_fLod = g_vTreeRotation.w;
		const float  c_fLodLerp = g_vTreeRotation.z;

		// setup aliases (taken from incoming vertex)
		const float3 c_vPos = sIn.m_vPosition.xyz;
		const float2 c_vDiffuseTexCoords = sIn.m_vTexCoords.xy;
		const float3 c_vLodPos = sIn.m_vLodPosition.xyz;
		const float  c_fWindScalar = sIn.m_vPosition.w;
		const float4 c_vTangent = UncompressVector4(sIn.m_vTangent);
		const float4 c_vNormal = UncompressVector4(sIn.m_vNormal);
		const float  c_fWindActive = (c_vTangent.w > 0.0f);
		const float  c_fWindScalarMag = sIn.m_vLodPosition.w;
		const float4 c_vWindData = UncompressWindVector(sIn.m_vWindData, c_fWindScalarMag);

		// LOD interpolation; branches are shrunk & grown, depending on the LOD setting
		float3 vPosition = lerp(c_vLodPos, c_vPos, c_fLodLerp);
		float3 vRotatedNormal = AdjustForTreeRotation(c_vNormal.xyz);

		// rotation
		vPosition = AdjustForTreeRotation(vPosition);

		// move the branch vertex with wind
		#ifdef SPEEDTREE_BASIC_WIND
			if (c_fWindActive > 0.0f)
			{
				vPosition = LeafWindMotion(vPosition, vRotatedNormal, c_fWindScalar);

				float3 vWindOffset;
				vPosition = CommonWindMotion(vPosition, c_vWindData, vWindOffset);
			}
		#endif

		// scale tree
		vPosition *= c_fTreeScale;

		// translate tree
		vPosition += c_vTreePos;

		// compute alpha scalar based on LOD; will cross fade the 3D geometry with
		// billboard images
		sOut.m_vDiffuseTexCoords.z = Compute3dFade( );

		// final screen projection
		sOut.m_vPosition = ProjectToScreen(vPosition);

		// passthrougs
		sOut.m_vDiffuseTexCoords.xy = c_vDiffuseTexCoords;

		return sOut;
	}


	///////////////////////////////////////////////////////////////////////  
	//  LeafMeshPixel_Shadow

	float4 LeafMeshPixel_Shadow(SStandardPixel_Shadow sIn) : SPEEDTREE_PS_OUTPUT
	{
		return StandardPixel_Shadow(sIn);
	}

#endif // SPEEDTREE_SHADOWS_ENABLED

