[WIP]Interactive Grass

Post » Sat Jan 15, 2011 3:17 am

thats odd as i didnt alter that part and it how phals ingame comes and it works with out the interactive grass it really is picky huh lol, so should i just remove all of GrassVertOut GrassInstVS section then?
User avatar
Esther Fernandez
 
Posts: 3415
Joined: Wed Sep 27, 2006 11:52 am

Post » Sat Jan 15, 2011 2:31 am

anyone care to upload the fully edited version, or at least just paste it here.. i really hate editing, there's always something that goes wrong + today im really lazy ;)
User avatar
Sophie Miller
 
Posts: 3300
Joined: Sun Jun 18, 2006 12:35 am

Post » Sat Jan 15, 2011 6:07 pm

anyone care to upload the fully edited version, or at least just paste it here.. i really hate editing, there's always something that goes wrong + today im really lazy ;)

Everyone has a different ingame.fx. And I am always lazy. :P I did refined the post with clearer instructions.
User avatar
Kortknee Bell
 
Posts: 3345
Joined: Tue Jan 30, 2007 5:05 pm

Post » Sat Jan 15, 2011 3:43 am

:P I'd upload mine, but I've added code for waves around Vivec's water spouts, except mine are at piratelords redesigned vivec locations rather than the original games, which would be messed up if you aren't using it, also I got it working, I found a syntax error in the code above that was causing my crash, its a simple, there was a space where there should not have been a space thing, oops, my bad! lol
User avatar
Taylor Tifany
 
Posts: 3555
Joined: Sun Jun 25, 2006 7:22 am

Post » Sat Jan 15, 2011 4:40 am

:P I'd upload mine, but I've added code for waves around Vivec's water spouts, except mine are at piratelords redesigned vivec locations rather than the original games, which would be messed up if you aren't using it, also I got it working, I found a syntax error in the code above that was causing my crash, its a simple, there was a space where there should not have been a space thing, oops, my bad! lol


isnt the water ripples just a bunch of coordenates, so you can change them i think i have a list of the coordenates some ware as i needed to add them to phals new ingame
i could post them here for anyone that needs them other wise id like a copy of your ingame assuming it works with phals bata v5 that is
User avatar
Abel Vazquez
 
Posts: 3334
Joined: Tue Aug 14, 2007 12:25 am

Post » Sat Jan 15, 2011 7:57 am

Once I figure out how to make the grass snap back more smoothly I'll upload my ingame.fx. Right now, after you've walked through the grass instead of snapping back into place smoothly it suddenly becomes fully bent in the exact opposite direction, and then it moves smoothly back into place from the wrong direction, which is why the grass appears somewhat jerky.
User avatar
Kelly Tomlinson
 
Posts: 3503
Joined: Sat Jul 08, 2006 11:57 pm

Post » Sat Jan 15, 2011 8:51 am

awesome no rush, just one question dose this affect npcs and creatures or is it just hooked to the pc?
User avatar
Kelli Wolfe
 
Posts: 3440
Joined: Thu Aug 23, 2007 7:09 am

Post » Sat Jan 15, 2011 11:02 am

awesome no rush, just one question dose this affect npcs and creatures or is it just hooked to the pc?


This just affects the pc. I'm not sure how I would go about getting the positions of npcs and creatures for this to work.

Also, does anyone know how I could go about retrieving a vector of the player's last movement?
User avatar
Alexis Acevedo
 
Posts: 3330
Joined: Sat Oct 27, 2007 8:58 pm

Post » Sat Jan 15, 2011 9:47 am

This is coming along nicely, great work everybody! :)
I think something like
float eyedist = length(EyePos.xyz - PlayerPos.xyz);
if ( eyedist < 150 )
could be used like PGGet3dPerson, for instance
	//player bending grass	float eyedist = length(EyePos.xyz - PlayerPos.xyz);	float2 distxy = worldpos.xyz - PlayerPos.xyz;	float gdist = length(distxy);	float2 bend_ticks1 = distxy/1000/gdist;	if (eyedist > 150) { // 3rd person view		if ( gdist < 80 )  {			worldpos.xy += bend_ticks1/abs(bend_ticks1)*cos(bend_ticks1)*height/(25+gdist)*3500;		}	}	else { // 1st person view		if ( gdist < 130 ) {			worldpos.xy += bend_ticks1/abs(bend_ticks1)*cos(bend_ticks1)*height/(25+gdist)*5000;		}		}		worldpos.xy += (sin(pos_ticks1) + cos(pos_ticks2) + sin(pos_ticks3) + cos(pos_ticks4)) * height * wind;

This the current InGame.fx I'm messing with, working with Phal's latest dll.
Spoiler
// Original by Timeslip and LizTail, mods by harlanrm, phal, krzymar, Liztail, Peachykeen, C_Mireneye, Vtastek, tomerk, abot
// To be used with phal's MGE 3.8.2 rev. 178 and derivatives

Matrix TexProj;
Matrix view;
Matrix proj;
Matrix world;
float4x4 MatrixPalette [4] : MATRIXPALETTE;
float3 SunVec;
float3 SunCol;
float3 EyePos;
float3 SunAmb;
float3 SkyCol;
float ticks;
float2 offset;
float TexBlend;
float2 rcpres;
int FogCol;
float3 FogCol2;
float FogStart;
float FogRange;
float BlendStart;
float BlendEnd;
float GrassDist;
float2 WindVec;
float PixelWidth;
float PixelHeight;
float3 SunPos;
float SunVis;
float3 PlayerPos;
float2 RippleOrigin;
float WaterLevel;
float AlphaMultiplier;
float CausticIntens;

texture tex0;
texture tex1;
texture tex2;
texture tex3;
texture tex4;
texture tex5;
sampler s0 = sampler_state { texture = ; minfilter = linear; magfilter = linear; mipfilter = linear; addressu = clamp; addressv = clamp; };
sampler s1 = sampler_state { texture = ; minfilter = linear; magfilter = linear; mipfilter = linear; addressu = wrap; addressv = wrap; addressw = wrap; };
sampler s2 = sampler_state { texture = ; minfilter = linear; magfilter = linear; mipfilter = linear; addressu = wrap; addressv = wrap; };
sampler s3 = sampler_state { texture = ; minfilter = linear; magfilter = linear; mipfilter = linear; addressu = wrap; addressv = wrap; };
sampler s4 = sampler_state { texture = ; minfilter = linear; magfilter = linear; mipfilter = linear; addressu = clamp; addressv = clamp; };

// For sampling the far water texture
sampler s5 = sampler_state { texture = ; minfilter = linear; magfilter = linear; mipfilter = none; addressu = wrap; addressv = wrap; };
sampler s6 = sampler_state { texture = ; minfilter = linear; magfilter = linear; mipfilter = none; addressu = wrap; addressv = wrap; };
sampler s7 = sampler_state { texture = ; minfilter = linear; magfilter = linear; mipfilter = linear; addressu = clamp; addressv = clamp; };
sampler s8 = sampler_state { texture = ; minfilter = linear; magfilter = linear; mipfilter = linear; bordercolor = 0x80808080 ; addressu = border; addressv = border; };

//------------------------------------------------------------

// water & dynamic ripples settings
#if WAVEHEIGHT > 0
const bool fineWaterMesh = true; // use tesselated circular water mesh? false uses simple mesh
#else
const bool fineWaterMesh = false; // use tesselated circular water mesh? false uses simple mesh
#endif

const int waveTexResolution = 512; // texture resolution for rain ripples and player waves
const float waveTexWorldResolution = 2.50f; // world size of each player wave texture pixel

float waveTexWorldSize; // set by MGE
float waveTexRcpRes; // set by MGE

static const float3 watercolour = { 0.4, 0.45, 0.5 };
static const float FLT_MAX = 340282346600000000000000000000000000000.0f;

static const float FogRangeMinusStart = FogRange - FogStart;

//------------------------------------------------------------

static const float _lightfactor = 1 - pow (1 - SunVis, 2);
static const float3 _depthcolor = _lightfactor * SunCol * float3 (0.03, 0.04, 0.05) + (SkyCol + 0.5*FogCol2) * float3 (0.075, 0.08, 0.085);
//static const float3 _depthcolor = _lightfactor * SunCol * float3 (0.03, 0.04, 0.05) + (2 * SkyCol + FogCol2) * float3 (0.075, 0.08, 0.085);
static const float cauststr = 0.0001f * CausticIntens * saturate (0.75 * _lightfactor + 0.35 * length (FogCol2));

#if SHADER_MODEL >= 300
static const float _windfactor = length (WindVec) + 1.5;
static const float _windfactor2 = ( length(WindVec) * 0.75 ) + 0.25; // abot

static const float TwiceWaterLevel = 2 * WaterLevel;
#define PS_SM ps_3_0
#define VS_SM vs_3_0
#else
#define PS_SM ps_2_0
#define VS_SM vs_2_0
#endif

//------------------------------------------------------------
#if SHADER_MODEL >= 300
#ifdef EXPFOG
#define SCATTER 1
#endif
#endif
#ifdef SCATTER
#define FOGTYPE float4
#define REFFOGTYPE float4
float niceWeatherFactor;

//static const float ExpFogStart = max(0, FogStart);
//static const float ExpFogMult = saturate( FogRange/(FogRangeMinusStart) );
//static const float ExpFogRangeMinusStart = FogRange - ExpFogStart;
//float getFog(float dist)
//{
//return saturate( 1.01832*exp(-(dist-ExpFogStart)/(ExpFogRangeMinusStart))-0.01832 ) * ExpFogMult;
// return saturate( exp(-(dist-ExpFogStart)/(ExpFogRangeMinusStart)) ) * ExpFogMult;
//}

//#define getFogAlpha(dist) (saturate( exp(-((dist)-ExpFogStart)/(ExpFogRangeMinusStart)) ) * ExpFogMult)

#define getFogAlpha(dist) (saturate( exp(-(dist)/FogRange) ))

static const float3 scatter = {0.07, 0.27, 0.67};
static const float sunaltitude = pow(1.0+SunPos.z,10);
static const float sunaltitude_a = 2.8+1.2/sunaltitude;
//static const float sunaltitude_b = 0.75*sunaltitude;
static const float sunaltitude_b = 1 - exp2( -1.9*sunaltitude );
static const float sunaltitude2 = saturate(exp(-2*SunPos.z))*saturate(sunaltitude);
//abot static const float3 newskycol = 0.35*SkyCol+float3(0.22,0.40,0.70);
static const float3 newskycol = SkyCol;

float4 _getFog(float3 dir, float dist, bool coloradjust)
{
float fogdist;
float fog;
if(dist < 0) {
fogdist = 1;
fog = 0;
dist = 1E6;
} else {
fogdist = dist/FogRange;
fog = saturate( exp(-fogdist) );
fogdist = saturate(fogdist/4);
}

float3 fFogCol2 = ( lerp (FogCol2, SkyCol, 1 - pow (saturate (1 - 2.22 * saturate (dir.z - 0.075)), 1.15)) )*(1-fog);

if(niceWeatherFactor > 0.001 && (dist<0 || EyePos.z>WaterLevel-4)) {
float cos = dot(dir,SunPos);
float mie = (1.080/(1.2-cos))*sunaltitude2;
float rayl = 1-0.09*mie;

float atmdep = saturate(exp(-1.5*dir.z));

float3 att = atmdep*(scatter*(sunaltitude_a+mie));
att = (1-exp(-fogdist*att))/(att);

//float3 color = 0.125*mie + lerp(newskycol, float3(1,1,1), 0.75*fog)*rayl;
float3 color = 0.125*mie + newskycol*rayl;

color *= (1.4*atmdep+0.6) * saturate(sunaltitude_B);
color *= att;

color = lerp(fFogCol2,color,niceWeatherFactor);

return float4( color, fog );
} else {
return float4( fFogCol2, fog );
}
}
// static const bool underwater = (EyePos.z < WaterLevel-4);
// float4 getFog(float3 dir, float dist)
// {
//if(underwater && dist >= 0) {
// float fog = saturate( ( FogRange - dist ) / (FogRangeMinusStart) )*(1-fog);
// return float4( FogCol2*(1-fog), fog );
//} else {
// return _getFog(dir,dist,true);
//}
//}
//float4 getFog_refl(float3 dir, float dist) { return _getFog(dir,dist,false); }
//float3 applyfog(float3 col, float4 fog) { return lerp(fog.rgb, col, fog.a); }
//float3 applyfog(float3 col, float4 fog) { return col*fog.a+fog.rgb; }

#define getFog(dir,dist) (_getFog((dir),(dist),true))
#define getFog_refl(dir,dist) (_getFog((dir),(dist),false))
#define applyfog(col,fog) ((col)*(fog).a + (fog).rgb)

static const float3 SunCollf = lerp(SunCol,getFog(SunPos,-1).rgb,niceWeatherFactor*sunaltitude2) * _lightfactor;

struct SkyVertOut {
float4 position: POSITION;
float4 pos: TEXCOORD0;
};
SkyVertOut SkyVS( float4 pos: POSITION ) {
SkyVertOut OUT;

OUT.pos = float4(pos.x,pos.y,-550-pos.z,1);
OUT.position = OUT.pos;
OUT.position.xyz = mul(OUT.position.xyz, (float3x3)view);
OUT.position = mul(OUT.position, proj);

return OUT;
}
float4 SkyPS( in SkyVertOut IN ) : COLOR0 {
float3 fog = getFog(normalize(IN.pos.xyz),-1).rgb;
return float4(fog,1);
}
#else //no scatter
static const float3 SunCollf = SunCol * _lightfactor;

#ifdef EXPFOG
#define FOGTYPE float4
#define REFFOGTYPE float
//static const float ExpFogStart = max (0, FogStart);
//static const float ExpFogMult = saturate (FogRange / FogRangeMinusStart);
//static const float ExpFogRangeMinusStart = FogRange - ExpFogStart;

#define skyfogblend(z) (lerp (FogCol2, SkyCol, 1 - pow (saturate (1 - 2.22 * saturate ((z) - 0.075)), 1.15)))
#define applyfog(col,fog) (lerp ((fog).rgb, (col), (fog).a))
//#define getFog(dist) (saturate (exp (-((dist) - ExpFogStart) / ExpFogRangeMinusStart)) * ExpFogMult)
#define getFog(dist) (saturate (exp (-(dist)/FogRange)))
#define getFogAlpha(dist) (getFog((dist)))
#else
#define FOGTYPE float
#define REFFOGTYPE float
#define getFog(dist) (saturate ((FogRange - (dist)) / FogRangeMinusStart))
#define getFogAlpha(dist) (getFog((dist)))
#endif
#endif

//------------------------------------------------------------


// variation of harlanrm's Vivec and Molag Mar sewer waves
#define SEWERWAVE 1

#ifdef SEWERWAVE
//Vivec sewer locations
static const float2 wLoc[62] = {
{ 19160, -86825},
{ 46500, -81930},
{ 31475, -104345},
{ 32165, -76700},
{ 19160, -81900},
{ 20260, -80775},
{ 20300, -87915},
{ 24125, -80775},
{ 24225, -87915},
{ 25275, -86700},
{ 25275, -81850},
{ 25550, -95230},
{ 25550, -91390},
{ 25550, -88840},
{ 25550, -84940},
{ 26300, -81750},
{ 26300, -77825},
{ 26630, -89955},
{ 26650, -96365},
{ 26700, -83850},
{ 27185, -90260},
{ 27625, -82800},
{ 27635, -76700},
{ 31180, -96925},
{ 31200, -103770},
{ 31540, -83850},
{ 31615, -96365},
{ 31765, -90260},
{ 31895, -89955},
{ 32150, -82800},
{ 32675, -95020},
{ 32675, -91785},
{ 32675, -88690},
{ 32675, -85300},
{ 32975, -95365},
{ 32975, -91190},
{ 32975, -89110},
{ 32975, -84720},
{ 33450, -81635},
{ 33450, -77945},
{ 34095, -96365},
{ 34120, -90260},
{ 34175, -104345},
{ 34480, -83850},
{ 34585, -89955},
{ 34640, -96925},
{ 34695, -103770},
{ 38500, -89955},
{ 38965, -96365},
{ 38980, -83850},
{ 39060, -90260},
{ 40100, -95300},
{ 40100, -91395},
{ 40100, -88790},
{ 40100, -84900},
{ 40400, -86900},
{ 40400, -81955},
{ 41350, -87915},
{ 41475, -80775},
{ 45300, -87915},
{ 45480, -80775},
{ 46500, -86790},
};
static const float2 wLoc2[8] = {
//Molag Mar
{ 107090, -63820},
{ 114215, -59905},
{ 113110, -64890},
{ 107090, -59875},
{ 108085, -58800},
{ 108110, -64890},
{ 113170, -58800},
{ 114215, -63780}
};
#endif


float4 RenderShader (in float2 TexCoords : TEXCOORD0, in float3 Light : TEXCOORD1, in float4 Height : TEXCOORD2) : COLOR0 {
clip (Height);
float3 Result = tex2D (s3, TexCoords).rgb * Light;
return float4 (Result, 1);
}

//------------------------------------------------------------

struct StatVertIn {
float4 pos : POSITION;
float4 normal : NORMAL;
float4 color : COLOR0;
float2 texcoords : TEXCOORD0;
};

//------------------------------------------------------------

struct StatVertOut {
float4 pos : POSITION;
float2 texcoords : TEXCOORD0;
float4 color : TEXCOORD1;
float3 normal : TEXCOORD2;
FOGTYPE fog : TEXCOORD3;
float blend : TEXCOORD5;
float emissive : TEXCOORD6;
};

//------------------------------------------------------------

StatVertOut StaticVS (StatVertIn IN) {
StatVertOut OUT;

OUT.texcoords = IN.texcoords;

// Define % to Fog
float4 worldpos = mul (IN.pos, world);

#ifdef EXPFOG
float3 EyeVec = worldpos.xyz - EyePos.xyz;
float dist = length (EyeVec);
EyeVec /= dist;
#ifdef SCATTER
OUT.fog = getFog (EyeVec,dist);
#else
OUT.fog = float4 (skyfogblend (EyeVec.z), getFog (dist));
#endif
#else
float dist = length (worldpos.xyz - EyePos.xyz);
OUT.fog = getFog (dist);
#endif

// Define % to Blend
OUT.blend = saturate ((BlendEnd - dist) / (BlendEnd - BlendStart));

// Projection
OUT.pos = mul (worldpos, view);
OUT.pos = mul (OUT.pos, proj);

// Lighting
OUT.normal = normalize (IN.normal.xyz * 2 - 1); // Decompress
OUT.normal = normalize (mul (OUT.normal.xyz, (float3x3)world)); // Rotate normals but don't translate them
OUT.color = IN.color;
OUT.emissive = IN.normal.w; // Emissive stored in 4th value in normal vector


return OUT;
}

//------------------------------------------------------------

struct StatInstVertIn {
float4 pos : POSITION;
float4 normal : NORMAL;
float4 color : COLOR0;
float2 texcoords : TEXCOORD0;
float4 m1 : TEXCOORD1;
float4 m2 : TEXCOORD2;
float4 m3 : TEXCOORD3;
float4 m4 : TEXCOORD4;
};

//------------------------------------------------------------

StatVertOut StaticInstVS (StatInstVertIn IN) {
StatVertOut OUT;

OUT.texcoords = IN.texcoords;

// Pack instance transform
float4x4 worldmat = float4x4 (IN.m1, IN.m2, IN.m3, IN.m4);

// Define % to Fog
float4 worldpos = mul (IN.pos, worldmat);

#ifdef EXPFOG
float3 EyeVec = worldpos.xyz - EyePos.xyz;
float dist = length (EyeVec);
EyeVec /= dist;
#ifdef SCATTER
OUT.fog = getFog (EyeVec,dist);
#else
OUT.fog = float4 (skyfogblend (EyeVec.z), getFog (dist));
#endif
#else
float dist = length (worldpos.xyz - EyePos.xyz);
OUT.fog = getFog (dist);
#endif

// Define % to Blend
OUT.blend = saturate ((BlendEnd - dist) / (BlendEnd - BlendStart));

// Projection
OUT.pos = mul (worldpos, view);
OUT.pos = mul (OUT.pos, proj);

// Lighting
OUT.normal = normalize (IN.normal.xyz * 2 - 1); // Decompress
OUT.normal = normalize (mul (OUT.normal.xyz, (float3x3)world)); // Rotate normals but don't translate them
OUT.color = IN.color;
OUT.emissive = IN.normal.w; // Emissive stored in 4th value in normal vector

return OUT;
}

