sqwarmed/sdk_src/materialsystem/stdshaders/water.cpp

801 lines
29 KiB
C++

//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "basevsshader.h"
#include "mathlib/vmatrix.h"
#include "common_hlsl_cpp_consts.h" // hack hack hack!
#include "convar.h"
#include "watercheap_vs20.inc"
#include "watercheap_ps20.inc"
#include "watercheap_ps20b.inc"
#include "water_vs20.inc"
#include "water_ps20.inc"
#include "water_ps20b.inc"
#include "shaderlib/commandbuilder.h"
// NOTE: This has to be the last file included!
#include "tier0/memdbgon.h"
DEFINE_FALLBACK_SHADER( Water, Water_DX9_HDR )
BEGIN_VS_SHADER( Water_DX90,
"Help for Water" )
BEGIN_SHADER_PARAMS
SHADER_PARAM( REFRACTTEXTURE, SHADER_PARAM_TYPE_TEXTURE, "_rt_WaterRefraction", "" )
SHADER_PARAM( REFLECTTEXTURE, SHADER_PARAM_TYPE_TEXTURE, "_rt_WaterReflection", "" )
SHADER_PARAM( REFRACTAMOUNT, SHADER_PARAM_TYPE_FLOAT, "0", "" )
SHADER_PARAM( REFRACTTINT, SHADER_PARAM_TYPE_COLOR, "[1 1 1]", "refraction tint" )
SHADER_PARAM( REFLECTAMOUNT, SHADER_PARAM_TYPE_FLOAT, "0.8", "" )
SHADER_PARAM( REFLECTTINT, SHADER_PARAM_TYPE_COLOR, "[1 1 1]", "reflection tint" )
SHADER_PARAM( NORMALMAP, SHADER_PARAM_TYPE_TEXTURE, "dev/water_normal", "normal map" )
SHADER_PARAM( BUMPFRAME, SHADER_PARAM_TYPE_INTEGER, "0", "frame number for $bumpmap" )
SHADER_PARAM( BUMPTRANSFORM, SHADER_PARAM_TYPE_MATRIX, "center .5 .5 scale 1 1 rotate 0 translate 0 0", "$bumpmap texcoord transform" )
SHADER_PARAM( TIME, SHADER_PARAM_TYPE_FLOAT, "", "" )
SHADER_PARAM( WATERDEPTH, SHADER_PARAM_TYPE_FLOAT, "", "" )
SHADER_PARAM( CHEAPWATERSTARTDISTANCE, SHADER_PARAM_TYPE_FLOAT, "", "This is the distance from the eye in inches that the shader should start transitioning to a cheaper water shader." )
SHADER_PARAM( CHEAPWATERENDDISTANCE, SHADER_PARAM_TYPE_FLOAT, "", "This is the distance from the eye in inches that the shader should finish transitioning to a cheaper water shader." )
SHADER_PARAM( ENVMAP, SHADER_PARAM_TYPE_TEXTURE, "env_cubemap", "envmap" )
SHADER_PARAM( ENVMAPFRAME, SHADER_PARAM_TYPE_INTEGER, "0", "" )
SHADER_PARAM( FOGCOLOR, SHADER_PARAM_TYPE_COLOR, "", "" )
SHADER_PARAM( FORCECHEAP, SHADER_PARAM_TYPE_BOOL, "", "" )
SHADER_PARAM( REFLECTENTITIES, SHADER_PARAM_TYPE_BOOL, "", "" )
SHADER_PARAM( FOGSTART, SHADER_PARAM_TYPE_FLOAT, "", "" )
SHADER_PARAM( FOGEND, SHADER_PARAM_TYPE_FLOAT, "", "" )
SHADER_PARAM( ABOVEWATER, SHADER_PARAM_TYPE_BOOL, "", "" )
SHADER_PARAM( REFLECTBLENDFACTOR, SHADER_PARAM_TYPE_FLOAT, "1.0", "" )
SHADER_PARAM( NOFRESNEL, SHADER_PARAM_TYPE_BOOL, "0", "" )
SHADER_PARAM( NOLOWENDLIGHTMAP, SHADER_PARAM_TYPE_BOOL, "0", "" )
SHADER_PARAM( SCROLL1, SHADER_PARAM_TYPE_COLOR, "", "" )
SHADER_PARAM( SCROLL2, SHADER_PARAM_TYPE_COLOR, "", "" )
SHADER_PARAM( FLOWMAP, SHADER_PARAM_TYPE_TEXTURE, "", "flowmap" )
SHADER_PARAM( FLOWMAPFRAME, SHADER_PARAM_TYPE_INTEGER, "0", "frame number for $flowmap" )
SHADER_PARAM( FLOWMAPSCROLLRATE, SHADER_PARAM_TYPE_VEC2, "[0 0", "2D rate to scroll $flowmap" )
SHADER_PARAM( FLOW_NOISE_TEXTURE, SHADER_PARAM_TYPE_TEXTURE, "", "flow noise texture" )
SHADER_PARAM( FLASHLIGHTTINT, SHADER_PARAM_TYPE_FLOAT, "0", "" )
SHADER_PARAM( LIGHTMAPWATERFOG, SHADER_PARAM_TYPE_BOOL, "0", "" )
SHADER_PARAM( FORCEFRESNEL, SHADER_PARAM_TYPE_FLOAT, "0", "" )
// New flow params
SHADER_PARAM( FLOW_WORLDUVSCALE, SHADER_PARAM_TYPE_FLOAT, "", "" )
SHADER_PARAM( FLOW_NORMALUVSCALE, SHADER_PARAM_TYPE_FLOAT, "", "" )
SHADER_PARAM( FLOW_TIMEINTERVALINSECONDS, SHADER_PARAM_TYPE_FLOAT, "", "" )
SHADER_PARAM( FLOW_UVSCROLLDISTANCE, SHADER_PARAM_TYPE_FLOAT, "", "" )
SHADER_PARAM( FLOW_BUMPSTRENGTH, SHADER_PARAM_TYPE_FLOAT, "", "" )
SHADER_PARAM( FLOW_TIMESCALE, SHADER_PARAM_TYPE_FLOAT, "", "" )
SHADER_PARAM( FLOW_NOISE_SCALE, SHADER_PARAM_TYPE_FLOAT, "", "" )
SHADER_PARAM( FLOW_DEBUG, SHADER_PARAM_TYPE_BOOL, "0", "" )
SHADER_PARAM( COLOR_FLOW_UVSCALE, SHADER_PARAM_TYPE_FLOAT, "", "" )
SHADER_PARAM( COLOR_FLOW_TIMESCALE, SHADER_PARAM_TYPE_FLOAT, "", "" )
SHADER_PARAM( COLOR_FLOW_TIMEINTERVALINSECONDS, SHADER_PARAM_TYPE_FLOAT, "", "" )
SHADER_PARAM( COLOR_FLOW_UVSCROLLDISTANCE, SHADER_PARAM_TYPE_FLOAT, "", "" )
SHADER_PARAM( COLOR_FLOW_LERPEXP, SHADER_PARAM_TYPE_FLOAT, "", "" )
END_SHADER_PARAMS
SHADER_INIT_PARAMS()
{
if( !params[ABOVEWATER]->IsDefined() )
{
Warning( "***need to set $abovewater for material %s\n", pMaterialName );
params[ABOVEWATER]->SetIntValue( 1 );
}
SET_FLAGS2( MATERIAL_VAR2_NEEDS_TANGENT_SPACES );
if( !params[CHEAPWATERSTARTDISTANCE]->IsDefined() )
{
params[CHEAPWATERSTARTDISTANCE]->SetFloatValue( 500.0f );
}
if( !params[CHEAPWATERENDDISTANCE]->IsDefined() )
{
params[CHEAPWATERENDDISTANCE]->SetFloatValue( 1000.0f );
}
if( !params[SCROLL1]->IsDefined() )
{
params[SCROLL1]->SetVecValue( 0.0f, 0.0f, 0.0f );
}
if( !params[SCROLL2]->IsDefined() )
{
params[SCROLL2]->SetVecValue( 0.0f, 0.0f, 0.0f );
}
if( !params[FOGCOLOR]->IsDefined() )
{
params[FOGCOLOR]->SetVecValue( 1.0f, 0.0f, 0.0f );
Warning( "material %s needs to have a $fogcolor.\n", pMaterialName );
}
if( !params[REFLECTENTITIES]->IsDefined() )
{
params[REFLECTENTITIES]->SetIntValue( 0 );
}
if( !params[REFLECTBLENDFACTOR]->IsDefined() )
{
params[REFLECTBLENDFACTOR]->SetFloatValue( 1.0f );
}
InitFloatParam( FLOW_WORLDUVSCALE, params, 1.0f );
InitFloatParam( FLOW_NORMALUVSCALE, params, 1.0f );
InitFloatParam( FLOW_TIMEINTERVALINSECONDS, params, 0.4f );
InitFloatParam( FLOW_UVSCROLLDISTANCE, params, 0.2f );
InitFloatParam( FLOW_BUMPSTRENGTH, params, 1.0f );
InitFloatParam( FLOW_TIMESCALE, params, 1.0f );
InitFloatParam( FLOW_NOISE_SCALE, params, 0.0002f );
InitFloatParam( COLOR_FLOW_UVSCALE, params, 1.0f );
InitFloatParam( COLOR_FLOW_TIMESCALE, params, 1.0f );
InitFloatParam( COLOR_FLOW_TIMEINTERVALINSECONDS, params, 0.4f );
InitFloatParam( COLOR_FLOW_UVSCROLLDISTANCE, params, 0.2f );
InitFloatParam( COLOR_FLOW_LERPEXP, params, 1.0f );
InitIntParam( FORCECHEAP, params, 0 );
InitFloatParam( FLASHLIGHTTINT, params, 1.0f );
InitIntParam( LIGHTMAPWATERFOG, params, 0 );
InitFloatParam( FORCEFRESNEL, params, -1.0f );
// Fallbacks for water need lightmaps usually
if ( params[BASETEXTURE]->IsDefined() || ( params[LIGHTMAPWATERFOG]->GetIntValue() != 0 ) )
{
SET_FLAGS2( MATERIAL_VAR2_LIGHTING_LIGHTMAP );
}
SET_FLAGS2( MATERIAL_VAR2_LIGHTING_LIGHTMAP );
// Don't need bumped lightmaps unless we have a basetexture. We only use them otherwise for lighting the water fog, which only needs one sample.
if( params[BASETEXTURE]->IsDefined() && g_pConfig->UseBumpmapping() && params[NORMALMAP]->IsDefined() )
{
SET_FLAGS2( MATERIAL_VAR2_LIGHTING_BUMPED_LIGHTMAP );
}
}
SHADER_FALLBACK
{
return 0;
}
SHADER_INIT
{
Assert( params[WATERDEPTH]->IsDefined() );
if( params[REFRACTTEXTURE]->IsDefined() )
{
LoadTexture( REFRACTTEXTURE );
}
if( params[REFLECTTEXTURE]->IsDefined() )
{
LoadTexture( REFLECTTEXTURE );
}
if ( params[ENVMAP]->IsDefined() )
{
LoadCubeMap( ENVMAP );
}
if ( params[NORMALMAP]->IsDefined() )
{
LoadBumpMap( NORMALMAP );
}
if( params[BASETEXTURE]->IsDefined() )
{
LoadTexture( BASETEXTURE );
}
if ( params[FLOWMAP]->IsDefined() )
{
LoadTexture( FLOWMAP );
}
if ( params[FLOW_NOISE_TEXTURE]->IsDefined() )
{
LoadTexture( FLOW_NOISE_TEXTURE );
}
}
inline void GetVecParam( int constantVar, float *val )
{
if( constantVar == -1 )
return;
IMaterialVar* pVar = s_ppParams[constantVar];
Assert( pVar );
if (pVar->GetType() == MATERIAL_VAR_TYPE_VECTOR)
pVar->GetVecValue( val, 4 );
else
val[0] = val[1] = val[2] = val[3] = pVar->GetFloatValue();
}
inline void DrawReflectionRefraction( IMaterialVar **params, IShaderShadow* pShaderShadow,
IShaderDynamicAPI* pShaderAPI, bool bReflection, bool bRefraction )
{
Vector4D Scroll1;
params[SCROLL1]->GetVecValue( Scroll1.Base(), 4 );
bool bHasFlowmap = params[FLOWMAP]->IsTexture();
bool hasFlashlight = UsingFlashlight( params );
bool bHasBaseTexture = params[BASETEXTURE]->IsTexture();
bool bHasMultiTexture = fabs( Scroll1.x ) > 0.0f;
bool bLightmapWaterFog = ( params[LIGHTMAPWATERFOG]->GetIntValue() != 0 );
bool bForceFresnel = ( params[FORCEFRESNEL]->GetFloatValue() != -1.0f );
if ( bHasFlowmap )
{
bHasMultiTexture = false;
}
if ( bHasBaseTexture || bHasMultiTexture )
{
//hasFlashlight = false;
//bLightmapWaterFog = false;
}
// LIGHTMAP - needed either with basetexture or lightmapwaterfog. Not sure where the bReflection restriction comes in.
bool bUsingLightmap = bLightmapWaterFog || ( bReflection && bHasBaseTexture );
SHADOW_STATE
{
SetInitialShadowState( );
if ( bRefraction )
{
// refract sampler
pShaderShadow->EnableTexture( SHADER_SAMPLER0, true );
pShaderShadow->EnableSRGBRead( SHADER_SAMPLER0, !IsX360() );
}
if ( bReflection )
{
// reflect sampler
pShaderShadow->EnableTexture( SHADER_SAMPLER1, true );
pShaderShadow->EnableSRGBRead( SHADER_SAMPLER1, !IsX360() );
}
if ( bHasBaseTexture )
{
// BASETEXTURE
pShaderShadow->EnableTexture( SHADER_SAMPLER10, true );
pShaderShadow->EnableSRGBRead( SHADER_SAMPLER10, true );
}
// normal map
pShaderShadow->EnableTexture( SHADER_SAMPLER2, true );
if ( bUsingLightmap )
{
pShaderShadow->EnableTexture( SHADER_SAMPLER3, true );
pShaderShadow->EnableSRGBRead( SHADER_SAMPLER3, false );
}
// flowmap
if ( bHasFlowmap )
{
pShaderShadow->EnableTexture( SHADER_SAMPLER4, true );
pShaderShadow->EnableSRGBRead( SHADER_SAMPLER4, false );
pShaderShadow->EnableTexture( SHADER_SAMPLER5, true );
pShaderShadow->EnableSRGBRead( SHADER_SAMPLER5, false );
}
if( hasFlashlight )
{
pShaderShadow->EnableTexture( SHADER_SAMPLER6, true );
pShaderShadow->EnableTexture( SHADER_SAMPLER7, true );
pShaderShadow->SetShadowDepthFiltering( SHADER_SAMPLER7 );
pShaderShadow->EnableTexture( SHADER_SAMPLER8, true );
}
int fmt = VERTEX_POSITION | VERTEX_NORMAL | VERTEX_TANGENT_S | VERTEX_TANGENT_T;
// texcoord0 : base texcoord
// texcoord1 : lightmap texcoord
// texcoord2 : lightmap texcoord offset
int numTexCoords = 1;
// You need lightmap data if you are using lightmapwaterfog or you have a basetexture.
if ( bLightmapWaterFog || bHasBaseTexture )
{
numTexCoords = 3;
}
pShaderShadow->VertexShaderVertexFormat( fmt, numTexCoords, 0, 0 );
DECLARE_STATIC_VERTEX_SHADER( water_vs20 );
SET_STATIC_VERTEX_SHADER_COMBO( MULTITEXTURE, bHasMultiTexture );
SET_STATIC_VERTEX_SHADER_COMBO( BASETEXTURE, bHasBaseTexture );
SET_STATIC_VERTEX_SHADER_COMBO( FLASHLIGHT, hasFlashlight );
SET_STATIC_VERTEX_SHADER_COMBO( LIGHTMAPWATERFOG, bLightmapWaterFog );
SET_STATIC_VERTEX_SHADER_COMBO( FLOWMAP, bHasFlowmap );
SET_STATIC_VERTEX_SHADER( water_vs20 );
// "REFLECT" "0..1"
// "REFRACT" "0..1"
if ( g_pHardwareConfig->SupportsPixelShaders_2_b() )
{
DECLARE_STATIC_PIXEL_SHADER( water_ps20b );
SET_STATIC_PIXEL_SHADER_COMBO( REFLECT, bReflection );
SET_STATIC_PIXEL_SHADER_COMBO( REFRACT, bRefraction );
SET_STATIC_PIXEL_SHADER_COMBO( ABOVEWATER, params[ABOVEWATER]->GetIntValue() );
SET_STATIC_PIXEL_SHADER_COMBO( MULTITEXTURE, bHasMultiTexture );
SET_STATIC_PIXEL_SHADER_COMBO( BASETEXTURE, bHasBaseTexture );
SET_STATIC_PIXEL_SHADER_COMBO( FLOWMAP, bHasFlowmap );
SET_STATIC_PIXEL_SHADER_COMBO( FLOW_DEBUG, clamp( params[ FLOW_DEBUG ]->GetIntValue(), 0, 2 ) );
SET_STATIC_PIXEL_SHADER_COMBO( FLASHLIGHT, hasFlashlight );
SET_STATIC_PIXEL_SHADER_COMBO( LIGHTMAPWATERFOG, bLightmapWaterFog );
SET_STATIC_PIXEL_SHADER_COMBO( FORCEFRESNEL, bForceFresnel );
SET_STATIC_PIXEL_SHADER( water_ps20b );
}
else
{
DECLARE_STATIC_PIXEL_SHADER( water_ps20 );
SET_STATIC_PIXEL_SHADER_COMBO( REFLECT, bReflection );
SET_STATIC_PIXEL_SHADER_COMBO( REFRACT, bRefraction );
SET_STATIC_PIXEL_SHADER_COMBO( ABOVEWATER, params[ABOVEWATER]->GetIntValue() );
SET_STATIC_PIXEL_SHADER_COMBO( MULTITEXTURE, bHasMultiTexture );
SET_STATIC_PIXEL_SHADER_COMBO( BASETEXTURE, bHasBaseTexture );
// SET_STATIC_PIXEL_SHADER_COMBO( FLOWMAP, bHasFlowmap );
SET_STATIC_PIXEL_SHADER_COMBO( FLOW_DEBUG, clamp( params[ FLOW_DEBUG ]->GetIntValue(), 0, 2 ) );
SET_STATIC_PIXEL_SHADER_COMBO( FORCEFRESNEL, bForceFresnel );
SET_STATIC_PIXEL_SHADER( water_ps20 );
}
FogToFogColor();
// we are writing linear values from this shader.
pShaderShadow->EnableSRGBWrite( true );
pShaderShadow->EnableAlphaWrites( true );
}
DYNAMIC_STATE
{
pShaderAPI->SetDefaultState();
if( bRefraction )
{
// HDRFIXME: add comment about binding.. Specify the number of MRTs in the enable
BindTexture( SHADER_SAMPLER0, REFRACTTEXTURE, -1 );
}
if( bReflection )
{
BindTexture( SHADER_SAMPLER1, REFLECTTEXTURE, -1 );
}
BindTexture( SHADER_SAMPLER2, NORMALMAP, BUMPFRAME );
if ( bUsingLightmap )
{
pShaderAPI->BindStandardTexture( SHADER_SAMPLER3, TEXTURE_LIGHTMAP );
}
if( bHasBaseTexture )
{
BindTexture( SHADER_SAMPLER10, BASETEXTURE, FRAME );
}
if ( bHasFlowmap )
{
BindTexture( SHADER_SAMPLER4, FLOWMAP, FLOWMAPFRAME );
BindTexture( SHADER_SAMPLER5, FLOW_NOISE_TEXTURE );
float vFlowConst1[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
vFlowConst1[0] = 1.0f / params[ FLOW_WORLDUVSCALE ]->GetFloatValue();
vFlowConst1[1] = 1.0f / params[ FLOW_NORMALUVSCALE ]->GetFloatValue();
vFlowConst1[2] = params[ FLOW_BUMPSTRENGTH ]->GetFloatValue();
vFlowConst1[3] = params[ FLOW_TIMESCALE ]->GetFloatValue();
pShaderAPI->SetPixelShaderConstant( 13, vFlowConst1, 1 );
float vFlowConst2[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
vFlowConst2[0] = params[ FLOW_TIMEINTERVALINSECONDS ]->GetFloatValue();
vFlowConst2[1] = params[ FLOW_UVSCROLLDISTANCE ]->GetFloatValue();
vFlowConst2[2] = params[ FLOW_NOISE_SCALE ]->GetFloatValue();
vFlowConst2[3] = params[ COLOR_FLOW_LERPEXP ]->GetFloatValue();
pShaderAPI->SetPixelShaderConstant( 14, vFlowConst2, 1 );
float vColorFlowConst1[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
vColorFlowConst1[0] = 1.0f / params[ COLOR_FLOW_UVSCALE ]->GetFloatValue();
vColorFlowConst1[1] = params[ COLOR_FLOW_TIMESCALE ]->GetFloatValue();
vColorFlowConst1[2] = params[ COLOR_FLOW_TIMEINTERVALINSECONDS ]->GetFloatValue();
vColorFlowConst1[3] = params[ COLOR_FLOW_UVSCROLLDISTANCE ]->GetFloatValue();
pShaderAPI->SetPixelShaderConstant( 26, vColorFlowConst1, 1 );
}
// Time
float vTimeConst[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
float flTime = pShaderAPI->CurrentTime();
vTimeConst[0] = flTime;
//vTimeConst[0] -= ( float )( ( int )( vTimeConst[0] / 1000.0f ) ) * 1000.0f;
pShaderAPI->SetPixelShaderConstant( 8, vTimeConst, 1 );
// These constants are used to rotate the world space water normals around the up axis to align the
// normal with the camera and then give us a 2D offset vector to use for reflection and refraction uv's
VMatrix mView;
pShaderAPI->GetMatrix( MATERIAL_VIEW, mView.m[0] );
mView = mView.Transpose3x3();
Vector4D vCameraRight( mView.m[0][0], mView.m[0][1], mView.m[0][2], 0.0f );
vCameraRight.z = 0.0f; // Project onto the plane of water
vCameraRight.AsVector3D().NormalizeInPlace();
Vector4D vCameraForward;
CrossProduct( Vector( 0.0f, 0.0f, 1.0f ), vCameraRight.AsVector3D(), vCameraForward.AsVector3D() ); // I assume the water surface normal is pointing along z!
pShaderAPI->SetPixelShaderConstant( 22, vCameraRight.Base() );
pShaderAPI->SetPixelShaderConstant( 23, vCameraForward.Base() );
SetPixelShaderConstant( 25, FORCEFRESNEL );
// Refraction tint
if( bRefraction )
{
SetPixelShaderConstantGammaToLinear( 1, REFRACTTINT );
}
// Reflection tint
if( bReflection )
{
if( g_pHardwareConfig->GetHDRType() == HDR_TYPE_INTEGER )
{
// Need to multiply by 4 in linear space since we premultiplied into
// the render target by .25 to get overbright data in the reflection render target.
float gammaReflectTint[3];
params[REFLECTTINT]->GetVecValue( gammaReflectTint, 3 );
float linearReflectTint[4];
linearReflectTint[0] = GammaToLinear( gammaReflectTint[0] ) * 4.0f;
linearReflectTint[1] = GammaToLinear( gammaReflectTint[1] ) * 4.0f;
linearReflectTint[2] = GammaToLinear( gammaReflectTint[2] ) * 4.0f;
linearReflectTint[3] = 1.0f;
pShaderAPI->SetPixelShaderConstant( 4, linearReflectTint, 1 );
}
else
{
SetPixelShaderConstantGammaToLinear( 4, REFLECTTINT );
}
}
SetVertexShaderTextureTransform( VERTEX_SHADER_SHADER_SPECIFIC_CONST_1, BUMPTRANSFORM );
float curtime=pShaderAPI->CurrentTime();
float vc0[4];
float v0[4];
params[SCROLL1]->GetVecValue(v0,4);
vc0[0]=curtime*v0[0];
vc0[1]=curtime*v0[1];
params[SCROLL2]->GetVecValue(v0,4);
vc0[2]=curtime*v0[0];
vc0[3]=curtime*v0[1];
pShaderAPI->SetVertexShaderConstant( VERTEX_SHADER_SHADER_SPECIFIC_CONST_3, vc0, 1 );
float c0[4] = { 1.0f / 3.0f, 1.0f / 3.0f, 1.0f / 3.0f, 0.0f };
pShaderAPI->SetPixelShaderConstant( 0, c0, 1 );
float c2[4] = { 0.5f, 0.5f, 0.5f, 0.5f };
pShaderAPI->SetPixelShaderConstant( 2, c2, 1 );
// fresnel constants
float c3[4] = { 1.0f, 0.0f, 0.0f, 0.0f };
pShaderAPI->SetPixelShaderConstant( 3, c3, 1 );
float c5[4] = { params[REFLECTAMOUNT]->GetFloatValue(), params[REFLECTAMOUNT]->GetFloatValue(),
params[REFRACTAMOUNT]->GetFloatValue(), params[REFRACTAMOUNT]->GetFloatValue() };
pShaderAPI->SetPixelShaderConstant( 5, c5, 1 );
#if 0
SetPixelShaderConstantGammaToLinear( 6, FOGCOLOR );
#else
// Need to use the srgb curve since that we do in UpdatePixelFogColorConstant so that we match the older version of water where we render to an offscreen buffer and fog on the way in.
float fogColorConstant[4];
params[FOGCOLOR]->GetVecValue( fogColorConstant, 3 );
fogColorConstant[3] = 0.0f;
fogColorConstant[0] = SrgbGammaToLinear( fogColorConstant[0] );
fogColorConstant[1] = SrgbGammaToLinear( fogColorConstant[1] );
fogColorConstant[2] = SrgbGammaToLinear( fogColorConstant[2] );
pShaderAPI->SetPixelShaderConstant( 6, fogColorConstant, 1 );
#endif
float c7[4] =
{
params[FOGSTART]->GetFloatValue(),
params[FOGEND]->GetFloatValue() - params[FOGSTART]->GetFloatValue(),
1.0f,
0.0f
};
if (g_pHardwareConfig->GetHDRType() == HDR_TYPE_INTEGER )
{
// water overbright factor
c7[2] = 4.0;
}
pShaderAPI->SetPixelShaderConstant( 7, c7, 1 );
pShaderAPI->SetPixelShaderFogParams( PSREG_FOG_PARAMS );
float vEyePos_SpecExponent[4];
pShaderAPI->GetWorldSpaceCameraPosition( vEyePos_SpecExponent );
vEyePos_SpecExponent[3] = 0.0f;
pShaderAPI->SetPixelShaderConstant( PSREG_EYEPOS_SPEC_EXPONENT, vEyePos_SpecExponent, 1 );
if( bHasFlowmap )
{
SetPixelShaderConstant( 9, FLOWMAPSCROLLRATE );
}
DECLARE_DYNAMIC_VERTEX_SHADER( water_vs20 );
SET_DYNAMIC_VERTEX_SHADER( water_vs20 );
CCommandBufferBuilder< CFixedCommandStorageBuffer< 1000 > > DynamicCmdsOut;
bool bFlashlightShadows = false;
bool bUberlight = false;
if( hasFlashlight )
{
pShaderAPI->GetFlashlightShaderInfo( &bFlashlightShadows, &bUberlight );
DynamicCmdsOut.SetVertexShaderFlashlightState( VERTEX_SHADER_SHADER_SPECIFIC_CONST_4 );
CBCmdSetPixelShaderFlashlightState_t state;
state.m_LightSampler = SHADER_SAMPLER6; // FIXME . . don't want this here.
state.m_DepthSampler = SHADER_SAMPLER7;
state.m_ShadowNoiseSampler = SHADER_SAMPLER8;
state.m_nColorConstant = PSREG_FLASHLIGHT_COLOR;
state.m_nAttenConstant = 15;
state.m_nOriginConstant = 16;
state.m_nDepthTweakConstant = 21;
state.m_nScreenScaleConstant = PSREG_FLASHLIGHT_SCREEN_SCALE;
state.m_nWorldToTextureConstant = -1;
state.m_bFlashlightNoLambert = false;
state.m_bSinglePassFlashlight = true;
DynamicCmdsOut.SetPixelShaderFlashlightState( state );
DynamicCmdsOut.SetPixelShaderConstant( 10, FLASHLIGHTTINT );
}
// Get viewport and render target dimensions and set shader constant to do a 2D mad
int nViewportX, nViewportY, nViewportWidth, nViewportHeight;
pShaderAPI->GetCurrentViewport( nViewportX, nViewportY, nViewportWidth, nViewportHeight );
int nRtWidth, nRtHeight;
pShaderAPI->GetCurrentRenderTargetDimensions( nRtWidth, nRtHeight );
float vViewportMad[4];
// viewport->screen transform
vViewportMad[0] = ( float )nViewportWidth / ( float )nRtWidth;
vViewportMad[1] = ( float )nViewportHeight / ( float )nRtHeight;
vViewportMad[2] = ( float )nViewportX / ( float )nRtWidth;
vViewportMad[3] = ( float )nViewportY / ( float )nRtHeight;
DynamicCmdsOut.SetPixelShaderConstant( 24, vViewportMad, 1 );
if ( g_pHardwareConfig->SupportsPixelShaders_2_b() )
{
DECLARE_DYNAMIC_PIXEL_SHADER( water_ps20b );
SET_DYNAMIC_PIXEL_SHADER_COMBO( FLASHLIGHTSHADOWS, bFlashlightShadows );
SET_DYNAMIC_PIXEL_SHADER( water_ps20b );
}
else
{
DECLARE_DYNAMIC_PIXEL_SHADER( water_ps20 );
SET_DYNAMIC_PIXEL_SHADER( water_ps20 );
}
DynamicCmdsOut.End();
pShaderAPI->ExecuteCommandBuffer( DynamicCmdsOut.Base() );
}
Draw();
}
inline void DrawCheapWater( IMaterialVar **params, IShaderShadow* pShaderShadow,
IShaderDynamicAPI* pShaderAPI, bool bBlend, bool bRefraction )
{
bool bHasFlowmap = params[FLOWMAP]->IsTexture();
SHADOW_STATE
{
SetInitialShadowState( );
// In edit mode, use nocull
if ( UsingEditor( params ) )
{
s_pShaderShadow->EnableCulling( false );
}
if( bBlend )
{
EnableAlphaBlending( SHADER_BLEND_SRC_ALPHA, SHADER_BLEND_ONE_MINUS_SRC_ALPHA );
}
// envmap
pShaderShadow->EnableTexture( SHADER_SAMPLER0, true );
// normal map
pShaderShadow->EnableTexture( SHADER_SAMPLER1, true );
if( bRefraction && bBlend )
{
// refraction map (used for alpha)
pShaderShadow->EnableTexture( SHADER_SAMPLER2, true );
}
// Noise texture
if ( bHasFlowmap )
{
pShaderShadow->EnableTexture( SHADER_SAMPLER3, true );
pShaderShadow->EnableTexture( SHADER_SAMPLER4, true );
}
// Normalizing cube map
pShaderShadow->EnableTexture( SHADER_SAMPLER6, true );
int fmt = VERTEX_POSITION | VERTEX_NORMAL | VERTEX_TANGENT_S | VERTEX_TANGENT_T;
pShaderShadow->VertexShaderVertexFormat( fmt, 1, 0, 0 );
DECLARE_STATIC_VERTEX_SHADER( watercheap_vs20 );
SET_STATIC_VERTEX_SHADER_COMBO( BLEND, bBlend && bRefraction );
SET_STATIC_VERTEX_SHADER( watercheap_vs20 );
if( g_pHardwareConfig->SupportsPixelShaders_2_b() )
{
DECLARE_STATIC_PIXEL_SHADER( watercheap_ps20b );
SET_STATIC_PIXEL_SHADER_COMBO( FRESNEL, params[NOFRESNEL]->GetIntValue() == 0 );
SET_STATIC_PIXEL_SHADER_COMBO( BLEND, bBlend );
SET_STATIC_PIXEL_SHADER_COMBO( REFRACTALPHA, bRefraction );
SET_STATIC_PIXEL_SHADER_COMBO( HDRTYPE, g_pHardwareConfig->GetHDRType() );
Vector4D Scroll1;
params[SCROLL1]->GetVecValue( Scroll1.Base(), 4 );
SET_STATIC_PIXEL_SHADER_COMBO( MULTITEXTURE,fabs(Scroll1.x) > 0.0);
SET_STATIC_PIXEL_SHADER_COMBO( FLOWMAP, bHasFlowmap );
SET_STATIC_PIXEL_SHADER_COMBO( FLOW_DEBUG, clamp( params[ FLOW_DEBUG ]->GetIntValue(), 0, 2 ) );
SET_STATIC_PIXEL_SHADER( watercheap_ps20b );
}
else
{
DECLARE_STATIC_PIXEL_SHADER( watercheap_ps20 );
SET_STATIC_PIXEL_SHADER_COMBO( FRESNEL, params[NOFRESNEL]->GetIntValue() == 0 );
SET_STATIC_PIXEL_SHADER_COMBO( BLEND, bBlend );
SET_STATIC_PIXEL_SHADER_COMBO( REFRACTALPHA, bRefraction );
SET_STATIC_PIXEL_SHADER_COMBO( HDRTYPE, g_pHardwareConfig->GetHDRType() );
Vector4D Scroll1;
params[SCROLL1]->GetVecValue( Scroll1.Base(), 4 );
SET_STATIC_PIXEL_SHADER_COMBO( MULTITEXTURE,fabs(Scroll1.x) > 0.0);
SET_STATIC_PIXEL_SHADER_COMBO( FLOWMAP, bHasFlowmap );
SET_STATIC_PIXEL_SHADER_COMBO( FLOW_DEBUG, clamp( params[ FLOW_DEBUG ]->GetIntValue(), 0, 2 ) );
SET_STATIC_PIXEL_SHADER( watercheap_ps20 );
}
// HDRFIXME: test cheap water!
if( g_pHardwareConfig->GetHDRType() != HDR_TYPE_NONE )
{
// we are writing linear values from this shader.
pShaderShadow->EnableSRGBWrite( true );
}
FogToFogColor();
}
DYNAMIC_STATE
{
pShaderAPI->SetDefaultState();
BindTexture( SHADER_SAMPLER0, ENVMAP, ENVMAPFRAME );
BindTexture( SHADER_SAMPLER1, NORMALMAP, BUMPFRAME );
if( bRefraction && bBlend )
{
BindTexture( SHADER_SAMPLER2, REFRACTTEXTURE, -1 );
}
if ( bHasFlowmap )
{
BindTexture( SHADER_SAMPLER3, FLOWMAP );
BindTexture( SHADER_SAMPLER4, FLOW_NOISE_TEXTURE );
float vFlowConst1[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
vFlowConst1[0] = 1.0f / params[ FLOW_WORLDUVSCALE ]->GetFloatValue();
vFlowConst1[1] = 1.0f / params[ FLOW_NORMALUVSCALE ]->GetFloatValue();
vFlowConst1[2] = params[ FLOW_BUMPSTRENGTH ]->GetFloatValue();
vFlowConst1[3] = params[ FLOW_TIMESCALE ]->GetFloatValue();
pShaderAPI->SetPixelShaderConstant( 13, vFlowConst1, 1 );
float vFlowConst2[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
vFlowConst2[0] = params[ FLOW_TIMEINTERVALINSECONDS ]->GetFloatValue();
vFlowConst2[1] = params[ FLOW_UVSCROLLDISTANCE ]->GetFloatValue();
vFlowConst2[2] = params[ FLOW_NOISE_SCALE ]->GetFloatValue();
pShaderAPI->SetPixelShaderConstant( 14, vFlowConst2, 1 );
// Time % 1000
float vTimeConst[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
float flTime = pShaderAPI->CurrentTime();
vTimeConst[0] = flTime;
//vTimeConst[0] -= ( float )( ( int )( vTimeConst[0] / 1000.0f ) ) * 1000.0f;
pShaderAPI->SetPixelShaderConstant( 10, vTimeConst, 1 );
}
pShaderAPI->BindStandardTexture( SHADER_SAMPLER6, TEXTURE_NORMALIZATION_CUBEMAP_SIGNED );
SetPixelShaderConstant( 0, FOGCOLOR );
float cheapWaterStartDistance = params[CHEAPWATERSTARTDISTANCE]->GetFloatValue();
float cheapWaterEndDistance = params[CHEAPWATERENDDISTANCE]->GetFloatValue();
float cheapWaterParams[4] =
{
cheapWaterStartDistance * VSHADER_VECT_SCALE,
cheapWaterEndDistance * VSHADER_VECT_SCALE,
PSHADER_VECT_SCALE / ( cheapWaterEndDistance - cheapWaterStartDistance ),
cheapWaterStartDistance / ( cheapWaterEndDistance - cheapWaterStartDistance ),
};
pShaderAPI->SetPixelShaderConstant( 1, cheapWaterParams );
if( g_pConfig->bShowSpecular )
{
SetPixelShaderConstant( 2, REFLECTTINT, REFLECTBLENDFACTOR );
}
else
{
float zero[4] = { 0.0f, 0.0f, 0.0f, params[REFLECTBLENDFACTOR]->GetFloatValue() };
pShaderAPI->SetPixelShaderConstant( 2, zero );
}
pShaderAPI->SetPixelShaderFogParams( PSREG_FOG_PARAMS );
float vEyePos_SpecExponent[4];
pShaderAPI->GetWorldSpaceCameraPosition( vEyePos_SpecExponent );
vEyePos_SpecExponent[3] = 0.0f;
pShaderAPI->SetPixelShaderConstant( PSREG_EYEPOS_SPEC_EXPONENT, vEyePos_SpecExponent, 1 );
if( params[SCROLL1]->IsDefined())
{
float curtime=pShaderAPI->CurrentTime();
float vc0[4];
float v0[4];
params[SCROLL1]->GetVecValue(v0,4);
vc0[0]=curtime*v0[0];
vc0[1]=curtime*v0[1];
params[SCROLL2]->GetVecValue(v0,4);
vc0[2]=curtime*v0[0];
vc0[3]=curtime*v0[1];
pShaderAPI->SetVertexShaderConstant( VERTEX_SHADER_SHADER_SPECIFIC_CONST_3, vc0, 1 );
}
DECLARE_DYNAMIC_VERTEX_SHADER( watercheap_vs20 );
SET_DYNAMIC_VERTEX_SHADER( watercheap_vs20 );
if( g_pHardwareConfig->SupportsPixelShaders_2_b() )
{
DECLARE_DYNAMIC_PIXEL_SHADER( watercheap_ps20b );
SET_DYNAMIC_PIXEL_SHADER_COMBO( HDRENABLED, IsHDREnabled() );
SET_DYNAMIC_PIXEL_SHADER( watercheap_ps20b );
}
else
{
DECLARE_DYNAMIC_PIXEL_SHADER( watercheap_ps20 );
SET_DYNAMIC_PIXEL_SHADER_COMBO( HDRENABLED, IsHDREnabled() );
SET_DYNAMIC_PIXEL_SHADER( watercheap_ps20 );
}
}
Draw();
}
SHADER_DRAW
{
bool bRefraction = params[REFRACTTEXTURE]->IsTexture();
bool bReflection = params[REFLECTTEXTURE]->IsTexture();
bool bForceCheap = ( params[FORCECHEAP]->GetIntValue() != 0 );
if ( ( bReflection || bRefraction ) && !UsingEditor( params ) && !bForceCheap )
{
DrawReflectionRefraction( params, pShaderShadow, pShaderAPI, bReflection, bRefraction );
}
else
{
bool bBlend = false;
DrawCheapWater( params, pShaderShadow, pShaderAPI, bBlend, bRefraction );
}
}
END_SHADER
//-----------------------------------------------------------------------------
// This allows us to use a block labelled 'Water_DX9_HDR' in the water materials
//-----------------------------------------------------------------------------
BEGIN_INHERITED_SHADER( Water_DX9_HDR, Water_DX90,
"Help for Water_DX9_HDR" )
SHADER_FALLBACK
{
if( g_pHardwareConfig->GetHDRType() == HDR_TYPE_NONE )
{
return "WATER_DX90";
}
return 0;
}
END_INHERITED_SHADER