///////////////////////////////////////////////////////////////////////  
//  LeafCard.hlsl
//
//	*** 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


///////////////////////////////////////////////////////////////////////  
//  Global Variables, specific to the leaf card shaders

float4x4	g_mCameraFacingMatrix   GLOBAL_REG(50);			// not shared, leaf cards only


///////////////////////////////////////////////////////////////////////  
//  Shader input/output structures
//
//	The cpp-level source code is setup to feed this vertex format to all of the
//	leaf card vertex shader variations.

struct SLeafCardVertex
{
	float4	m_vCardCenter		: SPEEDTREE_ATTR0;		// xyz = center pos, w = wind scalar
	float4	m_vNormal			: SPEEDTREE_ATTR8;		// xyz = normal, w = amb occ
	float4	m_vTangent			: SPEEDTREE_ATTR9;		// xyz = tangent, w = tangent padding
	float4	m_vWindData			: SPEEDTREE_ATTR10;		// xyzw = wind data
	float4  m_vCardCorner		: SPEEDTREE_ATTR11;		// xy = card corner, z = lod scale, w = wind scalar mag
	float4  m_vTexCoords		: SPEEDTREE_ATTR12;		// xy = diffuse texcoords, z = planar offset, w = shadow offset
};


///////////////////////////////////////////////////////////////////////  
//  LeafCardVertex

SStandardPixel LeafCardVertex(SLeafCardVertex sIn)
{
    // this will be fed to the leaf card 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_vCardCenter = sIn.m_vCardCenter.xyz;
	const float4 c_vNormal = UncompressVector4(sIn.m_vNormal);
	const float  c_fAmbientOcclusion = c_vNormal.w;
	const float4 c_vTangent = UncompressVector4(sIn.m_vTangent);
	const float2 c_vDiffuseTexCoords = sIn.m_vTexCoords.xy;
	const float2 c_vCorner = sIn.m_vCardCorner.xy;
	const float	 c_fLodScale = sIn.m_vCardCorner.z;
	const float  c_fWindScalar = sIn.m_vCardCenter.w;
	const float  c_fWindScalarMag = sIn.m_vCardCorner.w;
	const float4 c_vWindData = UncompressWindVector(sIn.m_vWindData, c_fWindScalarMag);
	const float  c_fPlanarOffset = sIn.m_vTexCoords.z;

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

	// LOD interpolation; cards are shrunk & grown, depending on the LOD setting
	float fLodScale = lerp(c_fLodScale, 1.0f, c_fLodLerp);
	float2 vLodScaledCorner = c_vCorner * fLodScale;
	float4 vCardCorner = float4(0.0f, vLodScaledCorner, 1.0f);

	// rotate the card to face the camera
	vCardCorner = mul(g_mCameraFacingMatrix, vCardCorner);

	// place the card according to the tree's overall scale
	float3 vPosition = vRotatedCenter + vCardCorner.xyz;
	
	// adjust corner to keep all the leaf cards from being coplanar
	vPosition.xyz += c_fPlanarOffset * g_vCameraDirection;

	// move the vertex with wind
	#ifdef SPEEDTREE_BASIC_WIND
		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 leaf card
	vPosition.xyz *= c_fTreeScale;

	// move the position to this instance's position in the forest
	vPosition.xyz += 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.xyz);

	// 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);

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

	// shadow projection
	#ifdef SPEEDTREE_SHADOWS_ENABLED
		for (int i = 0; i < SPEEDTREE_NUM_SHADOW_MAPS; ++i)
			sOut.m_av2dPosInLightSpace[i] = ProjectToLightSpace(vPosition.xyz, 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.xyz);

    return sOut;
}


///////////////////////////////////////////////////////////////////////  
//  LeafCardPixel

float4 LeafCardPixel(SStandardPixel sIn) : SPEEDTREE_PS_OUTPUT
{
	return StandardPixel(sIn,
						 false,  // specular effect is expensive and rarely noticed; replace with SPEEDTREE_SPECULAR_LIGHTING if needed
						 SPEEDTREE_TRANSMISSION_LIGHTING, 
						 SPEEDTREE_AMBIENT_CONTRAST, 
						 false,  // detail texture always off for leaf cards
						 false,  // detail normal mapping always off for leaf cards
						 false); // don't use smooth shadow filters here, too expensive for minimal effect
}