//------------------------------------------------------------

float4 StaticPS (StatVertOut IN): COLOR0 {
float4 Result = tex2D (s3, IN.texcoords);

// Lighting
float3 normal = normalize (IN.normal);
float3 diffuse = saturate (dot (-SunVec, normal)) * SunCol * IN.color.rgb;
float3 ambient = SunAmb * IN.color.rgb;
Result.rgb *= saturate (diffuse + ambient + IN.emissive);

// Fogging
#ifdef EXPFOG
#ifdef SCATTER
Result.rgb = applyfog( Result.rgb, IN.fog );
#else
Result.rgb = lerp (IN.fog.rgb, Result.rgb, IN.fog.a);
#endif
#else
Result.rgb = lerp (FogCol2, Result.rgb, IN.fog);
#endif

// Blending
Result.a = saturate (IN.color.a * Result.a * AlphaMultiplier) * IN.blend;

return Result;
}

//------------------------------------------------------------

struct StatRefVertOut {
float4 pos : POSITION;
float2 texcoords : TEXCOORD0;
float4 color : TEXCOORD1;
float3 normal : TEXCOORD2;
REFFOGTYPE fog : TEXCOORD3;
float height : TEXCOORD6;
};

//------------------------------------------------------------

StatRefVertOut StaticReflectionVS (StatVertIn IN) {
StatRefVertOut OUT;

OUT.texcoords = IN.texcoords;

float4 worldpos = mul (IN.pos, world);

// Define % to Fog
#if SHADER_MODEL >= 300
float3 EyeVec = float3 (worldpos.xy, TwiceWaterLevel - worldpos.z) - EyePos.xyz;
float dist = length (EyeVec);
EyeVec /= dist;

#ifdef EXPFOG
#ifdef SCATTER
OUT.fog = getFog_refl(EyeVec*float3(1,1,-1),dist);
#else
//OUT.fog = saturate (exp (-(max (0, worldpos.z) / (0.0001 + saturate (-EyeVec.z))) / ExpFogRangeMinusStart));
OUT.fog = saturate (exp (-(max (0, worldpos.z) / (0.0001 + saturate (-EyeVec.z))) / FogRangeMinusStart));
#endif
#else
OUT.fog = saturate (
getFog (dist) /
(0.001 + saturate ((FogRange - (EyePos.z - WaterLevel) / (0.001 + saturate (-EyeVec.z))) / (FogRangeMinusStart)))
);
#endif
#else
float dist = length (worldpos.xyz - EyePos.xyz);
OUT.fog = getFog (dist);
#endif

//// Define % to Blend
//OUT.blend = saturate ((BlendEnd - dist) / (BlendEnd - BlendStart));

// Projection
OUT.pos = mul (worldpos, view);
OUT.pos = mul (OUT.pos, proj);

// Lighting
OUT.normal = normalize (IN.normal.xyz * 2 - 1); // Decompress
OUT.normal = normalize (mul (OUT.normal, (float3x3)world)); // Rotate normals but don't translate them
OUT.color = IN.color;

// Figure hight of pixel in world coordinates
OUT.height = worldpos.z;

return OUT;
}

//------------------------------------------------------------

StatRefVertOut StaticReflectionInstVS (StatInstVertIn IN) {
StatRefVertOut OUT;

OUT.texcoords = IN.texcoords;

// Pack instance transform
float4x4 worldmat = float4x4 (IN.m1, IN.m2, IN.m3, IN.m4);

float4 worldpos = mul (IN.pos, worldmat);

// Define % to Fog
#if SHADER_MODEL >= 300
float3 EyeVec = float3 (worldpos.xy, TwiceWaterLevel - worldpos.z) - EyePos.xyz;
float dist = length (EyeVec);
EyeVec /= dist;

#ifdef EXPFOG
#ifdef SCATTER
OUT.fog = getFog_refl(EyeVec*float3(1,1,-1),dist);
#else
//OUT.fog = saturate (exp (-(max (0, worldpos.z) / (0.0001 + saturate (-EyeVec.z))) / ExpFogRangeMinusStart));
OUT.fog = saturate (exp (-(max (0, worldpos.z) / (0.0001 + saturate (-EyeVec.z))) / FogRangeMinusStart));
#endif
#else
OUT.fog = saturate (
getFog (dist) /
(0.001 + saturate ((FogRange - (EyePos.z - WaterLevel) / (0.001 + saturate (-EyeVec.z))) / (FogRangeMinusStart)))
);
#endif
#else
float dist = length (worldpos.xyz - EyePos.xyz);
OUT.fog = getFog (dist);
#endif

//// Define % to Blend
//OUT.blend = saturate ((BlendEnd - dist) / (BlendEnd - BlendStart));

// Projection
OUT.pos = mul (worldpos, view);
OUT.pos = mul (OUT.pos, proj);

// Lighting
OUT.normal = normalize (mul (IN.normal.xyz, (float3x3)worldmat));
OUT.color = IN.color;

// Figure height of pixel in world coordinates
OUT.height = worldpos.z;

return OUT;
}

//------------------------------------------------------------

float4 StaticReflectionPS (StatRefVertOut IN): COLOR0 {
// Clip to water plane
clip (IN.height + 4 - WaterLevel);
#ifdef SCATTER
clip (IN.fog.a - 0.001);
#else
clip (IN.fog - 0.001);
#endif

float4 Result = tex2D (s3, IN.texcoords);
clip (Result.a - 0.5);

// Lighting
float3 normal = normalize (IN.normal);
Result.rgb *= saturate ((saturate (dot (-SunVec, normal)) * SunCol + SunAmb) * IN.color.rgb);

// Fogging
#ifdef SCATTER
Result.rgb = applyfog(Result.rgb,IN.fog);
#else
Result.rgb = lerp (FogCol2, Result.rgb, IN.fog);
#endif

return float4 (Result.rgb, 1);
}

//------------------------------------------------------------

struct LowestLandVertOut {
float4 position : POSITION;
float4 pos : TEXCOORD0;
float2 texcoords : TEXCOORD1;
float3 light : COLOR0;
};

//------------------------------------------------------------

LowestLandVertOut LowestLandVS (in float4 pos : POSITION) {
LowestLandVertOut OUT;

OUT.position = mul (pos, world);
OUT.position = mul (OUT.position, view);
OUT.position = mul (OUT.position, proj);

OUT.pos = float4 (pos.xy - offset, pos.zw);

// Calculate texture coordinates
OUT.texcoords = OUT.pos.xy / 600;

// Lighting
OUT.light = saturate(-SunVec.z * SunCol);
OUT.light = saturate (OUT.light + SunAmb);

return OUT;
}

//------------------------------------------------------------

float4 LowestLandPS (in LowestLandVertOut IN): COLOR0 {
// Define % to Fog
float dist = length (IN.pos.xyz - EyePos.xyz);

float3 Result = tex2D (s3, IN.texcoords).rgb;
Result *= IN.light;

// Fogging
float fog;
fog = getFogAlpha (dist);

Result = lerp (FogCol2, Result, fog);

return float4 (Result, 1);
}

//------------------------------------------------------------

struct WaterVertOut {
float4 position : POSITION;
float4 pos : TEXCOORD0;
float2 texcoord1 : TEXCOORD1;
float2 texcoord2 : TEXCOORD2;
float2 texcoord3 : TEXCOORD3;
float4 screenpos : TEXCOORD5;
#if WAVEHEIGHT > 0
float4 screenposclamp : TEXCOORD7;
#endif
float w : TEXCOORD6;
};

//------------------------------------------------------------

WaterVertOut WaterVS (in float4 pos : POSITION) {
WaterVertOut OUT;

OUT.pos = float4 (pos.xy - offset, pos.zw);

// Calculate various texture coordinates
OUT.texcoord1 = OUT.pos.xy / 3900;
OUT.texcoord2 = OUT.pos.xy / 1104;
OUT.texcoord3 = OUT.pos.xy / 892;

#if WAVEHEIGHT > 0
float time = ticks / 2;

float height = tex3Dlod (s1, float4 (OUT.texcoord2, time, 0)).a - 0.5f;
float height2 = tex3Dlod (s1, float4 (OUT.texcoord1, time*0.56, 0)).a - 0.5f;

float dist = length (EyePos.xyz - OUT.pos.xyz);

//float addheight = WAVEHEIGHT * (lerp (height, height2, saturate (dist / 8000)) - 0.5f) * saturate (1 - dist / 6400) * saturate (dist / 200);
//abot float addheight = WAVEHEIGHT * (0.65*height * saturate (1 - dist / 8000) + height2) * saturate (1 - dist / 6400) * saturate (dist / 200);
float addheight = _windfactor2 * WAVEHEIGHT * (0.65*height * saturate (1 - dist / 8000) + height2) * saturate (1 - dist / 6400) * saturate (dist / 200);

float4 newPos = pos + float4 (0, 0, addheight, 0);

OUT.pos.zw = newPos.zw;

OUT.position = mul (newPos, world);
OUT.position = mul (OUT.position, view);
OUT.position = mul (OUT.position, proj);
OUT.w = OUT.position.w;

OUT.screenpos = mul (newPos , TexProj);
newPos = pos - float4 (0, 0, abs (addheight), 0);
OUT.screenposclamp = mul (newPos , TexProj);
#else
OUT.position = mul (pos, world);
OUT.position = mul (OUT.position, view);
OUT.position = mul (OUT.position, proj);
OUT.w = OUT.position.w;

OUT.screenpos = mul (pos, TexProj);
#endif

return OUT;
}

//------------------------------------------------------------

float3 GetFinalWaterNormal (float2 texcoord1, float2 texcoord2, float2 texcoord3, float dist, float2 IN_pos_xy) : NORMAL {
// Calculate the W texture coordinate based on the time that has passed
float time = ticks / 2;
float3 tex1 = float3(texcoord1, time*0.56);
float3 tex2 = float3(texcoord2, time);

// Blend together the normals from different sized areas of the same texture.
float2 far_normal = tex3D (s5, tex1).rg;
float2 close_normal = tex3D (s5, tex2).rg;
#ifdef MGE_DYNAMICRIPPLES
// add ripples
#if SHADER_MODEL >= 300
close_normal.rg += tex2D (s2, texcoord3).ba; // rain
close_normal.rg += tex2D (s8, (IN_pos_xy - RippleOrigin) / waveTexWorldSize).ba * 2 - 1.5; // player
#else
close_normal.rg += (tex2D (s2, texcoord3).ba // rain
+ tex2D (s8, (IN_pos_xy - RippleOrigin) / waveTexWorldSize).ba) * 2 - 2; // player
#endif
#endif
//float2 normal_R = lerp (close_normal, far_normal, saturate (dist / 8000)) * 2 - 1;
float2 normal_R = 0.65*(close_normal * 2 - 1) * saturate (1 - dist / 8000) + (far_normal * 2 - 1);

#if SEWERWAVE == 1 && SHADER_MODEL >= 300
//Add wave effect for each sewer location
if (dist < 7168) {
float ticksX = 8*ticks;
int i=0;
while ( i < 62) {
float d = length(EyePos.xy-wLoc[i]);
if (d > 65534) i=100;
else if ( d < 7168 ) {
d = length(IN_pos_xy-wLoc[i]);
if (d < 1280)
normal_R.rg += sin(fmod(d,128)/(128/6.283185307) - ticksX) / max((d*d)/20480,4);
}
i++;
}
i=0;
while ( i < 8) {
float d = length(EyePos.xy-wLoc2[i]);
if (d > 16384) i=100;
else if ( d < 7168 ) {
d = length(IN_pos_xy-wLoc2[i]);
if (d < 1280)
normal_R.rg += sin(fmod(d,128)/(128/6.283185307) - ticksX) / max((d*d)/20480,4);
}
i++;
}
}
#endif

return normalize(float3(normal_R,1));
}

//------------------------------------------------------------

float4 ReflectionShader (in WaterVertOut IN): COLOR0 {
// Calculate eye vector
float3 EyeVec = EyePos.xyz - IN.pos.xyz;
float dist = length (EyeVec);
EyeVec /= dist;

// Define % to Fog
#ifdef SCATTER
float4 fog = getFog_refl(-EyeVec, dist);
#else
float fog = getFog (dist);
#endif

// Calculate water normal
float3 normal = GetFinalWaterNormal (IN.texcoord1, IN.texcoord2, IN.texcoord3, dist, IN.pos.xy);

float2 Tex = IN.screenpos.xy / IN.w;

// reflection / refraction strength factor, wind strength increases distortion
#if SHADER_MODEL >= 300
//float2 reffactor = ((dist / 100 * _windfactor) + 0.1) * (normal.xy);
//float3 reffactor;
//reffactor.x = dot(-normal, float3(view[0][0],view[1][0],view[2][0]));
//reffactor.y = dot(-normal, float3(view[0][2],view[1][2],view[2][2]));
//reffactor.z = 1 - reffactor.y;
//reffactor *= ((dist / 100 * _windfactor) + 0.1).xxx;

// Distort refraction dependent on depth
float2 reffactor = 0.01 * _windfactor * normal.xy;
#else
// Distort refraction dependent on depth
float2 reffactor = 0.02 * normal.xy;
#endif

float2 newscrpos = Tex + reffactor.yx;

// Sample depth texture
float depth = tex2D (s7, newscrpos).r - IN.w;
newscrpos = Tex + saturate (depth / 100) * reffactor.yx;

// Sample refraction texture
float3 Refract = tex2D (s4, newscrpos).rgb;

#if SHADER_MODEL >= 300
// Get distorted depth
//depth = max (0, tex2D (s7, newscrpos).r - IN.w);
depth = tex2D (s7, newscrpos).r - IN.w;
if(depth < -1) depth = 1E6;
depth /= dot (-EyeVec, float3 (view [0][2], view [1][2], view [2][2]));

//abot float depthscale = saturate (exp (-(depth) / 800));
float depthscale = saturate (exp (-(depth) / 1100));
float shorefactor = pow (depthscale, 25);

#ifdef SCATTER
float3 depthcolor = applyfog(_depthcolor,fog);
#else
float3 depthcolor = lerp (FogCol2, _depthcolor, fog);
#endif

// Make transition between actual refraction image and depth color depending on water depth
Refract = lerp (depthcolor, Refract, 0.8 * depthscale + 0.2 * shorefactor);

// Sample reflection texture
float3 Reflect = {0, 0, 0};

// float totalalpha;

if (EyePos.z < WaterLevel - 4) {
Reflect = _depthcolor;
} else {
#ifdef WATERBLUR
float blurwidth = (1 - EyeVec.z) * 0.005;

float2 scrpos =
#if WAVEHEIGHT > 0
IN.screenposclamp.xy / IN.w
#else
Tex
#endif
+ float2(-2.5 * reffactor.x, 0.0015+abs (reffactor.y));

// unfolded blurring allows for better optimization
float2 shift = blurwidth * float2 (1, 0);
Reflect += 0.100 * (tex2D (s0, scrpos + shift).rgb
+ tex2D (s0, scrpos - shift).rgb);
shift = blurwidth * float2 (0.67, 0.33);
Reflect += 0.115 * (tex2D (s0, scrpos + shift).rgb
+ tex2D (s0, scrpos - shift).rgb);
shift = blurwidth * float2 (0.33, -0.33);
Reflect += 0.135 * (tex2D (s0, scrpos + shift).rgb
+ tex2D (s0, scrpos - shift).rgb);
shift = float2 (0.0, blurwidth * 0.67);
Reflect += 0.150 * (tex2D (s0, scrpos + shift).rgb
+ tex2D (s0, scrpos - shift).rgb);

#else
Reflect = tex2D (s0,
#if WAVEHEIGHT > 0
IN.screenposclamp.xy / IN.w
#else
Tex
#endif
+ float2 (-2.5 * reffactor.x, 0.0015+abs (reffactor.y)));
#endif
}

#ifdef SCATTER
//Reflect = applyfog(Reflect, fog);
Reflect = lerp (Reflect, applyfog(Reflect, fog),saturate((EyePos.z-WaterLevel)/7168.0));
float3 adjustnormal = lerp (float3 (0, 0, 0.1), normal, pow (saturate (1.05 * fog.a), 2));
#else
Reflect = lerp (FogCol2, Reflect, fog);
float3 adjustnormal = lerp (float3 (0, 0, 0.1), normal, pow (saturate (1.05 * fog), 2));
#endif

adjustnormal = lerp (adjustnormal, float3 (0, 0, 1.0), (1 - EyeVec.z) * (1 - saturate (1 / (dist / 1000 + 1))));

float fresnel = dot (EyeVec, adjustnormal);
fresnel = 0.02 + pow (saturate (0.9988 - 0.28 * fresnel), 16);
float3 Result = lerp (Refract, Reflect, fresnel);

// Specular lighting
float reflection = saturate (1.0025 * dot (EyeVec, reflect (-SunPos, normal)));
float3 spec = SunCollf * (pow (reflection, 150) + 0.07 * pow (reflection, 4));


// smooth transition at shore line
#ifdef SCATTER
Result = lerp (Result + spec * fog.a, Refract, shorefactor * fog.a);
#else
Result = lerp (Result + spec * fog, Refract, shorefactor * fog);
#endif
#else
// Make transition between actual refraction image and depth color depending on water depth
Refract = lerp (Refract, _depthcolor, saturate (depth / 1500 + 0.3));

float3 Reflect = tex2D (s0, Tex - float2 (2.5 * reffactor.x, -abs (reffactor.y))) / 2;

float fresnel = saturate (dot (EyeVec, float3 (0, 0, 1)) * 1.5);
float3 Result = lerp (Reflect, Refract, fresnel);

//Specular lighting
float reflection = saturate (dot (EyeVec, reflect (-SunPos, normal)));
float3 spec = SunCollf * pow (reflection, 150);

// Additional Specular
spec += pow (dot (normal, float3 (0, 0, 1)), 100) * SunAmb / 12; // gives water a shiny look

// smooth transition at shore line
Result += spec;

Result = lerp (FogCol2, Result, fog);
#endif

return float4 (Result, 1);
}

//------------------------------------------------------------

float4 NonReflectionShader (in WaterVertOut IN): COLOR0 {
// Calculate eye vector
float3 EyeVec = (EyePos - IN.pos.xyz);
float dist = length (EyeVec);
EyeVec /= dist;

// Define % to Fog
//float fog = saturate ((FogRange - dist) / FogRangeMinusStart);
float fog = getFogAlpha (dist);

// Calculate water normal
float3 normal = GetFinalWaterNormal (IN.texcoord1, IN.texcoord2, IN.texcoord3, dist, IN.pos.xy);

float2 Tex = IN.screenpos.xy / IN.w;

// reflection / refraction strength factor, wind strength increases distortion
#if SHADER_MODEL >= 300
float2 reffactor = 0.008 * _windfactor * normal.xy;
#else
float2 reffactor = 0.02 * normal.xy;
#endif

// Distort refraction dependent on depth
float2 newscrpos = Tex + reffactor.yx;

// Sample depth texture
float depth = max (0, tex2D (s7, newscrpos).r - IN.w);
newscrpos = Tex + saturate (depth / 100) * reffactor.yx;

// Sample refraction texture
float3 Refract = tex2D (s4, newscrpos).rgb;

#if SHADER_MODEL >= 300
// Get distorted depth
depth = max (0, tex2D (s7, newscrpos).r - IN.w);
depth /= dot (-EyeVec, float3 (view [0][2], view [1][2], view [2][2]));

float depthscale = saturate (exp (-depth / 800));
float shorefactor = pow (depthscale, 25);

// Make transition between actual refraction image and depth color depending on water depth
Refract = lerp (_depthcolor, Refract, 0.8 * depthscale + 0.2 * shorefactor);

float fresnel = dot (EyeVec, lerp (normal, float3 (0, 0, 1), (1 - EyeVec.z) * (1 - exp (-dist / 2500)))) * fog;
fresnel = 0.02 + pow (saturate (0.9988 - 0.28 * fresnel), 16);

float3 Reflect = (FogCol2 + SkyCol) * 0.4;
if (SunVec.z > 0.9) {
Reflect = FogCol2 * 0.55;
}
Reflect = lerp (FogCol2, Reflect, fog);

float3 Result = lerp (Refract, Reflect, fresnel);

// Specular lighting
float reflection = saturate (1.0025 * dot (EyeVec, reflect (-SunPos, normal)));
float3 spec = SunCollf * (pow (reflection, 150) + 0.07 * pow (reflection, 4)) * fog;

Result = lerp (Result + spec, Refract, shorefactor * fog);
#else
// Make transition between actual refraction image and depth color depending on water depth
Refract = lerp (Refract, _depthcolor, saturate (depth / 1500 + 0.3));

float fresnel = saturate(dot(EyeVec,float3(0,0,1)));

float3 Reflect = SkyCol / 2;

float3 Result = lerp (Reflect, Refract, saturate(fresnel*(depth+2)));

//Specular lighting
float reflection = saturate (1.0025 * dot (EyeVec, reflect (-SunPos, normal)));
float3 spec = SunCollf * pow (reflection, 150);

// Additional Specular
spec += pow (dot (normal, float3 (0, 0, 1)), 100) * SunAmb / 12; // gives water a shiny look

Result += spec;

//Fogging
Result = lerp (FogCol2, Result, fog);
#endif

return float4 (Result, 1);
}

