///////////////////////////////////////////////////////////////////////  
//  Terrain.hlsl
//
//	This file contains the shaders used for the vertical & horizontal
//	billboards. 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"
	#ifdef SPEEDTREE_SHADOWS_ENABLED
		#include "Shadows.hlsl"
	#endif
#endif


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

struct STerrainVertex
{
	float3		m_vPosition			: SPEEDTREE_ATTR0;		// xyz = coordinate
	float3		m_vTexCoords		: SPEEDTREE_ATTR8;		// xy = diffuse texcoords, z = ambient occlusion
};

struct STerrainPixel
{
    float4  m_vPosition				: SPEEDTREE_VS_OUTPUT;	// xyzw = screen-projected position
	float3	m_vTexCoords			: TEXCOORD0;			// xy = diffuse texcoords, z = ambient occlusion
	float4	m_vFogData				: TEXCOORD1;
#ifdef SPEEDTREE_SHADOWS_ENABLED
	float	m_fDepth				: TEXCOORD2;			// distance from the camera, in view space
	float4	m_av2dPosInLightSpace[SPEEDTREE_NUM_SHADOW_MAPS]	: TEXCOORD3;	// light space coordinates
#endif
};


///////////////////////////////////////////////////////////////////////  
//  Structure STerrainPixel_Depth

struct STerrainPixel_Depth
{
    float4  m_vPosition				: SPEEDTREE_VS_OUTPUT;
};


///////////////////////////////////////////////////////////////////////  
//  TerrainVertex

STerrainPixel TerrainVertex(STerrainVertex sIn)
{
    STerrainPixel sOut;

	float3 vPosition = sIn.m_vPosition.xyz;

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

	// passthrough values
	sOut.m_vTexCoords.xyz = sIn.m_vTexCoords.xyz;

	#ifdef SPEEDTREE_SHADOWS_ENABLED
		// shadow projection
		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_fDepth = sOut.m_vPosition.z / g_fFarClip;

		// fade ambient occlusion value
		const float c_fAmbientOcclusion = sIn.m_vTexCoords.z;
		sOut.m_vTexCoords.z = FadeByDepth(c_fAmbientOcclusion, sOut.m_fDepth, g_vSplitDistances[SPEEDTREE_NUM_SHADOW_MAPS - 1], g_vShadowFadeParams.y);
	#endif

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

    return sOut;
}


///////////////////////////////////////////////////////////////////////  
//  TerrainPixel

float4 TerrainPixel(STerrainPixel sIn) : SPEEDTREE_PS_OUTPUT
{
	// setup aliases (taken from global variables)
	const float4 c_vAmbientMaterial = g_vMaterialAmbient;
	const float4 c_vDiffuseMaterial = g_vMaterialDiffuse;
	const float  c_fSplat0Repeat = g_vSplatMapTiles.x;
	const float  c_fSplat1Repeat = g_vSplatMapTiles.y;
	const float  c_fSplat2Repeat = g_vSplatMapTiles.z;
	const float2 c_vTexCoords = sIn.m_vTexCoords.xy;
	const float	 c_fAmbientOcclusion = sIn.m_vTexCoords.z;

	// normal map
	float3 texNormal = TerrainNormalMapLookup(sIn.m_vTexCoords.xy);

	// splat map and individual textures
	float3 texSplats = SampleTexture(TerrainSplatMap, c_vTexCoords).xyz;

	float3 texSplat0 = SampleTexture(TerrainSplatLayer0, c_vTexCoords * c_fSplat0Repeat).xyz;
    float3 texSplat1 = SampleTexture(TerrainSplatLayer1, c_vTexCoords * c_fSplat1Repeat).xyz;
    float3 texSplat2 = SampleTexture(TerrainSplatLayer2, c_vTexCoords * c_fSplat2Repeat).xyz;

    // combination of splats based on map
    float3 vFinal = texSplat0 * texSplats.x + texSplat1 * texSplats.y + texSplat2 * texSplats.z;

	// get shadow contribution if enabled
	#ifdef SPEEDTREE_SHADOWS_ENABLED
		// fade the ambient occlusion contribution on the inverse of the real-time shadows, but use an offset so it's not the exact inverse
		float fShadow = c_fAmbientOcclusion;
		fShadow = min(fShadow, ShadowMapLookup(sIn.m_av2dPosInLightSpace, sIn.m_fDepth, false));
	#else
		float fShadow = c_fAmbientOcclusion;
	#endif

	#if defined(SPEEDTREE_SHADOWS_ENABLED) && defined(SPEEDTREE_TERRAIN_SHOW_SPLITS)
		vFinal += TintShadowMapRegion(sIn.m_fDepth);
	#endif

	// lighting & shadow computation
	float fLighting = saturate(dot(texNormal, g_vLightDir)) * fShadow;

	// final colors
	float3 vOut = vFinal * lerp(c_vAmbientMaterial.rgb, c_vDiffuseMaterial.rgb, fLighting);

	// fog
	vOut = FogPixel(sIn.m_vFogData, vOut);

	return float4(vOut, 1.0f);
}


#ifdef SPEEDTREE_Z_PREPASS

	///////////////////////////////////////////////////////////////////////  
	//  TerrainVertex_Depth

	STerrainPixel_Depth TerrainVertex_Depth(STerrainVertex sIn)
	{
		STerrainPixel_Depth sOut;

		float3 vPosition = sIn.m_vPosition.xyz;

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

		return sOut;
	}


	///////////////////////////////////////////////////////////////////////  
	//  TerrainPixel_Depth

	float4 TerrainPixel_Depth(STerrainPixel_Depth sIn) : SPEEDTREE_PS_OUTPUT
	{
		return float4(1, 1, 1, 1);
	}

#endif // SPEEDTREE_Z_PREPASS