#ifdef SPEEDTREE_Z_PREPASS

	///////////////////////////////////////////////////////////////////////  
	//  LeafCardVertex_Depth

	SStandardPixel_Depth LeafCardVertex_Depth(SLeafCardVertex sIn)
	{
		// this will be fed to the leaf card pixel shader
		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_vCardCenter = sIn.m_vCardCenter.xyz;
		const float4 c_vNormal = UncompressVector4(sIn.m_vNormal);
		const float  c_fAmbientOcclusion = c_vNormal.w;
		const float4 c_vTangent = UncompressVector4(sIn.m_vTangent);
		const float3 c_vBinormal = cross(c_vNormal.xyz, c_vTangent.xyz);
		const float2 c_vDiffuseTexCoords = sIn.m_vTexCoords.xy;
		const float2 c_vCorner = sIn.m_vCardCorner.xy;
		const float	 c_fLodScale = sIn.m_vCardCorner.z;
		const float  c_fWindScalar = sIn.m_vCardCenter.w;
		const float  c_fWindScalarMag = sIn.m_vCardCorner.w;
		const float4 c_vWindData = UncompressWindVector(sIn.m_vWindData, c_fWindScalarMag);
		const float  c_fPlanarOffset = sIn.m_vTexCoords.z;

		// compensate for the instance's arbitrary rotation
		float3 vRotatedCenter = AdjustForTreeRotation(c_vCardCenter);
		float3 vRotatedNormal = AdjustForTreeRotation(c_vNormal.xyz);
		
		// LOD interpolation; cards are shrunk & grown, depending on the LOD setting
		float fLodScale = lerp(c_fLodScale, 1.0f, c_fLodLerp);
		float2 vLodScaledCorner = c_vCorner * fLodScale;
		float4 vCardCorner = float4(0.0f, vLodScaledCorner, 1.0f);

		// rotate the card to face the camera
		vCardCorner = mul(g_mCameraFacingMatrix, vCardCorner);

		// place and scale the card according to the tree's overall scale
		float3 vPosition = vRotatedCenter + vCardCorner.xyz;
	
		// adjust corner to keep all the leaf cards from being coplanar
		vPosition.xyz += c_fPlanarOffset * g_vCameraDirection;
		
		// move the vertex with wind
		#ifdef SPEEDTREE_BASIC_WIND
			vPosition = LeafWindMotion(vPosition, vRotatedNormal, c_fWindScalar);
			float3 vWindOffset;
			vPosition = CommonWindMotion(vPosition, c_vWindData, vWindOffset);
		#endif

		// scale the leaf card
		vPosition.xyz *= c_fTreeScale;

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

		// move the position to this instance's position in the forest
		vPosition.xyz += c_vTreePos;

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

		return sOut;
	}


	///////////////////////////////////////////////////////////////////////  
	//  LeafCardPixel_Depth

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

#endif // SPEEDTREE_Z_PREPASS


#ifdef SPEEDTREE_SHADOWS_ENABLED

	///////////////////////////////////////////////////////////////////////  
	//  LeafCardVertex_Shadow

	SStandardPixel_Shadow LeafCardVertex_Shadow(SLeafCardVertex sIn)
	{
		// this will be fed to the leaf card pixel shader
		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_vCardCenter = sIn.m_vCardCenter.xyz;
		const float4 c_vNormal = UncompressVector4(sIn.m_vNormal);
		const float  c_fAmbientOcclusion = c_vNormal.w;
		const float4 c_vTangent = UncompressVector4(sIn.m_vTangent);
		const float3 c_vBinormal = cross(c_vNormal.xyz, c_vTangent.xyz);
		const float2 c_vDiffuseTexCoords = sIn.m_vTexCoords.xy;
		const float2 c_vCorner = sIn.m_vCardCorner.xy;
		const float	 c_fLodScale = sIn.m_vCardCorner.z;
		const float  c_fWindScalar = sIn.m_vCardCenter.w;
		const float  c_fWindScalarMag = sIn.m_vCardCorner.w;
		const float4 c_vWindData = UncompressWindVector(sIn.m_vWindData, c_fWindScalarMag);
		const float  c_fPlanarOffset = sIn.m_vTexCoords.z;
		const float  c_fShadowOffset = sIn.m_vTexCoords.w;

		// compensate for the instance's arbitrary rotation
		float3 vRotatedCenter = AdjustForTreeRotation(c_vCardCenter);
		float3 vRotatedNormal = AdjustForTreeRotation(c_vNormal.xyz);

		// LOD interpolation; cards are shrunk & grown, depending on the LOD setting
		float fLodScale = lerp(c_fLodScale, 1.0f, c_fLodLerp);
		float2 vLodScaledCorner = c_vCorner * fLodScale;
		float4 vCardCorner = float4(0.0f, vLodScaledCorner, 1.0f);

		// rotate the card to face the camera
		vCardCorner = mul(g_mCameraFacingMatrix, vCardCorner);

		// move the offset position away in the light direction to avoid shadowing artifacts
		vRotatedCenter -= c_fShadowOffset * g_vLightDir;

		// place and scale the card according to the tree's overall scale
		float3 vPosition = vRotatedCenter + vCardCorner.xyz;
	
		// adjust corner to keep all the leaf cards from being coplanar
		vPosition.xyz += c_fPlanarOffset * g_vCameraDirection;
		
		// move the vertex with wind
		#ifdef SPEEDTREE_BASIC_WIND
			vPosition = LeafWindMotion(vPosition, vRotatedNormal, c_fWindScalar);
			float3 vWindOffset;
			vPosition = CommonWindMotion(vPosition, c_vWindData, vWindOffset);
		#endif

		vPosition.xyz *= c_fTreeScale;

		// move the position to this instance's position in the forest
		vPosition.xyz += c_vTreePos;

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

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

		// passthrough values
		sOut.m_vDiffuseTexCoords.xy = c_vDiffuseTexCoords;

		return sOut;
	}


	///////////////////////////////////////////////////////////////////////  
	//  LeafCardPixel_Shadow

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

#endif // SPEEDTREE_SHADOWS_ENABLED