//------------------------------------------------------------

float4 UnderWaterPS (in WaterVertOut IN): COLOR0 {
// Calculate eye vector
float3 EyeVec = (EyePos - IN.pos.xyz);
float dist = length (EyeVec);
EyeVec /= dist;

// Calculate water normal
float3 normal = -GetFinalWaterNormal (IN.texcoord1, IN.texcoord2, IN.texcoord3, dist, IN.pos.xy);

float2 Tex = IN.screenpos.xy / IN.w;

// Define % to Fog
// #ifdef EXPFOG
// float fog = exp (-2 * dist / FogRange);
// #else
// float fog = saturate (1 - (dist / FogRange));
// fog *= fog;
// #endif
float fog = getFogAlpha (dist);

#if SHADER_MODEL >= 300
// reflection / refraction strength factor, wind strength increases distortion
// float2 reffactor = -((dist / 20 * (_windfactor)) + 0.25) * float2 (
// dot (normal, float3 (view [0][0], view [1][0], view [2][0])),
// dot (normal, float3 (view [0][1], view [1][1], view [2][1]))
// );
float2 reffactor = 0.016 * _windfactor * normal.xy;
#else
float2 reffactor = 0.05 * normal.xy;
#endif

// Sample depth texture
float depth = max (0, tex2D (s7, Tex + reffactor.xy).r - IN.w);
float depthfactor = saturate (depth / 150);

#if SHADER_MODEL >= 300
depth = max (0, tex2D (s7, Tex + depthfactor * reffactor.xy).r - IN.w);
#else
depth = tex2D (s7, Tex + depthfactor * reffactor.xy).r - IN.w;
#endif

// Sample refraction texture
float3 Refract = tex2D (s4, Tex + depthfactor * reffactor.xy).rgb;

depthfactor = saturate (depth / 150);

// Specular lighting
float reflection = saturate (1.005 * dot (EyeVec, reflect (float3 (-SunPos.x, -SunPos.y, SunPos.z), normal)));
float3 Specular = saturate (1.5 * SunCollf) * (pow (reflection, 120) + 0.07 * pow (reflection, 2));

#if SHADER_MODEL >= 300
Refract += Specular * depthfactor * fog;
#else
Refract += Specular;
#endif

// fresnel factor
// float fresnel = saturate (dot (EyeVec, normal / float3 ((1.0 + 0.5 * normal.z).xx, 1)));
float fresnel = saturate (dot (EyeVec, normal));
fresnel = 0.4 * pow (saturate (1.3 - fresnel), 8) * fog;

#if SHADER_MODEL >= 300
if (SunVec.z > 0.9) fresnel *= 0.6;
#endif

float3 Result = Refract * (1 - fresnel * depthfactor);

// Realistic Fresnel
// fresnel = saturate (0.015 / max (0.01, fresnel - 0.645) - 0.02);
// Refract = tex2Dproj (s4, IN.screenpos + float4 (reffactor.xy, 0, 0) / (1.001 - fresnel)).rgb;
// float3 Result = lerp (Refract, FogCol2, fresnel);

return float4 (Result, 1);
}

//------------------------------------------------------------

struct LandVertOut {
float4 pos: POSITION;
float2 texcoord: TEXCOORD1;
float3 position: TEXCOORD2;
FOGTYPE fog : TEXCOORD3;
};

//------------------------------------------------------------

LandVertOut LandscapeVertexShader (float4 pos: POSITION, float2 texcoord: TEXCOORD0) {
LandVertOut OUT;

// Define % to Fog
#ifdef EXPFOG
float3 EyeVec = pos.xyz - EyePos.xyz;
float dist = length (EyeVec);
EyeVec /= dist;
#ifdef SCATTER
OUT.fog = getFog (EyeVec,dist);
#else
OUT.fog = float4 (skyfogblend (EyeVec.z), getFog (dist));
#endif
#else
float dist = length (pos.xyz - EyePos.xyz);
OUT.fog = getFog (dist);
#endif

// Lower vertices that are close to the camera to ensure they are always below it
float disp = lerp (200, 0, saturate (dist / 2000));
pos.z -= disp;

// OUT.pos = mul (pos, worldviewproj);
OUT.pos = mul (pos, world);
OUT.pos = mul (OUT.pos, view);
OUT.pos = mul (OUT.pos, proj);

OUT.texcoord = texcoord;
OUT.position = pos.xyz;

return OUT;
}

//------------------------------------------------------------

float4 LandscapePixelShader (in LandVertOut IN): COLOR0 {
// Normalize incoming normal
float3 normal = normalize (tex2D (s1, IN.texcoord).rgb * 2 - 1);

// World Texture
float3 Result = tex2D (s3, IN.texcoord).rgb;

// Detail Texture
float detail = tex2D (s2, IN.texcoord * 1064).g + 0.5;
detail *= tex2D (s2, IN.texcoord * 333).g + 0.5;
detail *= tex2D (s2, IN.texcoord * 90).g + 0.5;

// Lighting
Result *= detail * saturate ((saturate (dot (-SunVec, normal)) * SunCol) + SunAmb);

// Define % to Fog
#ifdef EXPFOG
#ifdef SCATTER
Result = applyfog( Result, IN.fog );
#else
Result = lerp (IN.fog.rgb, Result, IN.fog.a);
#endif
return float4 (Result, 1 - IN.fog.a);
#else
Result = lerp (FogCol2, Result, IN.fog);
return float4 (Result, 1 - IN.fog);
#endif
}

//------------------------------------------------------------

struct LandRefVertOut {
float4 pos: POSITION;
float2 texcoord: TEXCOORD1;
REFFOGTYPE fog : TEXCOORD2;
float height : TEXCOORD3;
};

//------------------------------------------------------------

LandRefVertOut LandscapeRefVS (float4 pos: POSITION, float2 texcoord: TEXCOORD0) {
LandRefVertOut OUT;

#if SHADER_MODEL >= 300
//// Lower vertices so there are fewer seams visible in the reflection
// pos.z -= 20 * saturate (1 - (pos.z / 100));
float3 EyeVec = float3 (pos.xy, TwiceWaterLevel - pos.z) - EyePos.xyz;
float dist = length (EyeVec);
EyeVec /= dist;

// Define % to Fog
#ifdef EXPFOG
#ifdef SCATTER
OUT.fog = getFog_refl(EyeVec*float3(1,1,-1),dist);
#else
//OUT.fog = saturate (exp ( -(max (0, pos.z) / (0.0001 + saturate (-EyeVec.z))) / ExpFogRangeMinusStart));
OUT.fog = saturate (exp ( -(max (0, pos.z) / (0.0001 + saturate (-EyeVec.z))) / FogRangeMinusStart));
#endif
#else
OUT.fog = saturate (
getFog (dist) /
(0.001 + saturate ((FogRange - (EyePos.z - WaterLevel) / (0.001 + saturate (-EyeVec.z))) / FogRangeMinusStart))
);
#endif
#else
// Lower vertices so there are fewer seams visible in the reflection
// pos.z -= 100;

// Define % to Fog
OUT.fog = getFog (length (pos.xyz - EyePos.xyz));
#endif

// OUT.pos = mul (pos, worldviewproj);
OUT.pos = mul (pos, world);
OUT.pos = mul (OUT.pos, view);
OUT.pos = mul (OUT.pos, proj);
OUT.texcoord = texcoord;

// Define height of pixel for clipping to water plane
OUT.height = pos.z;

return OUT;
}

//------------------------------------------------------------

float4 LandscapeRefPS (in LandRefVertOut IN): COLOR0 {
// Clip to water plane
clip (IN.height + 4 - WaterLevel);
#ifdef SCATTER
clip (IN.fog.a - 0.001);
#else
clip (IN.fog - 0.001);
#endif

// Normalize incoming normal
float3 normal = normalize (tex2D (s1, IN.texcoord).rgb * 2 - 1);

// World Texture
float3 Result = tex2D (s3, IN.texcoord).rgb;

// Detail Texture
float detail = tex2D (s2, IN.texcoord * 1064).g + 0.5;
detail *= tex2D (s2, IN.texcoord * 333).g + 0.5;
detail *= tex2D (s2, IN.texcoord * 90).g + 0.5;

// Lighting
Result *= detail * saturate ((saturate (dot (-SunVec, normal)) * SunCol) + SunAmb);

// let reflections fade to water color
#ifdef SCATTER
Result.rgb = applyfog(Result.rgb,IN.fog);
#else
Result.rgb = lerp (FogCol2, Result.rgb, IN.fog);
#endif

//return float4 (Result, saturate (3.5 * IN.fog));
return float4 (Result, 1);
}

//------------------------------------------------------------

struct GrassVertIn {
float4 pos : POSITION;
float3 normal : NORMAL;
float4 color : COLOR0;
float2 texcoords : TEXCOORD0;
};

//------------------------------------------------------------

struct GrassVertOut {
float4 pos : POSITION;
float2 texcoords : TEXCOORD0;
float3 color : COLOR0;
FOGTYPE fog : TEXCOORD1;
float4 screenpos: TEXCOORD4;
float blend : TEXCOORD5;
};

//------------------------------------------------------------

GrassVertOut GrassVS (GrassVertIn IN) {
GrassVertOut OUT;

OUT.texcoords = IN.texcoords;

// Animate grass
float4 worldpos = mul (IN.pos, world);

float height = clamp (IN.pos.z, 0, 100) / 100;

float2 wind = WindVec * 25 + 2.5;

float2 pos_ticks1 = worldpos.xy / 1000 + ticks;
float2 pos_ticks2 = worldpos.xy / 750 + ticks * 2;
float2 pos_ticks3 = worldpos.xy / 500 + ticks * 3;
float2 pos_ticks4 = worldpos.xy / 200 + ticks * 4;

//player bending grass
float eyedist = length(EyePos.xyz - PlayerPos.xyz);
float2 distxy = worldpos.xyz - PlayerPos.xyz;
float gdist = length(distxy);
float2 bend_ticks1 = distxy/1000/gdist;

if (eyedist > 150) { // 3rd person view
if ( gdist < 80 ) {
worldpos.xy += bend_ticks1/abs(bend_ticks1)*cos(bend_ticks1)*height/(25+gdist)*3500;
}
}
else { // 1st person view
if ( gdist < 130 ) {
worldpos.xy += bend_ticks1/abs(bend_ticks1)*cos(bend_ticks1)*height/(25+gdist)*5000;
}
}

worldpos.xy += (sin(pos_ticks1) + cos(pos_ticks2) + sin(pos_ticks3) + cos(pos_ticks4)) * height * wind;

// Define % to Fog
#ifdef EXPFOG
float3 EyeVec = worldpos.xyz - EyePos.xyz;
float dist = length (EyeVec);
EyeVec /= dist;
#ifdef SCATTER
OUT.fog = getFog (EyeVec,dist);
#else
OUT.fog = float4 (skyfogblend (EyeVec.z), getFog (dist));
#endif
#else
float dist = length (worldpos.xyz - EyePos.xyz);
OUT.fog = getFog (dist);
#endif

// Define % to Blend
OUT.blend = saturate ((BlendEnd - dist) / (BlendEnd - BlendStart));

// Projection
OUT.pos = mul (worldpos, view);
OUT.pos = mul (OUT.pos, proj);

// Texture Projection
OUT.screenpos = mul (worldpos, TexProj);

// Lighting
OUT.color = (SunCol * 0.25) + SunAmb;

return OUT;
}

//------------------------------------------------------------

GrassVertOut GrassInstVS (StatInstVertIn IN) {
GrassVertOut OUT;

// Pack instance transform
float4x4 worldmat = float4x4 (IN.m1, IN.m2, IN.m3, IN.m4);

OUT.texcoords = IN.texcoords;

// Define % to Fog
float4 worldpos = mul (IN.pos, worldmat);

#ifdef EXPFOG
float3 EyeVec = worldpos.xyz - EyePos.xyz;
float dist = length (EyeVec);
EyeVec /= dist;
#ifdef SCATTER
OUT.fog = getFog (EyeVec,dist);
#else
OUT.fog = float4 (skyfogblend (EyeVec.z), getFog (dist));
#endif
#else
float dist = length (worldpos.xyz - EyePos.xyz);
OUT.fog = getFog (dist);
#endif

OUT.blend = 1 - (saturate ((GrassDist - dist) / (GrassDist / 5)));
OUT.blend += 0.4;
OUT.screenpos = 0;

// Animate grass
float height = clamp (IN.pos.z, 0, 100) / 100;

float2 wind = WindVec * 1.6666666;

float2 pos_ticks1 = worldpos.xy / 1000 + ticks;
float2 pos_ticks2 = worldpos.xy / 750 + ticks * 2;
float2 pos_ticks3 = worldpos.xy / 500 + ticks * 3;
float2 pos_ticks4 = worldpos.xy / 250 + ticks * 4;

//player bending grass
float eyedist = length(EyePos.xyz - PlayerPos.xyz);
float2 distxy = worldpos.xyz - PlayerPos.xyz;
float gdist = length(distxy);
float2 bend_ticks1 = distxy/1000/gdist;

if (eyedist > 150) { // 3rd person view
if ( gdist < 80 ) {
worldpos.xy += bend_ticks1/abs(bend_ticks1)*cos(bend_ticks1)*height/(25+gdist)*3500;
}
}
else { // 1st person view
if ( gdist < 130 ) {
worldpos.xy += bend_ticks1/abs(bend_ticks1)*cos(bend_ticks1)*height/(25+gdist)*3500;
}
}

worldpos.xy += (sin(pos_ticks1) + cos(pos_ticks2) + sin(pos_ticks3) + cos(pos_ticks4)) * height * wind;

// Projection
OUT.pos = mul (worldpos, view);
OUT.pos = mul (OUT.pos, proj);

// Lighting
OUT.color = (SunCol * 0.25) + SunAmb;

return OUT;
}

//------------------------------------------------------------

float4 GrassPS (GrassVertOut IN): COLOR0 {
float4 Result = tex2D (s3, IN.texcoords);
// clip (Result.a - 0.4);

// Lighting
Result.rgb *= IN.color;

// Fogging
#ifdef EXPFOG
#ifdef SCATTER
Result.rgb = applyfog( Result.rgb, IN.fog );
#else
Result.rgb = lerp (IN.fog.rgb, Result.rgb, IN.fog.a);
#endif
#else
Result.rgb = lerp (FogCol2, Result.rgb, IN.fog);
#endif


// Blending
Result.a = saturate (Result.a * AlphaMultiplier) * IN.blend;
return float4 (Result.rgb, Result.a);
}

//------------------------------------------------------------

struct BlendDepthVertIn {
float4 pos : POSITION;
float2 texcoord : TEXCOORD0;
};

//------------------------------------------------------------

struct ScreenVertOut {
float4 pos: POSITION;
float2 texcoord : TEXCOORD0;
};

//------------------------------------------------------------

ScreenVertOut ScreenQuadVS (in BlendDepthVertIn IN) {
ScreenVertOut OUT;

OUT.pos = mul (IN.pos, world);
OUT.pos = mul (OUT.pos, view);
OUT.pos = mul (OUT.pos, proj);

OUT.texcoord = IN.texcoord;

return OUT;
}

//------------------------------------------------------------

float4 BlendDepthPS (ScreenVertOut IN): COLOR0 {
// return float4 (tex2D (s0, IN.texcoord).rgb, 1);

float3 color = tex2D (s4, IN.texcoord).rgb;
float depth = tex2D (s0, IN.texcoord).r;
depth = min( tex2D (s0, IN.texcoord + float2(PixelWidth, 0)).r, depth);
depth = min( tex2D (s0, IN.texcoord + float2(-PixelWidth, 0)).r, depth);
depth = min( tex2D (s0, IN.texcoord + float2(0, PixelHeight)).r, depth);
depth = min( tex2D (s0, IN.texcoord + float2(0, -PixelHeight)).r, depth);

//// Display depth buffer for testing
// depth = 1 - saturate (depth / FogRange);
// return float4 (depth, depth, depth, 1);

// Define % to Blend
float blend = saturate ((BlendEnd - depth) / (BlendEnd - BlendStart));

//// Display blend for testing
//return float4( blend, blend, blend, 1 );

return float4 (color, 1 - blend);
}

//------------------------------------------------------------

float4 ClearDepthPS (ScreenVertOut IN): COLOR0 {
return float4 (FLT_MAX / 2, 1, 1, 1);
}

//------------------------------------------------------------

// float blur_weights [4] = { 0.47442968, 0.23392642, 0.02804153, 0.00081723 };

float blur_weights [7] = { 0.199471, 0.176033, 0.120985, 0.064759, 0.026995, 0.008764, 0.002216 };

float2 TwelveKernel [12];

//------------------------------------------------------------

float4 HorizontalBlurPS (ScreenVertOut IN): COLOR0 {
float4 Original = tex2D (s4, IN.texcoord);
float3 Blurred = 0;
float total_weight = 0;

// Early out to prevent night sky blur - tetchy
if (Original.a >= 0.9999) {
return Original;
} else {

for (int i = 0; i < 12; ++i) {
float4 Current = tex2D (s4, IN.texcoord + TwelveKernel [i]);
float weight = saturate (Original.a * Current.a);
Blurred += Current.rgb * weight;
total_weight += weight;
}
Blurred = (Blurred + Original.rgb) / (total_weight + 1.0);

return float4 (Blurred, Original.a);
}
}

//------------------------------------------------------------

float4 VerticalBlurPS (ScreenVertOut IN): COLOR0 {
float4 orig_color = tex2D (s4, IN.texcoord);

// return float4 (orig_color.a, orig_color.a, orig_color.a, orig_color.a);

// Early out to prevent night sky blur - tetchy
if (orig_color.a >= 0.9999) {
return orig_color;
} else {

float2 offset = float2 (0, PixelHeight);

float4 color = 0;

color += tex2D (s4, IN.texcoord - offset * 6) * blur_weights [6];
color += tex2D (s4, IN.texcoord - offset * 5) * blur_weights [5];
color += tex2D (s4, IN.texcoord - offset * 4) * blur_weights [4];
color += tex2D (s4, IN.texcoord - offset * 3) * blur_weights [3];
color += tex2D (s4, IN.texcoord - offset * 2) * blur_weights [2];
color += tex2D (s4, IN.texcoord - offset) * blur_weights [1];
color += orig_color * blur_weights [0];
color += tex2D (s4, IN.texcoord + offset) * blur_weights [1];
color += tex2D (s4, IN.texcoord + offset * 2) * blur_weights [2];
color += tex2D (s4, IN.texcoord + offset * 3) * blur_weights [3];
color += tex2D (s4, IN.texcoord + offset * 4) * blur_weights [4];
color += tex2D (s4, IN.texcoord + offset * 5) * blur_weights [5];
color += tex2D (s4, IN.texcoord + offset * 6) * blur_weights [6];

float blur = saturate (color.a * orig_color.a);

//// Don't let the sky get too blurry// test no longer needed - tetchy
// if (orig_color.a <= 0.0001) {
// blur = max (0.75, blur);
// }

color.rgb = lerp (color.rgb, orig_color.rgb, blur);

return float4 (color.rgb, orig_color.a);
}
}

//------------------------------------------------------------

float4 CopyAndSetAlphaPS (ScreenVertOut IN): COLOR0 {
float3 color = tex2D (s4, IN.texcoord).rgb;

return float4 (color, 1);
}

//------------------------------------------------------------

struct RenderDepthVertOut {
float4 pos: POSITION;
float4 position: TEXCOORD0;
// float4 col: COLOR0;
float2 texcoords: TEXCOORD1;
};

//------------------------------------------------------------

RenderDepthVertOut GrassDepthVS (GrassVertIn IN) {
RenderDepthVertOut OUT;

OUT.texcoords = IN.texcoords;

// Animate grass
float4 worldpos = mul (IN.pos, world);

float height = clamp (IN.pos.z, 0, 100) / 100;

float2 wind = WindVec * 25 + 2.5;

float2 pos_ticks1 = worldpos.xy / 1000 + ticks;
float2 pos_ticks2 = worldpos.xy / 750 + ticks * 2;
float2 pos_ticks3 = worldpos.xy / 500 + ticks * 3;
float2 pos_ticks4 = worldpos.xy / 200 + ticks * 4;

//player bending grass
float eyedist = length(EyePos.xyz - PlayerPos.xyz);
float2 distxy = worldpos.xyz - PlayerPos.xyz;
float gdist = length(distxy);
float2 bend_ticks1 = distxy/1000/gdist;

if (eyedist > 150) { // 3rd person view
if ( gdist < 80 ) {
worldpos.xy += bend_ticks1/abs(bend_ticks1)*cos(bend_ticks1)*height/(25+gdist)*3500;
}
}
else { // 1st person view
if ( gdist < 130 ) {
worldpos.xy += bend_ticks1/abs(bend_ticks1)*cos(bend_ticks1)*height/(25+gdist)*3500;
}
}

worldpos.xy += (sin(pos_ticks1) + cos(pos_ticks2) + sin(pos_ticks3) + cos(pos_ticks4)) * height * wind;

// Projection
OUT.pos = mul (worldpos, view);
OUT.pos = mul (OUT.pos, proj);

OUT.position = OUT.pos;

return OUT;
}

//------------------------------------------------------------

float4 GrassDepthPS (RenderDepthVertOut IN): COLOR0 {
// Apply alpha testing
float alpha = tex2D (s3, IN.texcoords).a;
clip (alpha - 0.5);

return float4 (IN.position.w, 1, 1, 1);
}

//------------------------------------------------------------

RenderDepthVertOut GrassDepthInstVS (StatInstVertIn IN) {
RenderDepthVertOut OUT;

// Pack instance transform
float4x4 worldmat = float4x4 (IN.m1, IN.m2, IN.m3, IN.m4);

OUT.texcoords = IN.texcoords;

float4 worldpos = mul (IN.pos, worldmat);

// Animate grass
float height = clamp (IN.pos.z, 0, 100) / 100;

float2 wind = WindVec * 1.6666666;

float2 pos_ticks1 = worldpos.xy / 1000 + ticks;
float2 pos_ticks2 = worldpos.xy / 750 + ticks * 2;
float2 pos_ticks3 = worldpos.xy / 500 + ticks * 3;
float2 pos_ticks4 = worldpos.xy / 250 + ticks * 4;

//player bending grass
float eyedist = length(EyePos.xyz - PlayerPos.xyz);
float2 distxy = worldpos.xyz - PlayerPos.xyz;
float gdist = length(distxy);
float2 bend_ticks1 = distxy/1000/gdist;

if (eyedist > 150) { // 3rd person view
if ( gdist < 80 ) {
worldpos.xy += bend_ticks1/abs(bend_ticks1)*cos(bend_ticks1)*height/(25+gdist)*3500;
}
}
else { // 1st person view
if ( gdist < 130 ) {
worldpos.xy += bend_ticks1/abs(bend_ticks1)*cos(bend_ticks1)*height/(25+gdist)*3500;
}
}

worldpos.xy += (sin(pos_ticks1) + cos(pos_ticks2) + sin(pos_ticks3) + cos(pos_ticks4)) * height * wind;

// Projection
OUT.pos = mul (worldpos, view);
OUT.pos = mul (OUT.pos, proj);

OUT.position = OUT.pos;

return OUT;
}

//------------------------------------------------------------

struct CausticsVertOut {
float4 pos: POSITION;
float2 tex : TEXCOORD0;
};

//------------------------------------------------------------

CausticsVertOut CausticsVS (in BlendDepthVertIn IN) {
CausticsVertOut OUT;
OUT.pos = mul (IN.pos, proj);
OUT.tex = IN.texcoord;
return OUT;
}

//------------------------------------------------------------

float4 CausticsPS (in CausticsVertOut IN): COLOR0 {
float3 color = tex2D(s4, IN.tex);

float depth = tex2D( s7, IN.tex ).r;
float fog = getFogAlpha(depth);
float blend = saturate( (BlendEnd - depth) / (BlendEnd - BlendStart) );

float3 eyevec = float3(view[0][2],view[1][2],view[2][2]);
eyevec += (1/proj[0][0] * (2*IN.tex.x-1)).xxx * float3(view[0][0],view[1][0],view[2][0]);
eyevec += (-1/proj[1][1] * (2*IN.tex.y-1)).xxx * float3(view[0][1],view[1][1],view[2][1]);

float3 uwpos = EyePos + eyevec * depth;
uwpos.z -= WaterLevel;
float sunraypath = (uwpos.z / SunVec.z);
float caust = tex3D (s5, float3( (uwpos - SunVec * sunraypath).xy / 1104, ticks/2) ).b;
color *= 1.00 + caust * blend * ( max (-uwpos.z, 0) * saturate(exp (uwpos.z / 400)) ) * fog * fog * cauststr;

return float4(color,1);
}

//------------------------------------------------------------

ScreenVertOut WaveVS (in BlendDepthVertIn IN) {
ScreenVertOut OUT;
OUT.pos = mul (IN.pos, proj);
OUT.texcoord = IN.texcoord;
return OUT;
}

//------------------------------------------------------------

static const float waveTexRcpRes2 = 1.5 * waveTexRcpRes;

//------------------------------------------------------------

float4 WavePS (in float2 Tex : TEXCOORD0): COLOR0 {
float4 c = 2 * tex2D (s6, Tex) - (1.0).xxxx;
float4 ret = {0, c.r, 0, 0};

float4 n = {
tex2D (s6, Tex + float2 (waveTexRcpRes, 0)).r,
tex2D (s6, Tex + float2 (-waveTexRcpRes, 0)).r,
tex2D (s6, Tex + float2 (0, waveTexRcpRes)).r,
tex2D (s6, Tex + float2 (0, -waveTexRcpRes)).r
};
float4 n2 = {
tex2D (s6, Tex + float2 (waveTexRcpRes2, 0)).r,
tex2D (s6, Tex + float2 (-waveTexRcpRes2, 0)).r,
tex2D (s6, Tex + float2 (0, waveTexRcpRes2)).r,
tex2D (s6, Tex + float2 (0, -waveTexRcpRes2)).r
};

n = 2 * n - (1.0).xxxx;
// n2 = 2 * n2 - (1.0).xxxx;

float nsum = n.x + n.y + n.z + n.w;

// dampened discrete two - dimensional wave equation
// red channel: u (t)
// green channel: u (t - 1)
// u (t + 1) = (1 - udamp) * u (t) + a * (nsum - 4 * u (t)) + (1 - vdamp) * (u (t) - u (t - 1))
// = a * nsum + ((2 - udamp - vdamp) - 4 * a) * u (t) - (1 - vdamp) * u (t - 1);

#if SHADER_MODEL >= 300
ret.r = 0.14 * nsum + (1.96 - 0.56) * c.r - 0.98 * c.g;
#else
ret.r = 0.10 * nsum + (1.96 - 0.40) * c.r - 0.98 * c.g;
#endif

// if (abs (ret.r) < 0.01) ret.r = 0;
// if (abs (ret.g) < 0.01) ret.g = 0;

// calculate normal map
ret.ba = 2 * (n.xy - n.zw) + (n2.xy - n2.zw);

ret = 0.5f * ret + (0.5f).xxxx;

return ret;
}

//------------------------------------------------------------

static const float playerWaveSize = 12.0f / waveTexWorldSize; // 12 world units radius

//------------------------------------------------------------

float4 PlayerWavePS (in float2 Tex : TEXCOORD0): COLOR0 {
float4 ret = tex2D (s6, Tex);
float wavesize = (1.0 + 0.055 * sin (16 * ticks) + 0.065 * sin (12.87645 * ticks)) * playerWaveSize;
ret.rg *= saturate (2 * abs (length (Tex - RippleOrigin) / wavesize - 1));
return ret;
}

//------------------------------------------------------------

Technique T0 {
//------------------------------------------------------------
// Used to render the reflected landscape
Pass P00 {
#if SHADER_MODEL >= 300
AlphaBlendEnable = true;
SRCBLEND = SRCALPHA;
DESTBLEND = INVSRCALPHA;
#else
AlphaBlendEnable = false;
#endif

AlphaTestEnable = false;
FogEnable = false;
#if SHADER_MODEL >= 300
CullMode = CCW;
#else
CullMode = None;
#endif

ZEnable = true;
ZWriteEnable = true;
ZFunc = LessEqual;

VertexShader = compile VS_SM LandscapeRefVS ();
PixelShader = compile PS_SM LandscapeRefPS ();
}
//------------------------------------------------------------
// Used to render the landscape
Pass P01 {
ZEnable = true;
ZWriteEnable = true;
ZFunc = LessEqual;

AlphaBlendEnable = false;
AlphaTestEnable = false;
CullMode = CW;
FogEnable = false;

VertexShader = compile VS_SM LandscapeVertexShader ();
PixelShader = compile PS_SM LandscapePixelShader ();
}
//------------------------------------------------------------
// Used to render the water in SM 2.0 mode
Pass P02 {
AlphaBlendEnable = false;
AlphaTestEnable = false;
CullMode = CW;
FogEnable = false;
ZEnable = true;
ZWriteEnable = true;
ZFunc = LessEqual;

VertexShader = compile VS_SM WaterVS ();
PixelShader = compile PS_SM ReflectionShader ();
}
//------------------------------------------------------------
// Used to render the water in SM 3.0 mode
Pass P03 {
AlphaBlendEnable = false;
AlphaTestEnable = false;
CullMode = CW;
FogEnable = false;
ZEnable = true;
ZWriteEnable = true;
ZFunc = LessEqual;

VertexShader = compile VS_SM WaterVS ();
PixelShader = compile PS_SM ReflectionShader ();
}
//------------------------------------------------------------
// Used for rendering distant statics
Pass P04 {
AlphaBlendEnable = false;
FogEnable = false;
CullMode = CW;
ZEnable = true;
ZWriteEnable = true;
ZFunc = LessEqual;

VertexShader = compile VS_SM StaticVS ();
PixelShader = compile PS_SM StaticPS ();
}
//------------------------------------------------------------
// Used for rendering the water from underneath
Pass P05 {
AlphaBlendEnable = false;
AlphaTestEnable = false;
CullMode = CCW;
FogEnable = false;
ZEnable = true;
ZWriteEnable = true;
ZFunc = LessEqual;

VertexShader = compile VS_SM WaterVS ();
PixelShader = compile PS_SM UnderWaterPS ();
}
//------------------------------------------------------------
// Used for rendering water in non - reflective mode
Pass P06 {
AlphaBlendEnable = false;
AlphaTestEnable = false;
CullMode = CW;
FogEnable = false;
ZEnable = true;
ZWriteEnable = true;
ZFunc = LessEqual;

VertexShader = compile VS_SM WaterVS ();
PixelShader = compile PS_SM NonReflectionShader ();
}
//------------------------------------------------------------
// Used for rendering reflected statics
Pass P07 {
#if SHADER_MODEL >= 300
AlphaBlendEnable = true;
SRCBLEND = SRCALPHA;
DESTBLEND = INVSRCALPHA;
AlphaTestEnable = false;
#else
AlphaBlendEnable = false;
#endif
FogEnable = false;
CullMode = CCW;
ZEnable = true;
ZWriteEnable = true;
ZFunc = LessEqual;

VertexShader = compile VS_SM StaticReflectionVS ();
PixelShader = compile PS_SM StaticReflectionPS ();
}
//------------------------------------------------------------
// Used for rendering the lowest possible land out into infinity
Pass P08 {
AlphaBlendEnable = false;
#if SHADER_MODEL >= 300
AlphaTestEnable = false;
#endif
CullMode = CW;
FogEnable = false;
ZEnable = true;
ZWriteEnable = false;
ZFunc = LessEqual;

VertexShader = compile VS_SM LowestLandVS ();
PixelShader = compile PS_SM LowestLandPS ();
}
//------------------------------------------------------------
// Used for rendering distant statics with HW instancing
Pass P09 {
AlphaBlendEnable = false;
FogEnable = false;
CullMode = CW;
ZEnable = true;
ZWriteEnable = true;
ZFunc = LessEqual;

VertexShader = compile VS_SM StaticInstVS ();
PixelShader = compile PS_SM StaticPS ();
}
//------------------------------------------------------------
// Used for rendering reflected distant statics with HW instancing
Pass P10 {
#if SHADER_MODEL >= 300
AlphaBlendEnable = true;
SRCBLEND = SRCALPHA;
DESTBLEND = INVSRCALPHA;
AlphaTestEnable = false;
#else
AlphaBlendEnable = false;
#endif
FogEnable = false;
CullMode = CCW;
ZEnable = true;
ZWriteEnable = true;
ZFunc = LessEqual;

VertexShader = compile VS_SM StaticReflectionInstVS ();
PixelShader = compile PS_SM StaticReflectionPS ();
}
//------------------------------------------------------------
// Used for rendering grass
Pass P11 {
AlphaBlendEnable = false;
FogEnable = false;
CullMode = None;
ZEnable = true;
ZWriteEnable = true;
ZFunc = LessEqual;

VertexShader = compile VS_SM GrassVS ();
PixelShader = compile PS_SM GrassPS ();
}
//------------------------------------------------------------
// Used for rendering grass with instancing
Pass P12 {
AlphaBlendEnable = false;
AlphaTestEnable = false;
FogEnable = false;
CullMode = None;
ZEnable = true;
ZWriteEnable = true;
ZFunc = LessEqual;

VertexShader = compile VS_SM GrassInstVS ();
PixelShader = compile PS_SM GrassPS ();
}
//------------------------------------------------------------
// Used for blending what Morrowind draws with what MGE draws
Pass P13 {
AlphaBlendEnable = true;
SRCBLEND = SRCALPHA;
DESTBLEND = INVSRCALPHA;
FogEnable = false;
CullMode = None;
ZEnable = false;
ZWriteEnable = false;

VertexShader = compile VS_SM ScreenQuadVS ();
PixelShader = compile PS_SM BlendDepthPS ();
}
//------------------------------------------------------------
// Used for horizontal blurring
Pass P14 {
AlphaBlendEnable = false;
AlphaTestEnable = false;
FogEnable = false;
CullMode = None;
ZEnable = false;
ZWriteEnable = false;

VertexShader = compile VS_SM ScreenQuadVS ();
PixelShader = compile PS_SM HorizontalBlurPS ();
}
//------------------------------------------------------------
// Used for vertical blurring
Pass P15 {
AlphaBlendEnable = false;
AlphaTestEnable = false;
FogEnable = false;
CullMode = None;
ZEnable = false;
ZWriteEnable = false;

VertexShader = compile VS_SM ScreenQuadVS ();
PixelShader = compile PS_SM VerticalBlurPS ();
}
//------------------------------------------------------------
// Used to copy a texture to the screen while also setting alpha to 0
Pass P16 {
AlphaBlendEnable = false;
AlphaTestEnable = false;
FogEnable = false;
CullMode = None;
ZEnable = false;
ZWriteEnable = false;

VertexShader = compile VS_SM ScreenQuadVS ();
PixelShader = compile PS_SM CopyAndSetAlphaPS ();
}
//------------------------------------------------------------
// Used for rendering grass depth
Pass P17 {
AlphaBlendEnable = false;
FogEnable = false;
CullMode = None;
ZEnable = true;
ZWriteEnable = true;
ZFunc = LessEqual;

VertexShader = compile VS_SM GrassDepthVS ();
PixelShader = compile PS_SM GrassDepthPS ();
}
//------------------------------------------------------------
// Used for rendering grass depth with instancing
Pass P18 {
AlphaBlendEnable = false;
FogEnable = false;
CullMode = None;
ZEnable = true;
ZWriteEnable = true;
ZFunc = LessEqual;

VertexShader = compile VS_SM GrassDepthInstVS ();
PixelShader = compile PS_SM GrassDepthPS ();
}
//------------------------------------------------------------
// Used for rendering the underwater caustic lighting
Pass P19 {
AlphaBlendEnable = false;
AlphaTestEnable = false;
FogEnable = false;
CullMode = None;
ZEnable = false;
ZWriteEnable = false;
VertexShader = compile VS_SM CausticsVS ();
PixelShader = compile PS_SM CausticsPS ();
}
//------------------------------------------------------------
// Used for calculating waves
Pass P20 {
AlphaBlendEnable = false;
AlphaTestEnable = false;
FogEnable = false;
CullMode = None;
ZEnable = false;
ZWriteEnable = false;
VertexShader = compile VS_SM WaveVS ();
PixelShader = compile PS_SM WavePS ();
}
//------------------------------------------------------------
// Used for creating ripples around PC
Pass P21 {
AlphaBlendEnable = false;
AlphaTestEnable = false;
FogEnable = false;
CullMode = None;
ZEnable = false;
ZWriteEnable = false;
VertexShader = compile VS_SM WaveVS ();
PixelShader = compile PS_SM PlayerWavePS ();
}
//------------------------------------------------------------
// Used to set up the render state
Pass Zero { // 22
AlphaBlendEnable = false;
AlphaTestEnable = false;
FogEnable = false;
FogColor = ;
ColorVertex = false;
Lighting = false;
ZEnable = true;
ZWriteEnable = true;
ZFunc = LessEqual;
StencilEnable = false;
ColorWriteEnable = red | green | blue;
CullMode = CCW;
ShadeMode = gouraud;
ColorOp [0] = selectarg1;
ColorOp [1] = disable;
AlphaOp [0] = disable;
AlphaOp [1] = disable;
ResultArg [0] = current;
Texture [0] = null;
Texture [1] = null;
Texture [2] = null;
Texture [3] = null;
Texture [4] = null;
Texture [5] = null;
Texture [6] = null;
Texture [7] = null;
TexCoordIndex [0] = 0;
TexCoordIndex [1] = 1;
TexCoordIndex [2] = 2;
TexCoordIndex [3] = 3;
TexCoordIndex [4] = 4;
TexCoordIndex [5] = 5;
TexCoordIndex [6] = 6;
TexCoordIndex [7] = 7;
TextureTransformFlags [0] = 0;
TextureTransformFlags [1] = 0;
TextureTransformFlags [2] = 0;
TextureTransformFlags [3] = 0;
TextureTransformFlags [4] = 0;
TextureTransformFlags [5] = 0;
TextureTransformFlags [6] = 0;
TextureTransformFlags [7] = 0;
MagFilter [0] = Linear;
MinFilter [0] = Linear;
MipFilter [0] = Linear;
Clipping = true;
}
//------------------------------------------------------------
//Used for rendering the sky
Pass W // 23
{
AlphaBlendEnable=false;
AlphaTestEnable=false;
FogEnable=false;
CullMode=None;
ZEnable=false;
ZWriteEnable=false;
#ifdef SCATTER
VertexShader = compile VS_SM SkyVS();
PixelShader = compile PS_SM SkyPS();
#endif
}
}

User avatar
Dale Johnson
 
Posts: 3352
Joined: Fri Aug 10, 2007 5:24 am

Post » Sat Jan 15, 2011 8:49 am

it would be so great if the grass could detect collision on a mesh in general so it would work on anything that moves, wouldnt it be awesome if when you killed a cliff racer and landed on the grass it would flatten the grass down or have grass blowing up against a wall rather then through it or flowing around a log or stone, but that i Imagen would be so hard to code and unpredictable i guess. nether the less this is just one more step in making morrowind a better and lively place to live in.
User avatar
Rachael Williams
 
Posts: 3373
Joined: Tue Aug 01, 2006 6:43 pm

Post » Sat Jan 15, 2011 3:24 am

it would be so great if the grass could detect collision on a mesh in general so it would work on anything that moves, wouldnt it be awesome if when you killed a cliff racer and landed on the grass it would flatten the grass down or have grass blowing up against a wall rather then through it or flowing around a log or stone, but that i Imagen would be so hard to code and unpredictable i guess. nether the less this is just one more step in making morrowind a better and lively place to live in.

That is more like for OpenMW like projects. We might accomplish this within shaders, but with geometry shaders which need DX11, which needs engine rewrite, which needs OpenMW like engine rewrites. :)
User avatar
Mariaa EM.
 
Posts: 3347
Joined: Fri Aug 10, 2007 3:28 am

Post » Sat Jan 15, 2011 1:46 pm

Is there a way to get the ingame.fx file save a variable from a previous frame?
User avatar
Nims
 
Posts: 3352
Joined: Thu Jun 07, 2007 3:29 pm

Post » Sat Jan 15, 2011 6:43 pm

Is there a way to get the ingame.fx file save a variable from a previous frame?

Welcome to the harsh nature of shaders:
a pixel shader can not retrieve the value of previous frame
a pixel shader can not store a value for the next frame

Yet we can do wonders with them.

Additional variables needed. (Additional programming in MGE source code for this.)
User avatar
LijLuva
 
Posts: 3347
Joined: Wed Sep 20, 2006 1:59 am

Post » Sat Jan 15, 2011 5:10 am

I used the eye position as a hack to find out the direction the player is moving, since there is no way right now to find the actual movement vector. This let me make the grass move much more naturally, but it can look a bit weird when the player is moving backwards or sideways instead of forwards. I also modified the code so instead of disabling wind completely, the wind is weakened depending on how close the player is to the grass, which also makes the grass move more naturally. Here's the code specifically for the grass animation part:
// Animate grass	float4 worldpos = mul (IN.pos, world);	//distance to grass for range	float gdist = length(worldpos.xy - PlayerPos.xy);	float height = clamp (IN.pos.z, 0, 100) / 100;	float2 wind = WindVec * 2.5 + 0.25;	float2 pos_ticks1 = worldpos.xy / 1000 + ticks;	float2 pos_ticks2 = worldpos.xy / 750 + ticks * 2;	float2 pos_ticks3 = worldpos.xy / 500 + ticks * 3;	float2 pos_ticks4 = worldpos.xy / 200 + ticks * 4;	//grass offset for bendingfloat2 bend_ticks1 = (worldpos.xy - PlayerPos.xy)/1000 * 1/gdist;float2 bend_direction = (worldpos.xy - EyePos.xy);//interactive grassif ( gdist < 100 ) {	//bend	worldpos.xy += (bend_direction)/abs(bend_direction)*(cos(bend_ticks1)) * height * 1/(25+gdist) * 3500;	worldpos.xy += (gdist)/100*( sin(pos_ticks1) + cos(pos_ticks2) + sin(pos_ticks3) + cos(pos_ticks4) ) * height * wind * 10;} else {	worldpos.xy += ( sin(pos_ticks1) + cos(pos_ticks2) + sin(pos_ticks3) + cos(pos_ticks4) ) * height * wind * 10;}


And if anyone wants my full InGame.fx file here it is:

Spoiler
// Original by Timeslip and LizTail, mods by harlanrm, phal and krzymar
// To be used with MGE 3.8.2 rev. 175 and derivatives
Matrix TexProj;
Matrix view;
Matrix proj;
Matrix world;
float4x4 MatrixPalette [4] : MATRIXPALETTE;
float3 SunVec;
float3 SunCol;
float3 EyePos;
float3 SunAmb;
float3 SkyCol;
float ticks;
float2 offset;
float TexBlend;
float2 rcpres;
int FogCol;
float3 FogCol2;
float FogStart;
float FogRange;
float BlendStart;
float BlendEnd;
float GrassDist;
float2 WindVec;
float PixelWidth;
float PixelHeight;
float3 SunPos;
float SunVis;
float3 PlayerPos;
float2 RippleOrigin;
float WaterLevel;
float AlphaMultiplier;
float CausticIntens;

texture tex0;
texture tex1;
texture tex2;
texture tex3;
texture tex4;
texture tex5;
sampler s0 = sampler_state { texture = ; minfilter = linear; magfilter = linear; mipfilter = linear; addressu = clamp; addressv = clamp; };
sampler s1 = sampler_state { texture = ; minfilter = linear; magfilter = linear; mipfilter = linear; addressu = wrap; addressv = wrap; addressw = wrap; };
sampler s2 = sampler_state { texture = ; minfilter = linear; magfilter = linear; mipfilter = linear; addressu = wrap; addressv = wrap; };
sampler s3 = sampler_state { texture = ; minfilter = linear; magfilter = linear; mipfilter = linear; addressu = wrap; addressv = wrap; };
sampler s4 = sampler_state { texture = ; minfilter = linear; magfilter = linear; mipfilter = linear; addressu = clamp; addressv = clamp; };

// For sampling the far water texture
sampler s5 = sampler_state { texture = ; minfilter = linear; magfilter = linear; mipfilter = none; addressu = wrap; addressv = wrap; };
sampler s6 = sampler_state { texture = ; minfilter = linear; magfilter = linear; mipfilter = none; addressu = wrap; addressv = wrap; };
sampler s7 = sampler_state { texture = ; minfilter = linear; magfilter = linear; mipfilter = linear; addressu = clamp; addressv = clamp; };
sampler s8 = sampler_state { texture = ; minfilter = linear; magfilter = linear; mipfilter = linear; bordercolor = 0x80808080 ; addressu = border; addressv = border; };

//------------------------------------------------------------

// water & dynamic ripples settings
#if WAVEHEIGHT > 0
const bool fineWaterMesh = true; // use tesselated circular water mesh? false uses simple mesh
#else
const bool fineWaterMesh = false; // use tesselated circular water mesh? false uses simple mesh
#endif

const int waveTexResolution = 512; // texture resolution for rain ripples and player waves
const float waveTexWorldResolution = 2.50f; // world size of each player wave texture pixel

float waveTexWorldSize; // set by MGE
float waveTexRcpRes; // set by MGE

static const float3 watercolour = { 0.4, 0.45, 0.5 };
static const float FLT_MAX = 340282346600000000000000000000000000000.0f;

static const float FogRangeMinusStart = FogRange - FogStart;

//------------------------------------------------------------

static const float _lightfactor = 1 - pow (1 - SunVis, 2);
static const float3 _depthcolor = _lightfactor * SunCol * float3 (0.03, 0.04, 0.05) + (SkyCol + 0.5*FogCol2) * float3 (0.075, 0.08, 0.085);
static const float cauststr = 0.0001f * CausticIntens * saturate (0.75 * _lightfactor + 0.35 * length (FogCol2));

#if SHADER_MODEL >= 300
static const float _windfactor = length (WindVec) + 1.5;
static const float TwiceWaterLevel = 2 * WaterLevel;
#define PS_SM ps_3_0
#define VS_SM vs_3_0
#else
#define PS_SM ps_2_0
#define VS_SM vs_2_0
#endif

//------------------------------------------------------------
#if SHADER_MODEL >= 300
#ifdef EXPFOG
#define SCATTER 1
#endif
#endif
#ifdef SCATTER
#define FOGTYPE float4
#define REFFOGTYPE float4
float niceWeatherFactor;

//static const float ExpFogStart = max(0, FogStart);
//static const float ExpFogMult = saturate( FogRange/(FogRangeMinusStart) );
//static const float ExpFogRangeMinusStart = FogRange - ExpFogStart;
//float getFog(float dist)
//{
//return saturate( 1.01832*exp(-(dist-ExpFogStart)/(ExpFogRangeMinusStart))-0.01832 ) * ExpFogMult;
// return saturate( exp(-(dist-ExpFogStart)/(ExpFogRangeMinusStart)) ) * ExpFogMult;
//}

//#define getFogAlpha(dist) (saturate( exp(-((dist)-ExpFogStart)/(ExpFogRangeMinusStart)) ) * ExpFogMult)

#define getFogAlpha(dist) (saturate( exp(-(dist)/FogRange) ))

static const float3 scatter = {0.07, 0.27, 0.67};
static const float sunaltitude = pow(1.0+SunPos.z,10);
static const float sunaltitude_a = 2.8+1.2/sunaltitude;
//static const float sunaltitude_b = 0.75*sunaltitude;
static const float sunaltitude_b = 1 - exp2( -1.9*sunaltitude );
static const float sunaltitude2 = saturate(exp(-2*SunPos.z))*saturate(sunaltitude);
static const float3 newskycol = 0.35*SkyCol+float3(0.22,0.40,0.70);
float4 _getFog(float3 dir, float dist, bool coloradjust)
{
float fogdist;
float fog;
if(dist < 0) {
fogdist = 1;
fog = 0;
dist = 1E6;
} else {
fogdist = dist/FogRange;
fog = saturate( exp(-fogdist) );
fogdist = saturate(fogdist/4);
}

float3 fFogCol2 = ( lerp (FogCol2, SkyCol, 1 - pow (saturate (1 - 2.22 * saturate (dir.z - 0.075)), 1.15)) )*(1-fog);

if(niceWeatherFactor > 0.001 && (dist<0 || EyePos.z>WaterLevel-4)) {
float cos = dot(dir,SunPos);
float mie = (1.080/(1.2-cos))*sunaltitude2;
float rayl = 1-0.09*mie;

float atmdep = saturate(exp(-1.5*dir.z));

float3 att = atmdep*(scatter*(sunaltitude_a+mie));
att = (1-exp(-fogdist*att))/(att);

//float3 color = 0.125*mie + lerp(newskycol, float3(1,1,1), 0.75*fog)*rayl;
float3 color = 0.125*mie + newskycol*rayl;
color *= (1.4*atmdep+0.6) * saturate(sunaltitude_B);
color *= att;

color = lerp(fFogCol2,color,niceWeatherFactor);

return float4( color, fog );
} else {
return float4( fFogCol2, fog );
}
}
// static const bool underwater = (EyePos.z < WaterLevel-4);
// float4 getFog(float3 dir, float dist)
// {
//if(underwater && dist >= 0) {
// float fog = saturate( ( FogRange - dist ) / (FogRangeMinusStart) )*(1-fog);
// return float4( FogCol2*(1-fog), fog );
//} else {
// return _getFog(dir,dist,true);
//}
//}
//float4 getFog_refl(float3 dir, float dist) { return _getFog(dir,dist,false); }
//float3 applyfog(float3 col, float4 fog) { return lerp(fog.rgb, col, fog.a); }
//float3 applyfog(float3 col, float4 fog) { return col*fog.a+fog.rgb; }

#define getFog(dir,dist) (_getFog((dir),(dist),true))
#define getFog_refl(dir,dist) (_getFog((dir),(dist),false))
#define applyfog(col,fog) ((col)*(fog).a + (fog).rgb)

static const float3 SunCollf = lerp(SunCol,getFog(SunPos,-1).rgb,niceWeatherFactor*sunaltitude2) * _lightfactor;

struct SkyVertOut {
float4 position: POSITION;
float4 pos: TEXCOORD0;
};
SkyVertOut SkyVS( float4 pos: POSITION ) {
SkyVertOut OUT;

OUT.pos = float4(pos.x,pos.y,-550-pos.z,1);
OUT.position = OUT.pos;
OUT.position.xyz = mul(OUT.position.xyz, (float3x3)view);
OUT.position = mul(OUT.position, proj);

return OUT;
}
float4 SkyPS( in SkyVertOut IN ) : COLOR0 {
float3 fog = getFog(normalize(IN.pos.xyz),-1).rgb;
return float4(fog,1);
}
#else //no scatter
static const float3 SunCollf = SunCol * _lightfactor;

#ifdef EXPFOG
#define FOGTYPE float4
#define REFFOGTYPE float
//static const float ExpFogStart = max (0, FogStart);
//static const float ExpFogMult = saturate (FogRange / FogRangeMinusStart);
//static const float ExpFogRangeMinusStart = FogRange - ExpFogStart;

#define skyfogblend(z) (lerp (FogCol2, SkyCol, 1 - pow (saturate (1 - 2.22 * saturate ((z) - 0.075)), 1.15)))
#define applyfog(col,fog) (lerp ((fog).rgb, (col), (fog).a))
//#define getFog(dist) (saturate (exp (-((dist) - ExpFogStart) / ExpFogRangeMinusStart)) * ExpFogMult)
#define getFog(dist) (saturate (exp (-(dist)/FogRange)))
#define getFogAlpha(dist) (getFog((dist)))
#else
#define FOGTYPE float
#define REFFOGTYPE float
#define getFog(dist) (saturate ((FogRange - (dist)) / FogRangeMinusStart))
#define getFogAlpha(dist) (getFog((dist)))
#endif
#endif

//------------------------------------------------------------

float4 RenderShader (in float2 TexCoords : TEXCOORD0, in float3 Light : TEXCOORD1, in float4 Height : TEXCOORD2) : COLOR0 {
clip (Height);
float3 Result = tex2D (s3, TexCoords).rgb * Light;
return float4 (Result, 1);
}

//------------------------------------------------------------

struct StatVertIn {
float4 pos : POSITION;
float4 normal : NORMAL;
float4 color : COLOR0;
float2 texcoords : TEXCOORD0;
};

//------------------------------------------------------------

struct StatVertOut {
float4 pos : POSITION;
float2 texcoords : TEXCOORD0;
float4 color : TEXCOORD1;
float3 normal : TEXCOORD2;
FOGTYPE fog : TEXCOORD3;
float blend : TEXCOORD5;
float emissive : TEXCOORD6;
};

//------------------------------------------------------------

StatVertOut StaticVS (StatVertIn IN) {
StatVertOut OUT;

OUT.texcoords = IN.texcoords;

// Define % to Fog
float4 worldpos = mul (IN.pos, world);

#ifdef EXPFOG
float3 EyeVec = worldpos.xyz - EyePos.xyz;
float dist = length (EyeVec);
EyeVec /= dist;
#ifdef SCATTER
OUT.fog = getFog (EyeVec,dist);
#else
OUT.fog = float4 (skyfogblend (EyeVec.z), getFog (dist));
#endif
#else
float dist = length (worldpos.xyz - EyePos.xyz);
OUT.fog = getFog (dist);
#endif

// Define % to Blend
OUT.blend = saturate ((BlendEnd - dist) / (BlendEnd - BlendStart));

// Projection
OUT.pos = mul (worldpos, view);
OUT.pos = mul (OUT.pos, proj);

// Lighting
OUT.normal = normalize (IN.normal.xyz * 2 - 1); // Decompress
OUT.normal = normalize (mul (OUT.normal.xyz, (float3x3)world)); // Rotate normals but don't translate them
OUT.color = IN.color;
OUT.emissive = IN.normal.w; // Emissive stored in 4th value in normal vector


return OUT;
}

//------------------------------------------------------------

struct StatInstVertIn {
float4 pos : POSITION;
float4 normal : NORMAL;
float4 color : COLOR0;
float2 texcoords : TEXCOORD0;
float4 m1 : TEXCOORD1;
float4 m2 : TEXCOORD2;
float4 m3 : TEXCOORD3;
float4 m4 : TEXCOORD4;
};

//------------------------------------------------------------

StatVertOut StaticInstVS (StatInstVertIn IN) {
StatVertOut OUT;

OUT.texcoords = IN.texcoords;

// Pack instance transform
float4x4 worldmat = float4x4 (IN.m1, IN.m2, IN.m3, IN.m4);

// Define % to Fog
float4 worldpos = mul (IN.pos, worldmat);

#ifdef EXPFOG
float3 EyeVec = worldpos.xyz - EyePos.xyz;
float dist = length (EyeVec);
EyeVec /= dist;
#ifdef SCATTER
OUT.fog = getFog (EyeVec,dist);
#else
OUT.fog = float4 (skyfogblend (EyeVec.z), getFog (dist));
#endif
#else
float dist = length (worldpos.xyz - EyePos.xyz);
OUT.fog = getFog (dist);
#endif

// Define % to Blend
OUT.blend = saturate ((BlendEnd - dist) / (BlendEnd - BlendStart));

// Projection
OUT.pos = mul (worldpos, view);
OUT.pos = mul (OUT.pos, proj);

// Lighting
OUT.normal = normalize (IN.normal.xyz * 2 - 1); // Decompress
OUT.normal = normalize (mul (OUT.normal.xyz, (float3x3)world)); // Rotate normals but don't translate them
OUT.color = IN.color;
OUT.emissive = IN.normal.w; // Emissive stored in 4th value in normal vector

return OUT;
}

//------------------------------------------------------------

float4 StaticPS (StatVertOut IN): COLOR0 {
float4 Result = tex2D (s3, IN.texcoords);

// Lighting
float3 normal = normalize (IN.normal);
float3 diffuse = saturate (dot (-SunVec, normal)) * SunCol * IN.color.rgb;
float3 ambient = SunAmb * IN.color.rgb;
Result.rgb *= saturate (diffuse + ambient + IN.emissive);

// Fogging
#ifdef EXPFOG
#ifdef SCATTER
Result.rgb = applyfog( Result.rgb, IN.fog );
#else
Result.rgb = lerp (IN.fog.rgb, Result.rgb, IN.fog.a);
#endif
#else
Result.rgb = lerp (FogCol2, Result.rgb, IN.fog);
#endif

// Blending
Result.a = saturate (IN.color.a * Result.a * AlphaMultiplier) * IN.blend;

return Result;
}

//------------------------------------------------------------

struct StatRefVertOut {
float4 pos : POSITION;
float2 texcoords : TEXCOORD0;
float4 color : TEXCOORD1;
float3 normal : TEXCOORD2;
REFFOGTYPE fog : TEXCOORD3;
float height : TEXCOORD6;
};

//------------------------------------------------------------

StatRefVertOut StaticReflectionVS (StatVertIn IN) {
StatRefVertOut OUT;

OUT.texcoords = IN.texcoords;

float4 worldpos = mul (IN.pos, world);

// Define % to Fog
#if SHADER_MODEL >= 300
float3 EyeVec = float3 (worldpos.xy, TwiceWaterLevel - worldpos.z) - EyePos.xyz;
float dist = length (EyeVec);
EyeVec /= dist;

#ifdef EXPFOG
#ifdef SCATTER
OUT.fog = getFog_refl(EyeVec*float3(1,1,-1),dist);
#else
//OUT.fog = saturate (exp (-(max (0, worldpos.z) / (0.0001 + saturate (-EyeVec.z))) / ExpFogRangeMinusStart));
OUT.fog = saturate (exp (-(max (0, worldpos.z) / (0.0001 + saturate (-EyeVec.z))) / FogRangeMinusStart));
#endif
#else
OUT.fog = saturate (
getFog (dist) /
(0.001 + saturate ((FogRange - (EyePos.z - WaterLevel) / (0.001 + saturate (-EyeVec.z))) / (FogRangeMinusStart)))
);
#endif
#else
float dist = length (worldpos.xyz - EyePos.xyz);
OUT.fog = getFog (dist);
#endif

//// Define % to Blend
//OUT.blend = saturate ((BlendEnd - dist) / (BlendEnd - BlendStart));

// Projection
OUT.pos = mul (worldpos, view);
OUT.pos = mul (OUT.pos, proj);

// Lighting
OUT.normal = normalize (IN.normal.xyz * 2 - 1); // Decompress
OUT.normal = normalize (mul (OUT.normal, (float3x3)world)); // Rotate normals but don't translate them
OUT.color = IN.color;

// Figure hight of pixel in world coordinates
OUT.height = worldpos.z;

return OUT;
}

//------------------------------------------------------------

StatRefVertOut StaticReflectionInstVS (StatInstVertIn IN) {
StatRefVertOut OUT;

OUT.texcoords = IN.texcoords;

// Pack instance transform
float4x4 worldmat = float4x4 (IN.m1, IN.m2, IN.m3, IN.m4);

float4 worldpos = mul (IN.pos, worldmat);

// Define % to Fog
#if SHADER_MODEL >= 300
float3 EyeVec = float3 (worldpos.xy, TwiceWaterLevel - worldpos.z) - EyePos.xyz;
float dist = length (EyeVec);
EyeVec /= dist;

#ifdef EXPFOG
#ifdef SCATTER
OUT.fog = getFog_refl(EyeVec*float3(1,1,-1),dist);
#else
//OUT.fog = saturate (exp (-(max (0, worldpos.z) / (0.0001 + saturate (-EyeVec.z))) / ExpFogRangeMinusStart));
OUT.fog = saturate (exp (-(max (0, worldpos.z) / (0.0001 + saturate (-EyeVec.z))) / FogRangeMinusStart));
#endif
#else
OUT.fog = saturate (
getFog (dist) /
(0.001 + saturate ((FogRange - (EyePos.z - WaterLevel) / (0.001 + saturate (-EyeVec.z))) / (FogRangeMinusStart)))
);
#endif
#else
float dist = length (worldpos.xyz - EyePos.xyz);
OUT.fog = getFog (dist);
#endif

//// Define % to Blend
//OUT.blend = saturate ((BlendEnd - dist) / (BlendEnd - BlendStart));

// Projection
OUT.pos = mul (worldpos, view);
OUT.pos = mul (OUT.pos, proj);

// Lighting
OUT.normal = normalize (mul (IN.normal.xyz, (float3x3)worldmat));
OUT.color = IN.color;

// Figure height of pixel in world coordinates
OUT.height = worldpos.z;

return OUT;
}

//------------------------------------------------------------

float4 StaticReflectionPS (StatRefVertOut IN): COLOR0 {
// Clip to water plane
clip (IN.height + 4 - WaterLevel);
#ifdef SCATTER
clip (IN.fog.a - 0.001);
#else
clip (IN.fog - 0.001);
#endif

float4 Result = tex2D (s3, IN.texcoords);
clip (Result.a - 0.5);

// Lighting
float3 normal = normalize (IN.normal);
Result.rgb *= saturate ((saturate (dot (-SunVec, normal)) * SunCol + SunAmb) * IN.color.rgb);

// Fogging
#ifdef SCATTER
Result.rgb = applyfog(Result.rgb,IN.fog);
#else
Result.rgb = lerp (FogCol2, Result.rgb, IN.fog);
#endif

return float4 (Result.rgb, 1);
}

//------------------------------------------------------------

struct LowestLandVertOut {
float4 position : POSITION;
float4 pos : TEXCOORD0;
float2 texcoords : TEXCOORD1;
float3 light : COLOR0;
};

//------------------------------------------------------------

LowestLandVertOut LowestLandVS (in float4 pos : POSITION) {
LowestLandVertOut OUT;

OUT.position = mul (pos, world);
OUT.position = mul (OUT.position, view);
OUT.position = mul (OUT.position, proj);

OUT.pos = float4 (pos.xy - offset, pos.zw);

// Calculate texture coordinates
OUT.texcoords = OUT.pos.xy / 600;

// Lighting
OUT.light = saturate(-SunVec.z * SunCol);
OUT.light = saturate (OUT.light + SunAmb);

return OUT;
}

//------------------------------------------------------------

float4 LowestLandPS (in LowestLandVertOut IN): COLOR0 {
// Define % to Fog
float dist = length (IN.pos.xyz - EyePos.xyz);

float3 Result = tex2D (s3, IN.texcoords).rgb;
Result *= IN.light;

// Fogging
float fog;
fog = getFogAlpha (dist);

Result = lerp (FogCol2, Result, fog);

return float4 (Result, 1);
}

//------------------------------------------------------------

struct WaterVertOut {
float4 position : POSITION;
float4 pos : TEXCOORD0;
float2 texcoord1 : TEXCOORD1;
float2 texcoord2 : TEXCOORD2;
float2 texcoord3 : TEXCOORD3;
float4 screenpos : TEXCOORD5;
#if WAVEHEIGHT > 0
float4 screenposclamp : TEXCOORD7;
#endif
float w : TEXCOORD6;
};

//------------------------------------------------------------

WaterVertOut WaterVS (in float4 pos : POSITION) {
WaterVertOut OUT;

OUT.pos = float4 (pos.xy - offset, pos.zw);

// Calculate various texture coordinates
OUT.texcoord1 = OUT.pos.xy / 3900;
OUT.texcoord2 = OUT.pos.xy / 1104;
OUT.texcoord3 = OUT.pos.xy / 892;

#if WAVEHEIGHT > 0
float time = ticks / 2;

float height = tex3Dlod (s1, float4 (OUT.texcoord2, time, 0)).a - 0.5f;
float height2 = tex3Dlod (s1, float4 (OUT.texcoord1, time*0.56, 0)).a - 0.5f;

float dist = length (EyePos.xyz - OUT.pos.xyz);

//float addheight = WAVEHEIGHT * (lerp (height, height2, saturate (dist / 8000)) - 0.5f) * saturate (1 - dist / 6400) * saturate (dist / 200);
float addheight = WAVEHEIGHT * (0.65*height * saturate (1 - dist / 8000) + height2) * saturate (1 - dist / 6400) * saturate (dist / 200);

float4 newPos = pos + float4 (0, 0, addheight, 0);

OUT.pos.zw = newPos.zw;

OUT.position = mul (newPos, world);
OUT.position = mul (OUT.position, view);
OUT.position = mul (OUT.position, proj);
OUT.w = OUT.position.w;

OUT.screenpos = mul (newPos , TexProj);
newPos = pos - float4 (0, 0, abs (addheight), 0);
OUT.screenposclamp = mul (newPos , TexProj);
#else
OUT.position = mul (pos, world);
OUT.position = mul (OUT.position, view);
OUT.position = mul (OUT.position, proj);
OUT.w = OUT.position.w;

OUT.screenpos = mul (pos, TexProj);
#endif

return OUT;
}

//------------------------------------------------------------

float3 GetFinalWaterNormal (float2 texcoord1, float2 texcoord2, float2 texcoord3, float dist, float2 IN_pos_xy) : NORMAL {
// Calculate the W texture coordinate based on the time that has passed
float time = ticks / 2;
float3 tex1 = float3(texcoord1, time*0.56);
float3 tex2 = float3(texcoord2, time);

// Blend together the normals from different sized areas of the same texture.
float2 far_normal = tex3D (s5, tex1).rg;
float2 close_normal = tex3D (s5, tex2).rg;
#ifdef MGE_DYNAMICRIPPLES
// add ripples
#if SHADER_MODEL >= 300
close_normal.rg += tex2D (s2, texcoord3).ba; // rain
close_normal.rg += tex2D (s8, (IN_pos_xy - RippleOrigin) / waveTexWorldSize).ba * 2 - 1.5; // player
#else
close_normal.rg += (tex2D (s2, texcoord3).ba // rain
+ tex2D (s8, (IN_pos_xy - RippleOrigin) / waveTexWorldSize).ba) * 2 - 2; // player
#endif
#endif
//float2 normal_R = lerp (close_normal, far_normal, saturate (dist / 8000)) * 2 - 1;
float2 normal_R = 0.65*(close_normal * 2 - 1) * saturate (1 - dist / 8000) + (far_normal * 2 - 1);
return normalize(float3(normal_R,1));
}

//------------------------------------------------------------

float4 ReflectionShader (in WaterVertOut IN): COLOR0 {
// Calculate eye vector
float3 EyeVec = EyePos.xyz - IN.pos.xyz;
float dist = length (EyeVec);
EyeVec /= dist;

// Define % to Fog
#ifdef SCATTER
float4 fog = getFog_refl(-EyeVec, dist);
#else
float fog = getFog (dist);
#endif

// Calculate water normal
float3 normal = GetFinalWaterNormal (IN.texcoord1, IN.texcoord2, IN.texcoord3, dist, IN.pos.xy);

float2 Tex = IN.screenpos.xy / IN.w;

// reflection / refraction strength factor, wind strength increases distortion
#if SHADER_MODEL >= 300
//float2 reffactor = ((dist / 100 * _windfactor) + 0.1) * (normal.xy);
//float3 reffactor;
//reffactor.x = dot(-normal, float3(view[0][0],view[1][0],view[2][0]));
//reffactor.y = dot(-normal, float3(view[0][2],view[1][2],view[2][2]));
//reffactor.z = 1 - reffactor.y;
//reffactor *= ((dist / 100 * _windfactor) + 0.1).xxx;

// Distort refraction dependent on depth
float2 reffactor = 0.01 * _windfactor * normal.xy;
#else
// Distort refraction dependent on depth
float2 reffactor = 0.02 * normal.xy;
#endif

float2 newscrpos = Tex + reffactor.yx;

// Sample depth texture
float depth = tex2D (s7, newscrpos).r - IN.w;
newscrpos = Tex + saturate (depth / 100) * reffactor.yx;

// Sample refraction texture
float3 Refract = tex2D (s4, newscrpos).rgb;

#if SHADER_MODEL >= 300
// Get distorted depth
//depth = max (0, tex2D (s7, newscrpos).r - IN.w);
depth = tex2D (s7, newscrpos).r - IN.w;
if(depth < -1) depth = 1E6;
depth /= dot (-EyeVec, float3 (view [0][2], view [1][2], view [2][2]));

float depthscale = saturate (exp (-(depth) / 800));
float shorefactor = pow (depthscale, 25);

#ifdef SCATTER
float3 depthcolor = applyfog(_depthcolor,fog);
#else
float3 depthcolor = lerp (FogCol2, _depthcolor, fog);
#endif

// Make transition between actual refraction image and depth color depending on water depth
Refract = lerp (depthcolor, Refract, 0.8 * depthscale + 0.2 * shorefactor);

// Sample reflection texture
float3 Reflect = {0, 0, 0};

// float totalalpha;

if (EyePos.z < WaterLevel - 4) {
Reflect = _depthcolor;
} else {
#ifdef WATERBLUR
float blurwidth = (1 - EyeVec.z) * 0.005;

float2 scrpos =
#if WAVEHEIGHT > 0
IN.screenposclamp.xy / IN.w
#else
Tex
#endif
+ float2(-2.5 * reffactor.x, 0.0015+abs (reffactor.y));

// unfolded blurring allows for better optimization
float2 shift = blurwidth * float2 (1, 0);
Reflect += 0.100 * (tex2D (s0, scrpos + shift).rgb
+ tex2D (s0, scrpos - shift).rgb);
shift = blurwidth * float2 (0.67, 0.33);
Reflect += 0.115 * (tex2D (s0, scrpos + shift).rgb
+ tex2D (s0, scrpos - shift).rgb);
shift = blurwidth * float2 (0.33, -0.33);
Reflect += 0.135 * (tex2D (s0, scrpos + shift).rgb
+ tex2D (s0, scrpos - shift).rgb);
shift = float2 (0.0, blurwidth * 0.67);
Reflect += 0.150 * (tex2D (s0, scrpos + shift).rgb
+ tex2D (s0, scrpos - shift).rgb);

#else
Reflect = tex2D (s0,
#if WAVEHEIGHT > 0
IN.screenposclamp.xy / IN.w
#else
Tex
#endif
+ float2 (-2.5 * reffactor.x, 0.0015+abs (reffactor.y)));
#endif
}

#ifdef SCATTER
//Reflect = applyfog(Reflect, fog);
Reflect = lerp (Reflect, applyfog(Reflect, fog),saturate((EyePos.z-WaterLevel)/7168.0));
float3 adjustnormal = lerp (float3 (0, 0, 0.1), normal, pow (saturate (1.05 * fog.a), 2));
#else
Reflect = lerp (FogCol2, Reflect, fog);
float3 adjustnormal = lerp (float3 (0, 0, 0.1), normal, pow (saturate (1.05 * fog), 2));
#endif

adjustnormal = lerp (adjustnormal, float3 (0, 0, 1.0), (1 - EyeVec.z) * (1 - saturate (1 / (dist / 1000 + 1))));

float fresnel = dot (EyeVec, adjustnormal);
fresnel = 0.02 + pow (saturate (0.9988 - 0.28 * fresnel), 16);
float3 Result = lerp (Refract, Reflect, fresnel);

// Specular lighting
float reflection = saturate (1.0025 * dot (EyeVec, reflect (-SunPos, normal)));
float3 spec = SunCollf * (pow (reflection, 150) + 0.07 * pow (reflection, 4));


// smooth transition at shore line
#ifdef SCATTER
Result = lerp (Result + spec * fog.a, Refract, shorefactor * fog.a);
#else
Result = lerp (Result + spec * fog, Refract, shorefactor * fog);
#endif
#else
// Make transition between actual refraction image and depth color depending on water depth
Refract = lerp (Refract, _depthcolor, saturate (depth / 1500 + 0.3));

float3 Reflect = tex2D (s0, Tex - float2 (2.5 * reffactor.x, -abs (reffactor.y))) / 2;

float fresnel = saturate (dot (EyeVec, float3 (0, 0, 1)) * 1.5);
float3 Result = lerp (Reflect, Refract, fresnel);

//Specular lighting
float reflection = saturate (dot (EyeVec, reflect (-SunPos, normal)));
float3 spec = SunCollf * pow (reflection, 150);

// Additional Specular
spec += pow (dot (normal, float3 (0, 0, 1)), 100) * SunAmb / 12; // gives water a shiny look

// smooth transition at shore line
Result += spec;

Result = lerp (FogCol2, Result, fog);
#endif

return float4 (Result, 1);
}

//------------------------------------------------------------

float4 NonReflectionShader (in WaterVertOut IN): COLOR0 {
// Calculate eye vector
float3 EyeVec = (EyePos - IN.pos.xyz);
float dist = length (EyeVec);
EyeVec /= dist;

// Define % to Fog
//float fog = saturate ((FogRange - dist) / FogRangeMinusStart);
float fog = getFogAlpha (dist);

// Calculate water normal
float3 normal = GetFinalWaterNormal (IN.texcoord1, IN.texcoord2, IN.texcoord3, dist, IN.pos.xy);

float2 Tex = IN.screenpos.xy / IN.w;

// reflection / refraction strength factor, wind strength increases distortion
#if SHADER_MODEL >= 300
float2 reffactor = 0.008 * _windfactor * normal.xy;
#else
float2 reffactor = 0.02 * normal.xy;
#endif

// Distort refraction dependent on depth
float2 newscrpos = Tex + reffactor.yx;

// Sample depth texture
float depth = max (0, tex2D (s7, newscrpos).r - IN.w);
newscrpos = Tex + saturate (depth / 100) * reffactor.yx;

// Sample refraction texture
float3 Refract = tex2D (s4, newscrpos).rgb;

#if SHADER_MODEL >= 300
// Get distorted depth
depth = max (0, tex2D (s7, newscrpos).r - IN.w);
depth /= dot (-EyeVec, float3 (view [0][2], view [1][2], view [2][2]));

float depthscale = saturate (exp (-depth / 800));
float shorefactor = pow (depthscale, 25);

// Make transition between actual refraction image and depth color depending on water depth
Refract = lerp (_depthcolor, Refract, 0.8 * depthscale + 0.2 * shorefactor);

float fresnel = dot (EyeVec, lerp (normal, float3 (0, 0, 1), (1 - EyeVec.z) * (1 - exp (-dist / 2500)))) * fog;
fresnel = 0.02 + pow (saturate (0.9988 - 0.28 * fresnel), 16);

float3 Reflect = (FogCol2 + SkyCol) * 0.4;
if (SunVec.z > 0.9) {
Reflect = FogCol2 * 0.55;
}
Reflect = lerp (FogCol2, Reflect, fog);

float3 Result = lerp (Refract, Reflect, fresnel);

// Specular lighting
float reflection = saturate (1.0025 * dot (EyeVec, reflect (-SunPos, normal)));
float3 spec = SunCollf * (pow (reflection, 150) + 0.07 * pow (reflection, 4)) * fog;

Result = lerp (Result + spec, Refract, shorefactor * fog);
#else
// Make transition between actual refraction image and depth color depending on water depth
Refract = lerp (Refract, _depthcolor, saturate (depth / 1500 + 0.3));

float fresnel = saturate(dot(EyeVec,float3(0,0,1)));

float3 Reflect = SkyCol / 2;

float3 Result = lerp (Reflect, Refract, saturate(fresnel*(depth+2)));

//Specular lighting
float reflection = saturate (1.0025 * dot (EyeVec, reflect (-SunPos, normal)));
float3 spec = SunCollf * pow (reflection, 150);

// Additional Specular
spec += pow (dot (normal, float3 (0, 0, 1)), 100) * SunAmb / 12; // gives water a shiny look

Result += spec;

//Fogging
Result = lerp (FogCol2, Result, fog);
#endif

return float4 (Result, 1);
}

//------------------------------------------------------------

float4 UnderWaterPS (in WaterVertOut IN): COLOR0 {
// Calculate eye vector
float3 EyeVec = (EyePos - IN.pos.xyz);
float dist = length (EyeVec);
EyeVec /= dist;

// Calculate water normal
float3 normal = -GetFinalWaterNormal (IN.texcoord1, IN.texcoord2, IN.texcoord3, dist, IN.pos.xy);

float2 Tex = IN.screenpos.xy / IN.w;

// Define % to Fog
// #ifdef EXPFOG
// float fog = exp (-2 * dist / FogRange);
// #else
// float fog = saturate (1 - (dist / FogRange));
// fog *= fog;
// #endif
float fog = getFogAlpha (dist);

#if SHADER_MODEL >= 300
// reflection / refraction strength factor, wind strength increases distortion
// float2 reffactor = -((dist / 20 * (_windfactor)) + 0.25) * float2 (
// dot (normal, float3 (view [0][0], view [1][0], view [2][0])),
// dot (normal, float3 (view [0][1], view [1][1], view [2][1]))
// );
float2 reffactor = 0.016 * _windfactor * normal.xy;
#else
float2 reffactor = 0.05 * normal.xy;
#endif

// Sample depth texture
float depth = max (0, tex2D (s7, Tex + reffactor.xy).r - IN.w);
float depthfactor = saturate (depth / 150);

#if SHADER_MODEL >= 300
depth = max (0, tex2D (s7, Tex + depthfactor * reffactor.xy).r - IN.w);
#else
depth = tex2D (s7, Tex + depthfactor * reffactor.xy).r - IN.w;
#endif

// Sample refraction texture
float3 Refract = tex2D (s4, Tex + depthfactor * reffactor.xy).rgb;

depthfactor = saturate (depth / 150);

// Specular lighting
float reflection = saturate (1.005 * dot (EyeVec, reflect (float3 (-SunPos.x, -SunPos.y, SunPos.z), normal)));
float3 Specular = saturate (1.5 * SunCollf) * (pow (reflection, 120) + 0.07 * pow (reflection, 2));

#if SHADER_MODEL >= 300
Refract += Specular * depthfactor * fog;
#else
Refract += Specular;
#endif

// fresnel factor
// float fresnel = saturate (dot (EyeVec, normal / float3 ((1.0 + 0.5 * normal.z).xx, 1)));
float fresnel = saturate (dot (EyeVec, normal));
fresnel = 0.4 * pow (saturate (1.3 - fresnel), 8) * fog;

#if SHADER_MODEL >= 300
if (SunVec.z > 0.9) fresnel *= 0.6;
#endif

float3 Result = Refract * (1 - fresnel * depthfactor);

// Realistic Fresnel
// fresnel = saturate (0.015 / max (0.01, fresnel - 0.645) - 0.02);
// Refract = tex2Dproj (s4, IN.screenpos + float4 (reffactor.xy, 0, 0) / (1.001 - fresnel)).rgb;
// float3 Result = lerp (Refract, FogCol2, fresnel);

return float4 (Result, 1);
}

//------------------------------------------------------------

struct LandVertOut {
float4 pos: POSITION;
float2 texcoord: TEXCOORD1;
float3 position: TEXCOORD2;
FOGTYPE fog : TEXCOORD3;
};

//------------------------------------------------------------

LandVertOut LandscapeVertexShader (float4 pos: POSITION, float2 texcoord: TEXCOORD0) {
LandVertOut OUT;

// Define % to Fog
#ifdef EXPFOG
float3 EyeVec = pos.xyz - EyePos.xyz;
float dist = length (EyeVec);
EyeVec /= dist;
#ifdef SCATTER
OUT.fog = getFog (EyeVec,dist);
#else
OUT.fog = float4 (skyfogblend (EyeVec.z), getFog (dist));
#endif
#else
float dist = length (pos.xyz - EyePos.xyz);
OUT.fog = getFog (dist);
#endif

// Lower vertices that are close to the camera to ensure they are always below it
float disp = lerp (200, 0, saturate (dist / 2000));
pos.z -= disp;

// OUT.pos = mul (pos, worldviewproj);
OUT.pos = mul (pos, world);
OUT.pos = mul (OUT.pos, view);
OUT.pos = mul (OUT.pos, proj);

OUT.texcoord = texcoord;
OUT.position = pos.xyz;

return OUT;
}

//------------------------------------------------------------

float4 LandscapePixelShader (in LandVertOut IN): COLOR0 {
// Normalize incoming normal
float3 normal = normalize (tex2D (s1, IN.texcoord).rgb * 2 - 1);

// World Texture
float3 Result = tex2D (s3, IN.texcoord).rgb;

// Detail Texture
float detail = tex2D (s2, IN.texcoord * 1064).g + 0.5;
detail *= tex2D (s2, IN.texcoord * 333).g + 0.5;
detail *= tex2D (s2, IN.texcoord * 90).g + 0.5;

// Lighting
Result *= detail * saturate ((saturate (dot (-SunVec, normal)) * SunCol) + SunAmb);

// Define % to Fog
#ifdef EXPFOG
#ifdef SCATTER
Result = applyfog( Result, IN.fog );
#else
Result = lerp (IN.fog.rgb, Result, IN.fog.a);
#endif
return float4 (Result, 1 - IN.fog.a);
#else
Result = lerp (FogCol2, Result, IN.fog);
return float4 (Result, 1 - IN.fog);
#endif
}

//------------------------------------------------------------

struct LandRefVertOut {
float4 pos: POSITION;
float2 texcoord: TEXCOORD1;
REFFOGTYPE fog : TEXCOORD2;
float height : TEXCOORD3;
};

//------------------------------------------------------------

LandRefVertOut LandscapeRefVS (float4 pos: POSITION, float2 texcoord: TEXCOORD0) {
LandRefVertOut OUT;

#if SHADER_MODEL >= 300
//// Lower vertices so there are fewer seams visible in the reflection
// pos.z -= 20 * saturate (1 - (pos.z / 100));
float3 EyeVec = float3 (pos.xy, TwiceWaterLevel - pos.z) - EyePos.xyz;
float dist = length (EyeVec);
EyeVec /= dist;

// Define % to Fog
#ifdef EXPFOG
#ifdef SCATTER
OUT.fog = getFog_refl(EyeVec*float3(1,1,-1),dist);
#else
//OUT.fog = saturate (exp ( -(max (0, pos.z) / (0.0001 + saturate (-EyeVec.z))) / ExpFogRangeMinusStart));
OUT.fog = saturate (exp ( -(max (0, pos.z) / (0.0001 + saturate (-EyeVec.z))) / FogRangeMinusStart));
#endif
#else
OUT.fog = saturate (
getFog (dist) /
(0.001 + saturate ((FogRange - (EyePos.z - WaterLevel) / (0.001 + saturate (-EyeVec.z))) / FogRangeMinusStart))
);
#endif
#else
// Lower vertices so there are fewer seams visible in the reflection
// pos.z -= 100;

// Define % to Fog
OUT.fog = getFog (length (pos.xyz - EyePos.xyz));
#endif

// OUT.pos = mul (pos, worldviewproj);
OUT.pos = mul (pos, world);
OUT.pos = mul (OUT.pos, view);
OUT.pos = mul (OUT.pos, proj);
OUT.texcoord = texcoord;

// Define height of pixel for clipping to water plane
OUT.height = pos.z;

return OUT;
}

//------------------------------------------------------------

float4 LandscapeRefPS (in LandRefVertOut IN): COLOR0 {
// Clip to water plane
clip (IN.height + 4 - WaterLevel);
#ifdef SCATTER
clip (IN.fog.a - 0.001);
#else
clip (IN.fog - 0.001);
#endif

// Normalize incoming normal
float3 normal = normalize (tex2D (s1, IN.texcoord).rgb * 2 - 1);

// World Texture
float3 Result = tex2D (s3, IN.texcoord).rgb;

// Detail Texture
float detail = tex2D (s2, IN.texcoord * 1064).g + 0.5;
detail *= tex2D (s2, IN.texcoord * 333).g + 0.5;
detail *= tex2D (s2, IN.texcoord * 90).g + 0.5;

// Lighting
Result *= detail * saturate ((saturate (dot (-SunVec, normal)) * SunCol) + SunAmb);

// let reflections fade to water color
#ifdef SCATTER
Result.rgb = applyfog(Result.rgb,IN.fog);
#else
Result.rgb = lerp (FogCol2, Result.rgb, IN.fog);
#endif

//return float4 (Result, saturate (3.5 * IN.fog));
return float4 (Result, 1);
}

//------------------------------------------------------------

struct GrassVertIn {
float4 pos : POSITION;
float3 normal : NORMAL;
float4 color : COLOR0;
float2 texcoords : TEXCOORD0;
};

//------------------------------------------------------------

struct GrassVertOut {
float4 pos : POSITION;
float2 texcoords : TEXCOORD0;
float3 color : COLOR0;
FOGTYPE fog : TEXCOORD1;
float4 screenpos: TEXCOORD4;
float blend : TEXCOORD5;
};

//------------------------------------------------------------

GrassVertOut GrassVS (GrassVertIn IN) {
GrassVertOut OUT;

OUT.texcoords = IN.texcoords;

// Animate grass
float4 worldpos = mul (IN.pos, world);

//distance to grass for range
float gdist = length(worldpos.xy - PlayerPos.xy);

float height = clamp (IN.pos.z, 0, 100) / 100;

float2 wind = WindVec * 2.5 + 0.25;

float2 pos_ticks1 = worldpos.xy / 1000 + ticks;
float2 pos_ticks2 = worldpos.xy / 750 + ticks * 2;
float2 pos_ticks3 = worldpos.xy / 500 + ticks * 3;
float2 pos_ticks4 = worldpos.xy / 200 + ticks * 4;

//grass offset for bending
float2 bend_ticks1 = (worldpos.xy - PlayerPos.xy)/1000 * 1/gdist;
float2 bend_direction = (worldpos.xy - EyePos.xy);


//interactive grass
if ( gdist < 100 ) {
//bend

worldpos.xy += (bend_direction)/abs(bend_direction)*(cos(bend_ticks1)) * height * 1/(25+gdist) * 3500;

worldpos.xy += (gdist)/100*( sin(pos_ticks1) + cos(pos_ticks2) + sin(pos_ticks3) + cos(pos_ticks4) ) * height * wind * 10;

} else {
worldpos.xy += ( sin(pos_ticks1) + cos(pos_ticks2) + sin(pos_ticks3) + cos(pos_ticks4) ) * height * wind * 10;
}


// Define % to Fog
#ifdef EXPFOG
float3 EyeVec = worldpos.xyz - EyePos.xyz;
float dist = length (EyeVec);
EyeVec /= dist;
#ifdef SCATTER
OUT.fog = getFog (EyeVec,dist);
#else
OUT.fog = float4 (skyfogblend (EyeVec.z), getFog (dist));
#endif
#else
float dist = length (worldpos.xyz - EyePos.xyz);
OUT.fog = getFog (dist);
#endif

// Define % to Blend
OUT.blend = saturate ((BlendEnd - dist) / (BlendEnd - BlendStart));

// Projection
OUT.pos = mul (worldpos, view);
OUT.pos = mul (OUT.pos, proj);

// Texture Projection
OUT.screenpos = mul (worldpos, TexProj);

// Lighting
OUT.color = (SunCol * 0.25) + SunAmb;

return OUT;
}

//------------------------------------------------------------

GrassVertOut GrassInstVS (StatInstVertIn IN) {
GrassVertOut OUT;

// Pack instance transform
float4x4 worldmat = float4x4 (IN.m1, IN.m2, IN.m3, IN.m4);

OUT.texcoords = IN.texcoords;

// Define % to Fog
float4 worldpos = mul (IN.pos, worldmat);

#ifdef EXPFOG
float3 EyeVec = worldpos.xyz - EyePos.xyz;
float dist = length (EyeVec);
EyeVec /= dist;
#ifdef SCATTER
OUT.fog = getFog (EyeVec,dist);
#else
OUT.fog = float4 (skyfogblend (EyeVec.z), getFog (dist));
#endif
#else
float dist = length (worldpos.xyz - EyePos.xyz);
OUT.fog = getFog (dist);
#endif

OUT.blend = 1 - (saturate ((GrassDist - dist) / (GrassDist / 5)));
OUT.blend += 0.4;
OUT.screenpos = 0;

// Animate grass
//distance to grass for range
float gdist = length(worldpos.xy - PlayerPos.xy);

float height = clamp (IN.pos.z, 0, 100) / 100;

float2 wind = WindVec / 6;

float2 pos_ticks1 = worldpos.xy / 1000 + ticks;
float2 pos_ticks2 = worldpos.xy / 750 + ticks * 2;
float2 pos_ticks3 = worldpos.xy / 500 + ticks * 3;
float2 pos_ticks4 = worldpos.xy / 250 + ticks * 4;

//grass offset for bending
float2 bend_ticks1 = (worldpos.xy - PlayerPos.xy)/1000 * 1/gdist;
float2 bend_direction = (worldpos.xy - EyePos.xy);


//interactive grass
if ( gdist < 100 ) {
//bend

worldpos.xy += (bend_direction)/abs(bend_direction)*(cos(bend_ticks1)) * height * 1/(25+gdist) * 3500;

worldpos.xy += (gdist)/100*( sin(pos_ticks1) + cos(pos_ticks2) + sin(pos_ticks3) + cos(pos_ticks4) ) * height * wind * 10;

} else {
worldpos.xy += ( sin(pos_ticks1) + cos(pos_ticks2) + sin(pos_ticks3) + cos(pos_ticks4) ) * height * wind * 10;
}


// Projection
OUT.pos = mul (worldpos, view);
OUT.pos = mul (OUT.pos, proj);

// Lighting
OUT.color = (SunCol * 0.25) + SunAmb;

return OUT;
}

//------------------------------------------------------------

float4 GrassPS (GrassVertOut IN): COLOR0 {
float4 Result = tex2D (s3, IN.texcoords);
// clip (Result.a - 0.4);

// Lighting
Result.rgb *= IN.color;

// Fogging
#ifdef EXPFOG
#ifdef SCATTER
Result.rgb = applyfog( Result.rgb, IN.fog );
#else
Result.rgb = lerp (IN.fog.rgb, Result.rgb, IN.fog.a);
#endif
#else
Result.rgb = lerp (FogCol2, Result.rgb, IN.fog);
#endif


// Blending
Result.a = saturate (Result.a * AlphaMultiplier) * IN.blend;
return float4 (Result.rgb, Result.a);
}

//------------------------------------------------------------

struct BlendDepthVertIn {
float4 pos : POSITION;
float2 texcoord : TEXCOORD0;
};

//------------------------------------------------------------

struct ScreenVertOut {
float4 pos: POSITION;
float2 texcoord : TEXCOORD0;
};

//------------------------------------------------------------

ScreenVertOut ScreenQuadVS (in BlendDepthVertIn IN) {
ScreenVertOut OUT;

OUT.pos = mul (IN.pos, world);
OUT.pos = mul (OUT.pos, view);
OUT.pos = mul (OUT.pos, proj);

OUT.texcoord = IN.texcoord;

return OUT;
}

//------------------------------------------------------------

float4 BlendDepthPS (ScreenVertOut IN): COLOR0 {
// return float4 (tex2D (s0, IN.texcoord).rgb, 1);

float3 color = tex2D (s4, IN.texcoord).rgb;
float depth = tex2D (s0, IN.texcoord).r;
depth = min( tex2D (s0, IN.texcoord + float2(PixelWidth, 0)).r, depth);
depth = min( tex2D (s0, IN.texcoord + float2(-PixelWidth, 0)).r, depth);
depth = min( tex2D (s0, IN.texcoord + float2(0, PixelHeight)).r, depth);
depth = min( tex2D (s0, IN.texcoord + float2(0, -PixelHeight)).r, depth);

//// Display depth buffer for testing
// depth = 1 - saturate (depth / FogRange);
// return float4 (depth, depth, depth, 1);

// Define % to Blend
float blend = saturate ((BlendEnd - depth) / (BlendEnd - BlendStart));

//// Display blend for testing
//return float4( blend, blend, blend, 1 );

return float4 (color, 1 - blend);
}

//------------------------------------------------------------

float4 ClearDepthPS (ScreenVertOut IN): COLOR0 {
return float4 (FLT_MAX / 2, 1, 1, 1);
}

//------------------------------------------------------------

// float blur_weights [4] = { 0.47442968, 0.23392642, 0.02804153, 0.00081723 };

float blur_weights [7] = { 0.199471, 0.176033, 0.120985, 0.064759, 0.026995, 0.008764, 0.002216 };

float2 TwelveKernel [12];

//------------------------------------------------------------

float4 HorizontalBlurPS (ScreenVertOut IN): COLOR0 {
float4 Original = tex2D (s4, IN.texcoord);
float3 Blurred = 0;
float total_weight = 0;

// Early out to prevent night sky blur - tetchy
if (Original.a >= 0.9999) {
return Original;
} else {

for (int i = 0; i < 12; ++i) {
float4 Current = tex2D (s4, IN.texcoord + TwelveKernel [i]);
float weight = saturate (Original.a * Current.a);
Blurred += Current.rgb * weight;
total_weight += weight;
}
Blurred = (Blurred + Original.rgb) / (total_weight + 1.0);

return float4 (Blurred, Original.a);
}
}

//------------------------------------------------------------

float4 VerticalBlurPS (ScreenVertOut IN): COLOR0 {
float4 orig_color = tex2D (s4, IN.texcoord);

// return float4 (orig_color.a, orig_color.a, orig_color.a, orig_color.a);

// Early out to prevent night sky blur - tetchy
if (orig_color.a >= 0.9999) {
return orig_color;
} else {

float2 offset = float2 (0, PixelHeight);

float4 color = 0;

color += tex2D (s4, IN.texcoord - offset * 6) * blur_weights [6];
color += tex2D (s4, IN.texcoord - offset * 5) * blur_weights [5];
color += tex2D (s4, IN.texcoord - offset * 4) * blur_weights [4];
color += tex2D (s4, IN.texcoord - offset * 3) * blur_weights [3];
color += tex2D (s4, IN.texcoord - offset * 2) * blur_weights [2];
color += tex2D (s4, IN.texcoord - offset) * blur_weights [1];
color += orig_color * blur_weights [0];
color += tex2D (s4, IN.texcoord + offset) * blur_weights [1];
color += tex2D (s4, IN.texcoord + offset * 2) * blur_weights [2];
color += tex2D (s4, IN.texcoord + offset * 3) * blur_weights [3];
color += tex2D (s4, IN.texcoord + offset * 4) * blur_weights [4];
color += tex2D (s4, IN.texcoord + offset * 5) * blur_weights [5];
color += tex2D (s4, IN.texcoord + offset * 6) * blur_weights [6];

float blur = saturate (color.a * orig_color.a);

//// Don't let the sky get too blurry// test no longer needed - tetchy
// if (orig_color.a <= 0.0001) {
// blur = max (0.75, blur);
// }

color.rgb = lerp (color.rgb, orig_color.rgb, blur);

return float4 (color.rgb, orig_color.a);
}
}

//------------------------------------------------------------

float4 CopyAndSetAlphaPS (ScreenVertOut IN): COLOR0 {
float3 color = tex2D (s4, IN.texcoord).rgb;

return float4 (color, 1);
}

//------------------------------------------------------------

struct RenderDepthVertOut {
float4 pos: POSITION;
float4 position: TEXCOORD0;
// float4 col: COLOR0;
float2 texcoords: TEXCOORD1;
};

//------------------------------------------------------------

RenderDepthVertOut GrassDepthVS (GrassVertIn IN) {
RenderDepthVertOut OUT;

OUT.texcoords = IN.texcoords;

// Animate grass
float4 worldpos = mul (IN.pos, world);

//distance to grass for range
float gdist = length(worldpos.xy - PlayerPos.xy);

float height = clamp (IN.pos.z, 0, 100) / 100;

float2 wind = WindVec * 2.5 + 0.25;

float2 pos_ticks1 = worldpos.xy / 1000 + ticks;
float2 pos_ticks2 = worldpos.xy / 750 + ticks * 2;
float2 pos_ticks3 = worldpos.xy / 500 + ticks * 3;
float2 pos_ticks4 = worldpos.xy / 200 + ticks * 4;

//grass offset for bending
float2 bend_ticks1 = (worldpos.xy - PlayerPos.xy)/1000 * 1/gdist;
float2 bend_direction = (worldpos.xy - EyePos.xy);


//interactive grass
if ( gdist < 100 ) {
//bend

worldpos.xy += (bend_direction)/abs(bend_direction)*(cos(bend_ticks1)) * height * 1/(25+gdist) * 3500;

worldpos.xy += (gdist)/100*( sin(pos_ticks1) + cos(pos_ticks2) + sin(pos_ticks3) + cos(pos_ticks4) ) * height * wind * 10;

} else {
worldpos.xy += ( sin(pos_ticks1) + cos(pos_ticks2) + sin(pos_ticks3) + cos(pos_ticks4) ) * height * wind * 10;
}


// Projection
OUT.pos = mul (worldpos, view);
OUT.pos = mul (OUT.pos, proj);

OUT.position = OUT.pos;

return OUT;
}

//------------------------------------------------------------

float4 GrassDepthPS (RenderDepthVertOut IN): COLOR0 {
// Apply alpha testing
float alpha = tex2D (s3, IN.texcoords).a;
clip (alpha - 0.5);

return float4 (IN.position.w, 1, 1, 1);
}

//------------------------------------------------------------

RenderDepthVertOut GrassDepthInstVS (StatInstVertIn IN) {
RenderDepthVertOut OUT;

// Pack instance transform
float4x4 worldmat = float4x4 (IN.m1, IN.m2, IN.m3, IN.m4);

OUT.texcoords = IN.texcoords;

float4 worldpos = mul (IN.pos, worldmat);

//distance to grass for range
float gdist = length(worldpos.xy - PlayerPos.xy);

// Animate grass
float height = clamp (IN.pos.z, 0, 100) / 100;

float2 wind = WindVec / 6;

float2 pos_ticks1 = worldpos.xy / 1000 + ticks;
float2 pos_ticks2 = worldpos.xy / 750 + ticks * 2;
float2 pos_ticks3 = worldpos.xy / 500 + ticks * 3;
float2 pos_ticks4 = worldpos.xy / 250 + ticks * 4;

//grass offset for bending
float2 bend_ticks1 = (worldpos.xy - PlayerPos.xy)/1000 * 1/gdist;
float2 bend_direction = (worldpos.xy - EyePos.xy);


//interactive grass
if ( gdist < 100 ) {
//bend

worldpos.xy += (bend_direction)/abs(bend_direction)*(cos(bend_ticks1)) * height * 1/(25+gdist) * 3500;

worldpos.xy += (gdist)/100*( sin(pos_ticks1) + cos(pos_ticks2) + sin(pos_ticks3) + cos(pos_ticks4) ) * height * wind * 10;

} else {
worldpos.xy += ( sin(pos_ticks1) + cos(pos_ticks2) + sin(pos_ticks3) + cos(pos_ticks4) ) * height * wind * 10;
}


// Projection
OUT.pos = mul (worldpos, view);
OUT.pos = mul (OUT.pos, proj);

OUT.position = OUT.pos;

return OUT;
}

//------------------------------------------------------------

struct CausticsVertOut {
float4 pos: POSITION;
float2 tex : TEXCOORD0;
};

//------------------------------------------------------------

CausticsVertOut CausticsVS (in BlendDepthVertIn IN) {
CausticsVertOut OUT;
OUT.pos = mul (IN.pos, proj);
OUT.tex = IN.texcoord;
return OUT;
}

//------------------------------------------------------------

float4 CausticsPS (in CausticsVertOut IN): COLOR0 {
float3 color = tex2D(s4, IN.tex);

float depth = tex2D( s7, IN.tex ).r;
float fog = getFogAlpha(depth);
float blend = saturate( (BlendEnd - depth) / (BlendEnd - BlendStart) );

float3 eyevec = float3(view[0][2],view[1][2],view[2][2]);
eyevec += (1/proj[0][0] * (2*IN.tex.x-1)).xxx * float3(view[0][0],view[1][0],view[2][0]);
eyevec += (-1/proj[1][1] * (2*IN.tex.y-1)).xxx * float3(view[0][1],view[1][1],view[2][1]);

float3 uwpos = EyePos + eyevec * depth;
uwpos.z -= WaterLevel;
float sunraypath = (uwpos.z / SunVec.z);
float caust = tex3D (s5, float3( (uwpos - SunVec * sunraypath).xy / 1104, ticks/2) ).b;
color *= 1.00 + caust * blend * ( max (-uwpos.z, 0) * saturate(exp (uwpos.z / 400)) ) * fog * fog * cauststr;

return float4(color,1);
}

//------------------------------------------------------------

ScreenVertOut WaveVS (in BlendDepthVertIn IN) {
ScreenVertOut OUT;
OUT.pos = mul (IN.pos, proj);
OUT.texcoord = IN.texcoord;
return OUT;
}

//------------------------------------------------------------

static const float waveTexRcpRes2 = 1.5 * waveTexRcpRes;

//------------------------------------------------------------

float4 WavePS (in float2 Tex : TEXCOORD0): COLOR0 {
float4 c = 2 * tex2D (s6, Tex) - (1.0).xxxx;
float4 ret = {0, c.r, 0, 0};

float4 n = {
tex2D (s6, Tex + float2 (waveTexRcpRes, 0)).r,
tex2D (s6, Tex + float2 (-waveTexRcpRes, 0)).r,
tex2D (s6, Tex + float2 (0, waveTexRcpRes)).r,
tex2D (s6, Tex + float2 (0, -waveTexRcpRes)).r
};
float4 n2 = {
tex2D (s6, Tex + float2 (waveTexRcpRes2, 0)).r,
tex2D (s6, Tex + float2 (-waveTexRcpRes2, 0)).r,
tex2D (s6, Tex + float2 (0, waveTexRcpRes2)).r,
tex2D (s6, Tex + float2 (0, -waveTexRcpRes2)).r
};

n = 2 * n - (1.0).xxxx;
// n2 = 2 * n2 - (1.0).xxxx;

float nsum = n.x + n.y + n.z + n.w;

// dampened discrete two - dimensional wave equation
// red channel: u (t)
// green channel: u (t - 1)
// u (t + 1) = (1 - udamp) * u (t) + a * (nsum - 4 * u (t)) + (1 - vdamp) * (u (t) - u (t - 1))
// = a * nsum + ((2 - udamp - vdamp) - 4 * a) * u (t) - (1 - vdamp) * u (t - 1);

#if SHADER_MODEL >= 300
ret.r = 0.14 * nsum + (1.96 - 0.56) * c.r - 0.98 * c.g;
#else
ret.r = 0.10 * nsum + (1.96 - 0.40) * c.r - 0.98 * c.g;
#endif

// if (abs (ret.r) < 0.01) ret.r = 0;
// if (abs (ret.g) < 0.01) ret.g = 0;

// calculate normal map
ret.ba = 2 * (n.xy - n.zw) + (n2.xy - n2.zw);

ret = 0.5f * ret + (0.5f).xxxx;

return ret;
}

//------------------------------------------------------------

static const float playerWaveSize = 12.0f / waveTexWorldSize; // 12 world units radius

//------------------------------------------------------------

float4 PlayerWavePS (in float2 Tex : TEXCOORD0): COLOR0 {
float4 ret = tex2D (s6, Tex);
float wavesize = (1.0 + 0.055 * sin (16 * ticks) + 0.065 * sin (12.87645 * ticks)) * playerWaveSize;
ret.rg *= saturate (2 * abs (length (Tex - RippleOrigin) / wavesize - 1));
return ret;
}

//------------------------------------------------------------

Technique T0 {
//------------------------------------------------------------
// Used to render the reflected landscape
Pass P00 {
#if SHADER_MODEL >= 300
AlphaBlendEnable = true;
SRCBLEND = SRCALPHA;
DESTBLEND = INVSRCALPHA;
#else
AlphaBlendEnable = false;
#endif

AlphaTestEnable = false;
FogEnable = false;
#if SHADER_MODEL >= 300
CullMode = CCW;
#else
CullMode = None;
#endif

ZEnable = true;
ZWriteEnable = true;
ZFunc = LessEqual;

VertexShader = compile VS_SM LandscapeRefVS ();
PixelShader = compile PS_SM LandscapeRefPS ();
}
//------------------------------------------------------------
// Used to render the landscape
Pass P01 {
ZEnable = true;
ZWriteEnable = true;
ZFunc = LessEqual;

AlphaBlendEnable = false;
AlphaTestEnable = false;
CullMode = CW;
FogEnable = false;

VertexShader = compile VS_SM LandscapeVertexShader ();
PixelShader = compile PS_SM LandscapePixelShader ();
}
//------------------------------------------------------------
// Used to render the water in SM 2.0 mode
Pass P02 {
AlphaBlendEnable = false;
AlphaTestEnable = false;
CullMode = CW;
FogEnable = false;
ZEnable = true;
ZWriteEnable = true;
ZFunc = LessEqual;

VertexShader = compile VS_SM WaterVS ();
PixelShader = compile PS_SM ReflectionShader ();
}
//------------------------------------------------------------
// Used to render the water in SM 3.0 mode
Pass P03 {
AlphaBlendEnable = false;
AlphaTestEnable = false;
CullMode = CW;
FogEnable = false;
ZEnable = true;
ZWriteEnable = true;
ZFunc = LessEqual;

VertexShader = compile VS_SM WaterVS ();
PixelShader = compile PS_SM ReflectionShader ();
}
//------------------------------------------------------------
// Used for rendering distant statics
Pass P04 {
AlphaBlendEnable = false;
FogEnable = false;
CullMode = CW;
ZEnable = true;
ZWriteEnable = true;
ZFunc = LessEqual;

VertexShader = compile VS_SM StaticVS ();
PixelShader = compile PS_SM StaticPS ();
}
//------------------------------------------------------------
// Used for rendering the water from underneath
Pass P05 {
AlphaBlendEnable = false;
AlphaTestEnable = false;
CullMode = CCW;
FogEnable = false;
ZEnable = true;
ZWriteEnable = true;
ZFunc = LessEqual;

VertexShader = compile VS_SM WaterVS ();
PixelShader = compile PS_SM UnderWaterPS ();
}
//------------------------------------------------------------
// Used for rendering water in non - reflective mode
Pass P06 {
AlphaBlendEnable = false;
AlphaTestEnable = false;
CullMode = CW;
FogEnable = false;
ZEnable = true;
ZWriteEnable = true;
ZFunc = LessEqual;

VertexShader = compile VS_SM WaterVS ();
PixelShader = compile PS_SM NonReflectionShader ();
}
//------------------------------------------------------------
// Used for rendering reflected statics
Pass P07 {
#if SHADER_MODEL >= 300
AlphaBlendEnable = true;
SRCBLEND = SRCALPHA;
DESTBLEND = INVSRCALPHA;
AlphaTestEnable = false;
#else
AlphaBlendEnable = false;
#endif
FogEnable = false;
CullMode = CCW;
ZEnable = true;
ZWriteEnable = true;
ZFunc = LessEqual;

VertexShader = compile VS_SM StaticReflectionVS ();
PixelShader = compile PS_SM StaticReflectionPS ();
}
//------------------------------------------------------------
// Used for rendering the lowest possible land out into infinity
Pass P08 {
AlphaBlendEnable = false;
#if SHADER_MODEL >= 300
AlphaTestEnable = false;
#endif
CullMode = CW;
FogEnable = false;
ZEnable = true;
ZWriteEnable = false;
ZFunc = LessEqual;

VertexShader = compile VS_SM LowestLandVS ();
PixelShader = compile PS_SM LowestLandPS ();
}
//------------------------------------------------------------
// Used for rendering distant statics with HW instancing
Pass P09 {
AlphaBlendEnable = false;
FogEnable = false;
CullMode = CW;
ZEnable = true;
ZWriteEnable = true;
ZFunc = LessEqual;

VertexShader = compile VS_SM StaticInstVS ();
PixelShader = compile PS_SM StaticPS ();
}
//------------------------------------------------------------
// Used for rendering reflected distant statics with HW instancing
Pass P10 {
#if SHADER_MODEL >= 300
AlphaBlendEnable = true;
SRCBLEND = SRCALPHA;
DESTBLEND = INVSRCALPHA;
AlphaTestEnable = false;
#else
AlphaBlendEnable = false;
#endif
FogEnable = false;
CullMode = CCW;
ZEnable = true;
ZWriteEnable = true;
ZFunc = LessEqual;

VertexShader = compile VS_SM StaticReflectionInstVS ();
PixelShader = compile PS_SM StaticReflectionPS ();
}
//------------------------------------------------------------
// Used for rendering grass
Pass P11 {
AlphaBlendEnable = false;
FogEnable = false;
CullMode = None;
ZEnable = true;
ZWriteEnable = true;
ZFunc = LessEqual;

VertexShader = compile VS_SM GrassVS ();
PixelShader = compile PS_SM GrassPS ();
}
//------------------------------------------------------------
// Used for rendering grass with instancing
Pass P12 {
AlphaBlendEnable = false;
AlphaTestEnable = false;
FogEnable = false;
CullMode = None;
ZEnable = true;
ZWriteEnable = true;
ZFunc = LessEqual;

VertexShader = compile VS_SM GrassInstVS ();
PixelShader = compile PS_SM GrassPS ();
}
//------------------------------------------------------------
// Used for blending what Morrowind draws with what MGE draws
Pass P13 {
AlphaBlendEnable = true;
SRCBLEND = SRCALPHA;
DESTBLEND = INVSRCALPHA;
FogEnable = false;
CullMode = None;
ZEnable = false;
ZWriteEnable = false;

VertexShader = compile VS_SM ScreenQuadVS ();
PixelShader = compile PS_SM BlendDepthPS ();
}
//------------------------------------------------------------
// Used for horizontal blurring
Pass P14 {
AlphaBlendEnable = false;
AlphaTestEnable = false;
FogEnable = false;
CullMode = None;
ZEnable = false;
ZWriteEnable = false;

VertexShader = compile VS_SM ScreenQuadVS ();
PixelShader = compile PS_SM HorizontalBlurPS ();
}
//------------------------------------------------------------
// Used for vertical blurring
Pass P15 {
AlphaBlendEnable = false;
AlphaTestEnable = false;
FogEnable = false;
CullMode = None;
ZEnable = false;
ZWriteEnable = false;

VertexShader = compile VS_SM ScreenQuadVS ();
PixelShader = compile PS_SM VerticalBlurPS ();
}
//------------------------------------------------------------
// Used to copy a texture to the screen while also setting alpha to 0
Pass P16 {
AlphaBlendEnable = false;
AlphaTestEnable = false;
FogEnable = false;
CullMode = None;
ZEnable = false;
ZWriteEnable = false;

VertexShader = compile VS_SM ScreenQuadVS ();
PixelShader = compile PS_SM CopyAndSetAlphaPS ();
}
//------------------------------------------------------------
// Used for rendering grass depth
Pass P17 {
AlphaBlendEnable = false;
FogEnable = false;
CullMode = None;
ZEnable = true;
ZWriteEnable = true;
ZFunc = LessEqual;

VertexShader = compile VS_SM GrassDepthVS ();
PixelShader = compile PS_SM GrassDepthPS ();
}
//------------------------------------------------------------
// Used for rendering grass depth with instancing
Pass P18 {
AlphaBlendEnable = false;
FogEnable = false;
CullMode = None;
ZEnable = true;
ZWriteEnable = true;
ZFunc = LessEqual;

VertexShader = compile VS_SM GrassDepthInstVS ();
PixelShader = compile PS_SM GrassDepthPS ();
}
//------------------------------------------------------------
// Used for rendering the underwater caustic lighting
Pass P19 {
AlphaBlendEnable = false;
AlphaTestEnable = false;
FogEnable = false;
CullMode = None;
ZEnable = false;
ZWriteEnable = false;
VertexShader = compile VS_SM CausticsVS ();
PixelShader = compile PS_SM CausticsPS ();
}
//------------------------------------------------------------
// Used for calculating waves
Pass P20 {
AlphaBlendEnable = false;
AlphaTestEnable = false;
FogEnable = false;
CullMode = None;
ZEnable = false;
ZWriteEnable = false;
VertexShader = compile VS_SM WaveVS ();
PixelShader = compile PS_SM WavePS ();
}
//------------------------------------------------------------
// Used for creating ripples around PC
Pass P21 {
AlphaBlendEnable = false;
AlphaTestEnable = false;
FogEnable = false;
CullMode = None;
ZEnable = false;
ZWriteEnable = false;
VertexShader = compile VS_SM WaveVS ();
PixelShader = compile PS_SM PlayerWavePS ();
}
//------------------------------------------------------------
// Used to set up the render state
Pass Zero { // 22
AlphaBlendEnable = false;
AlphaTestEnable = false;
FogEnable = false;
FogColor = ;
ColorVertex = false;
Lighting = false;
ZEnable = true;
ZWriteEnable = true;
ZFunc = LessEqual;
StencilEnable = false;
ColorWriteEnable = red | green | blue;
CullMode = CCW;
ShadeMode = gouraud;
ColorOp [0] = selectarg1;
ColorOp [1] = disable;
AlphaOp [0] = disable;
AlphaOp [1] = disable;
ResultArg [0] = current;
Texture [0] = null;
Texture [1] = null;
Texture [2] = null;
Texture [3] = null;
Texture [4] = null;
Texture [5] = null;
Texture [6] = null;
Texture [7] = null;
TexCoordIndex [0] = 0;
TexCoordIndex [1] = 1;
TexCoordIndex [2] = 2;
TexCoordIndex [3] = 3;
TexCoordIndex [4] = 4;
TexCoordIndex [5] = 5;
TexCoordIndex [6] = 6;
TexCoordIndex [7] = 7;
TextureTransformFlags [0] = 0;
TextureTransformFlags [1] = 0;
TextureTransformFlags [2] = 0;
TextureTransformFlags [3] = 0;
TextureTransformFlags [4] = 0;
TextureTransformFlags [5] = 0;
TextureTransformFlags [6] = 0;
TextureTransformFlags [7] = 0;
MagFilter [0] = Linear;
MinFilter [0] = Linear;
MipFilter [0] = Linear;
Clipping = true;
}
//------------------------------------------------------------
//Used for rendering the sky
Pass W // 23
{
AlphaBlendEnable=false;
AlphaTestEnable=false;
FogEnable=false;
CullMode=None;
ZEnable=false;
ZWriteEnable=false;
#ifdef SCATTER
VertexShader = compile VS_SM SkyVS();
PixelShader = compile PS_SM SkyPS();
#endif
}
}

User avatar
Spooky Angel
 
Posts: 3500
Joined: Thu Aug 10, 2006 5:41 pm

Post » Sat Jan 15, 2011 6:21 pm

Whenever I try using the copy/pasted ingame.fx files, my distant land refuses to load in game. Can someone more thoroughly explain where the code inserts go?
User avatar
Krystina Proietti
 
Posts: 3388
Joined: Sat Dec 23, 2006 9:02 pm

Post » Sat Jan 15, 2011 11:59 am

Whenever I try using the copy/pasted ingame.fx files, my distant land refuses to load in game. Can someone more thoroughly explain where the code inserts go?


Are you using Phal's latest MGE beta? (version 5)
User avatar
lolli
 
Posts: 3485
Joined: Mon Jan 01, 2007 10:42 am

Post » Sat Jan 15, 2011 2:45 pm

Are you using Phal's latest MGE beta? (version 5)
I sure am.
User avatar
hannaH
 
Posts: 3513
Joined: Tue Aug 15, 2006 4:50 am

Post » Sat Jan 15, 2011 1:37 pm

Find all four instances of
//Animate Grass


in the InGame.fx file, then add the parts in bold:
Spoiler
// Animate grass
float4 worldpos = mul (IN.pos, world);

//distance to grass for range
float gdist = length(worldpos.xy - PlayerPos.xy);


float height = clamp (IN.pos.z, 0, 100) / 100;

float2 wind = WindVec * 2.5 + 0.25;

float2 pos_ticks1 = worldpos.xy / 1000 + ticks;
float2 pos_ticks2 = worldpos.xy / 750 + ticks * 2;
float2 pos_ticks3 = worldpos.xy / 500 + ticks * 3;
float2 pos_ticks4 = worldpos.xy / 200 + ticks * 4;

//grass offset for bending
float2 bend_ticks1 = (worldpos.xy - PlayerPos.xy)/1000 * 1/gdist;
float2 bend_direction = (worldpos.xy - EyePos.xy);


//interactive grass
if ( gdist < 100 ) {
//bend

worldpos.xy += (bend_direction)/abs(bend_direction)*(cos(bend_ticks1)) * height * 1/(25+gdist) * 3500;

worldpos.xy += (gdist)/100*( sin(pos_ticks1) + cos(pos_ticks2) + sin(pos_ticks3) + cos(pos_ticks4) ) * height * wind * 10;

} else {

worldpos.xy += ( sin(pos_ticks1) + cos(pos_ticks2) + sin(pos_ticks3) + cos(pos_ticks4) ) * height * wind * 10;
}

User avatar
Rebecca Clare Smith
 
Posts: 3508
Joined: Fri Aug 04, 2006 4:13 pm

Post » Sat Jan 15, 2011 8:32 pm

Did -exactly- as you instructed, tomerk. Morrowind still fails to load ingame.fx if I alter it. I'm wondering if maybe notepad is saving it in the wrong encoding or something? It defaults to ANSI.

I don't know why this would make a difference, but it's the only other thing I can think of. I've been copying your code to the letter and I've tried several dozen times.

Could someone perhaps upload the .fx file to a file sharing host?

Update: I just tried editing the file in mge's shader editor. Same problem, though. Just tells me that it has nothing to do with notepad. MGE compiles it fine, too (it returns no errors when I click validate).
User avatar
Isabel Ruiz
 
Posts: 3447
Joined: Sat Nov 04, 2006 4:39 am

Post » Sat Jan 15, 2011 5:40 am

Did -exactly- as you instructed, tomerk. Morrowind still fails to load ingame.fx if I alter it. I'm wondering if maybe notepad is saving it in the wrong encoding or something? It defaults to ANSI.

I don't know why this would make a difference, but it's the only other thing I can think of. I've been copying your code to the letter and I've tried several dozen times.

Could someone perhaps upload the .fx file to a file sharing host?

Update: I just tried editing the file in mge's shader editor. Same problem, though. Just tells me that it has nothing to do with notepad. MGE compiles it fine, too (it returns no errors when I click validate).


i share you pain mate, everything i do its like a big screw you from morrowind lol how ever abots ingame worked it made my game run so slowly and lag every second though
User avatar
carly mcdonough
 
Posts: 3402
Joined: Fri Jul 28, 2006 3:23 am

Post » Sat Jan 15, 2011 2:35 pm

i share you pain mate, everything i do its like a big screw you from morrowind lol how ever abots ingame worked it made my game run so slowly and lag every second though
You could try disabling harlanrm's Vivec/Molag Mar sewers waterfalls code
changing
#define SEWERWAVE 1
to
#define SEWERWAVE 0
, maybe it could help FPS, I play with a 3/4 cells draw distance and I am comfortable with 18/20 FPS so I keep them enabled, they are spectacular though
User avatar
Vivien
 
Posts: 3530
Joined: Fri Apr 13, 2007 2:47 pm

Post » Sat Jan 15, 2011 5:29 pm

ive used the ripples before with no no trouble i use them with the old ingame before i got phals so i dont know and my comp spec should be okay is a hp tx2 touch

smart
User avatar
Stay-C
 
Posts: 3514
Joined: Sun Jul 16, 2006 2:04 am

Post » Sat Jan 15, 2011 9:38 am

You chaps are so amazing, Bethesda probably won't even have this in their next few games.
User avatar
Curveballs On Phoenix
 
Posts: 3365
Joined: Sun Jul 01, 2007 4:43 am

Post » Sat Jan 15, 2011 11:23 am

You chaps are so amazing, Bethesda probably won't even have this in their next few games.

:mohawk: :mohawk:
User avatar
SaVino GοΜ
 
Posts: 3360
Joined: Mon Sep 17, 2007 8:00 pm

Post » Sat Jan 15, 2011 6:02 pm

I don't want to beg for someone to upload a working ingame.fx, but I totally will.

I know that it is not that I am making the edits wrong, or if it is then I have absolutely no idea what it might be. I've checked my edits so many times against the code in this thread I could probably make the changes from memory and it still wouldn't work x.x

For reference, MGE gives me an error message "failed to load distant effects file" or something like that. Shaders work (like SSAO), but distant land (including grass) doesn't render and I'm stuck with using Morrowind's stock fog and water. This only happens when I try the new changes to ingame.fx myself: the ingame.fx included in phal's v5 works fine.
User avatar
Syaza Ramali
 
Posts: 3466
Joined: Wed Jan 24, 2007 10:46 am

PreviousNext

Return to III - Morrowind