void Draw_Eyes_Refract_Internal( CBaseVSShader *pShader, IMaterialVar** params, IShaderDynamicAPI *pShaderAPI,
	IShaderShadow* pShaderShadow, bool bDrawFlashlightAdditivePass, Eye_Refract_Vars_t &info, VertexCompressionType_t vertexCompression )
{
	bool bDiffuseWarp = IS_PARAM_DEFINED( info.m_nDiffuseWarpTexture );
	bool bIntro = IS_PARAM_DEFINED( info.m_nIntro ) ? ( params[info.m_nIntro]->GetIntValue() ? true : false ) : false;

	SHADOW_STATE
	{
		SET_FLAGS2( MATERIAL_VAR2_LIGHTING_VERTEX_LIT );

		pShaderShadow->EnableTexture( SHADER_SAMPLER0, true );	// Cornea normal
		pShaderShadow->EnableTexture( SHADER_SAMPLER1, true );	// Iris
		pShaderShadow->EnableTexture( SHADER_SAMPLER2, true );	// Cube reflection
		pShaderShadow->EnableTexture( SHADER_SAMPLER3, true );	// Ambient occlusion

		// Set stream format (note that this shader supports compression)
		unsigned int flags = VERTEX_POSITION | VERTEX_NORMAL | VERTEX_FORMAT_COMPRESSED;
		int nTexCoordCount = 1;
		int userDataSize = 0;
		pShaderShadow->VertexShaderVertexFormat( flags, nTexCoordCount, NULL, userDataSize );

		if ( bDiffuseWarp )
		{
			pShaderShadow->EnableTexture( SHADER_SAMPLER4, true );	// Light warp
		}

#if !defined( PLATFORM_X360 )
		bool bWorldNormal = ( ENABLE_FIXED_LIGHTING_OUTPUTNORMAL_AND_DEPTH == ( IS_FLAG2_SET( MATERIAL_VAR2_USE_GBUFFER0 ) + 2 * IS_FLAG2_SET( MATERIAL_VAR2_USE_GBUFFER1 )));
#endif

		int nShadowFilterMode = 0;
		if ( bDrawFlashlightAdditivePass == true )
		{
			if ( g_pHardwareConfig->SupportsPixelShaders_2_b() )
			{
				nShadowFilterMode = g_pHardwareConfig->GetShadowFilterMode();	// Based upon vendor and device dependent formats
			}

			pShaderShadow->EnableDepthWrites( false );
			pShaderShadow->EnableAlphaWrites( false );
			pShader->EnableAlphaBlending( SHADER_BLEND_ONE, SHADER_BLEND_ONE ); // Additive blending 
			pShaderShadow->EnableTexture( SHADER_SAMPLER5, true );	// Flashlight cookie
		}
		else
		{
			pShaderShadow->EnableAlphaWrites( true );
		}

#ifndef _X360
		if ( !g_pHardwareConfig->HasFastVertexTextures() )
#endif
		{
			DECLARE_STATIC_VERTEX_SHADER( eye_refract_vs20 );
			SET_STATIC_VERTEX_SHADER_COMBO( HALFLAMBERT, IS_FLAG_SET( MATERIAL_VAR_HALFLAMBERT ) );
			SET_STATIC_VERTEX_SHADER_COMBO( INTRO, bIntro ? 1 : 0 );
			SET_STATIC_VERTEX_SHADER_COMBO( FLASHLIGHT, bDrawFlashlightAdditivePass ? 1 : 0 );
			SET_STATIC_VERTEX_SHADER_COMBO( LIGHTWARPTEXTURE, bDiffuseWarp ? 1 : 0 );
			SET_STATIC_VERTEX_SHADER_COMBO( WORLD_NORMAL, 0 );
			SET_STATIC_VERTEX_SHADER( eye_refract_vs20 );

			if ( g_pHardwareConfig->SupportsPixelShaders_2_b() )
			{
				bool bSphereTexKillCombo = IS_PARAM_DEFINED( info.m_nSphereTexKillCombo ) ? ( params[info.m_nSphereTexKillCombo]->GetIntValue() ? true : false ) : ( kDefaultSphereTexKillCombo ? true : false );
				bool bRayTraceSphere = IS_PARAM_DEFINED( info.m_nRaytraceSphere ) ? ( params[info.m_nRaytraceSphere]->GetIntValue() ? true : false ) : ( kDefaultRaytraceSphere ? true : false );

				DECLARE_STATIC_PIXEL_SHADER( eye_refract_ps20b );
				SET_STATIC_PIXEL_SHADER_COMBO( SPHERETEXKILLCOMBO, bSphereTexKillCombo ? 1 : 0 );
				SET_STATIC_PIXEL_SHADER_COMBO( RAYTRACESPHERE, bRayTraceSphere ? 1 : 0 );
				SET_STATIC_PIXEL_SHADER_COMBO( FLASHLIGHT, bDrawFlashlightAdditivePass ? 1 : 0 );
				SET_STATIC_PIXEL_SHADER_COMBO( LIGHTWARPTEXTURE, bDiffuseWarp ? 1 : 0 );
				SET_STATIC_PIXEL_SHADER_COMBO( FLASHLIGHTDEPTHFILTERMODE, nShadowFilterMode );
				SET_STATIC_PIXEL_SHADER_COMBO( WORLD_NORMAL, 0 );
				SET_STATIC_PIXEL_SHADER( eye_refract_ps20b );

				if ( bDrawFlashlightAdditivePass == true )
				{
					pShaderShadow->EnableTexture( SHADER_SAMPLER6, true );	// Shadow depth map
					pShaderShadow->SetShadowDepthFiltering( SHADER_SAMPLER6 );
					pShaderShadow->EnableTexture( SHADER_SAMPLER7, true );	// Noise map
				}
			}
			else
			{
				DECLARE_STATIC_PIXEL_SHADER( eye_refract_ps20 );
				SET_STATIC_PIXEL_SHADER_COMBO( FLASHLIGHT, bDrawFlashlightAdditivePass ? 1 : 0 );
				SET_STATIC_PIXEL_SHADER_COMBO( LIGHTWARPTEXTURE, bDiffuseWarp ? 1 : 0 );
				SET_STATIC_PIXEL_SHADER_COMBO( WORLD_NORMAL, 0 );
				SET_STATIC_PIXEL_SHADER( eye_refract_ps20 );
			}
		}
#ifndef _X360
		else
		{
			pShaderShadow->EnableTexture( SHADER_SAMPLER8, true );	// Screen space ambient occlusion

			// The vertex shader uses the vertex id stream
			SET_FLAGS2( MATERIAL_VAR2_USES_VERTEXID );
			SET_FLAGS2( MATERIAL_VAR2_SUPPORTS_TESSELLATION );

			DECLARE_STATIC_VERTEX_SHADER( eye_refract_vs30 );
			SET_STATIC_VERTEX_SHADER_COMBO( HALFLAMBERT, IS_FLAG_SET( MATERIAL_VAR_HALFLAMBERT ) );
			SET_STATIC_VERTEX_SHADER_COMBO( INTRO, bIntro ? 1 : 0 );
			SET_STATIC_VERTEX_SHADER_COMBO( FLASHLIGHT, bDrawFlashlightAdditivePass ? 1 : 0 );
			SET_STATIC_VERTEX_SHADER_COMBO( LIGHTWARPTEXTURE, bDiffuseWarp ? 1 : 0 );
			SET_STATIC_VERTEX_SHADER_COMBO( WORLD_NORMAL, bWorldNormal );
			SET_STATIC_VERTEX_SHADER( eye_refract_vs30 );

			bool bSphereTexKillCombo = IS_PARAM_DEFINED( info.m_nSphereTexKillCombo ) ? ( params[info.m_nSphereTexKillCombo]->GetIntValue() ? true : false ) : ( kDefaultSphereTexKillCombo ? true : false );
			bool bRayTraceSphere = IS_PARAM_DEFINED( info.m_nRaytraceSphere ) ? ( params[info.m_nRaytraceSphere]->GetIntValue() ? true : false ) : ( kDefaultRaytraceSphere ? true : false );

			DECLARE_STATIC_PIXEL_SHADER( eye_refract_ps30 );
			SET_STATIC_PIXEL_SHADER_COMBO( SPHERETEXKILLCOMBO, bSphereTexKillCombo ? 1 : 0 );
			SET_STATIC_PIXEL_SHADER_COMBO( RAYTRACESPHERE, bRayTraceSphere ? 1 : 0 );
			SET_STATIC_PIXEL_SHADER_COMBO( FLASHLIGHT, bDrawFlashlightAdditivePass ? 1 : 0 );
			SET_STATIC_PIXEL_SHADER_COMBO( LIGHTWARPTEXTURE, bDiffuseWarp ? 1 : 0 );
			SET_STATIC_PIXEL_SHADER_COMBO( FLASHLIGHTDEPTHFILTERMODE, nShadowFilterMode );
			SET_STATIC_PIXEL_SHADER_COMBO( WORLD_NORMAL, bWorldNormal );
			SET_STATIC_PIXEL_SHADER( eye_refract_ps30 );

			if ( bDrawFlashlightAdditivePass == true )
			{
				pShaderShadow->EnableTexture( SHADER_SAMPLER6, true );	// Shadow depth map
				pShaderShadow->EnableTexture( SHADER_SAMPLER7, true );	// Noise map
			}
		}
#endif

		// On DX9, get the gamma read and write correct
		//pShaderShadow->EnableSRGBRead( SHADER_SAMPLER0, false );		// Cornea normal
		pShaderShadow->EnableSRGBRead( SHADER_SAMPLER1, true );			// Iris
		pShaderShadow->EnableSRGBRead( SHADER_SAMPLER2, true );			// Cube map reflection
		pShaderShadow->EnableSRGBRead( SHADER_SAMPLER3, true );			// Ambient occlusion
		pShaderShadow->EnableSRGBWrite( true );

		if ( bDiffuseWarp )
		{
			pShaderShadow->EnableSRGBRead( SHADER_SAMPLER4, true );		// Light Warp
		}

		if ( bDrawFlashlightAdditivePass == true )
		{
			pShaderShadow->EnableSRGBRead( SHADER_SAMPLER5, true );		// Flashlight cookie
		}

		// Fog
		if ( bDrawFlashlightAdditivePass == true )
		{
			pShader->FogToBlack();
		}
		else
		{
			pShader->FogToFogColor();
		}

		// Per-instance state
		pShader->PI_BeginCommandBuffer();
		if ( !bDrawFlashlightAdditivePass )
		{
			pShader->PI_SetPixelShaderLocalLighting( PSREG_LIGHT_INFO_ARRAY );
		}
		pShader->PI_SetVertexShaderAmbientLightCube();
		pShader->PI_SetPixelShaderAmbientLightCubeLuminance( 10 );
		pShader->PI_EndCommandBuffer();
	}
	DYNAMIC_STATE
	{
		VMatrix worldToTexture;
		ITexture *pFlashlightDepthTexture = NULL;
		FlashlightState_t flashlightState;
		bool bFlashlightShadows = false;
		if ( bDrawFlashlightAdditivePass == true )
		{
			flashlightState = pShaderAPI->GetFlashlightStateEx( worldToTexture, &pFlashlightDepthTexture );
			bFlashlightShadows = flashlightState.m_bEnableShadows;
		}

		bool bSinglePassFlashlight = false;

		pShader->BindTexture( SHADER_SAMPLER0, info.m_nCorneaTexture );
		pShader->BindTexture( SHADER_SAMPLER1, info.m_nIris, info.m_nIrisFrame );
		pShader->BindTexture( SHADER_SAMPLER2, info.m_nEnvmap );
		pShader->BindTexture( SHADER_SAMPLER3, info.m_nAmbientOcclTexture );
	
		if ( bDiffuseWarp )
		{
			if ( r_lightwarpidentity.GetBool() )
			{
				pShaderAPI->BindStandardTexture( SHADER_SAMPLER4, TEXTURE_IDENTITY_LIGHTWARP );
			}
			else
			{
				pShader->BindTexture( SHADER_SAMPLER4, info.m_nDiffuseWarpTexture );
			}
		}

		// On PC, we sample from ambient occlusion texture
		if ( IsPC() && g_pHardwareConfig->HasFastVertexTextures() )
		{
			ITexture *pAOTexture = pShaderAPI->GetTextureRenderingParameter( TEXTURE_RENDERPARM_AMBIENT_OCCLUSION );

			if ( pAOTexture )
			{
				pShader->BindTexture( SHADER_SAMPLER8, pAOTexture );
			}
			else
			{
				pShaderAPI->BindStandardTexture( SHADER_SAMPLER8, TEXTURE_WHITE );
			}
		}

		if ( bDrawFlashlightAdditivePass == true )
			pShader->BindTexture( SHADER_SAMPLER5, flashlightState.m_pSpotlightTexture, flashlightState.m_nSpotlightTextureFrame );

		pShader->SetVertexShaderConstant( VERTEX_SHADER_SHADER_SPECIFIC_CONST_0, info.m_nEyeOrigin );
		pShader->SetVertexShaderConstant( VERTEX_SHADER_SHADER_SPECIFIC_CONST_2, info.m_nIrisU );
		pShader->SetVertexShaderConstant( VERTEX_SHADER_SHADER_SPECIFIC_CONST_3, info.m_nIrisV );

		if ( bDrawFlashlightAdditivePass == true )
			pShaderAPI->SetVertexShaderConstant( VERTEX_SHADER_SHADER_SPECIFIC_CONST_4, flashlightState.m_vecLightOrigin.Base(), 1 );

		LightState_t lightState = { 0, false, false };
		if ( bDrawFlashlightAdditivePass == false )
		{
			pShaderAPI->GetDX9LightState( &lightState );
		}

		int nFixedLightingMode = pShaderAPI->GetIntRenderingParameter( INT_RENDERPARM_ENABLE_FIXED_LIGHTING );

#ifndef _X360
		if ( !g_pHardwareConfig->HasFastVertexTextures() )
#endif
		{
			DECLARE_DYNAMIC_VERTEX_SHADER( eye_refract_vs20 );
			SET_DYNAMIC_VERTEX_SHADER_COMBO( SKINNING, pShaderAPI->GetCurrentNumBones() > 0 );
			SET_DYNAMIC_VERTEX_SHADER_COMBO( DYNAMIC_LIGHT, lightState.HasDynamicLight() );
			SET_DYNAMIC_VERTEX_SHADER_COMBO( NUM_LIGHTS, lightState.m_nNumLights );
			SET_DYNAMIC_VERTEX_SHADER_COMBO( COMPRESSED_VERTS, (int)vertexCompression );
			SET_DYNAMIC_VERTEX_SHADER_COMBO( TESSELLATION, 0 );
			SET_DYNAMIC_VERTEX_SHADER( eye_refract_vs20 );
		}
#ifndef _X360
		else
		{
			pShader->SetHWMorphVertexShaderState( VERTEX_SHADER_SHADER_SPECIFIC_CONST_10, VERTEX_SHADER_SHADER_SPECIFIC_CONST_11, SHADER_VERTEXTEXTURE_SAMPLER0 );

			if ( nFixedLightingMode == ENABLE_FIXED_LIGHTING_OUTPUTNORMAL_AND_DEPTH )
			{
				float vEyeDir[4];
				pShaderAPI->GetWorldSpaceCameraDirection( vEyeDir );

				float flFarZ = pShaderAPI->GetFarZ();
				vEyeDir[0] /= flFarZ;	// Divide by farZ for SSAO algorithm
				vEyeDir[1] /= flFarZ;
				vEyeDir[2] /= flFarZ;
				pShaderAPI->SetVertexShaderConstant( VERTEX_SHADER_SHADER_SPECIFIC_CONST_5, vEyeDir );
			}

			TessellationMode_t nTessellationMode = pShaderAPI->GetTessellationMode();
			if ( nTessellationMode != TESSELLATION_MODE_DISABLED )
			{
				pShaderAPI->BindStandardVertexTexture( SHADER_VERTEXTEXTURE_SAMPLER1, TEXTURE_SUBDIVISION_PATCHES );

				bool bHasDisplacement = false; // TODO
				float vSubDDimensions[4] = { 1.0f/pShaderAPI->GetSubDHeight(), bHasDisplacement && mat_displacementmap.GetBool() ? 1.0f : 0.0f, 0.0f, 0.0f };
				pShaderAPI->SetVertexShaderConstant( VERTEX_SHADER_SHADER_SPECIFIC_CONST_1, vSubDDimensions );
			}

			DECLARE_DYNAMIC_VERTEX_SHADER( eye_refract_vs30 );
			SET_DYNAMIC_VERTEX_SHADER_COMBO( SKINNING, pShaderAPI->GetCurrentNumBones() > 0 );
			SET_DYNAMIC_VERTEX_SHADER_COMBO( DYNAMIC_LIGHT, lightState.HasDynamicLight() );
			SET_DYNAMIC_VERTEX_SHADER_COMBO( NUM_LIGHTS, lightState.m_nNumLights );
			SET_DYNAMIC_VERTEX_SHADER_COMBO( COMPRESSED_VERTS, (int)vertexCompression );
			SET_DYNAMIC_VERTEX_SHADER_COMBO( TESSELLATION, nTessellationMode );
			SET_DYNAMIC_VERTEX_SHADER( eye_refract_vs30 );
		}
#endif

		// Special constant for DX9 eyes: { Dilation, Glossiness, x, x };
		float vPSConst[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
		vPSConst[0] = IS_PARAM_DEFINED( info.m_nDilation ) ? params[info.m_nDilation]->GetFloatValue() : kDefaultDilation;
		vPSConst[1] = IS_PARAM_DEFINED( info.m_nGlossiness ) ? params[info.m_nGlossiness]->GetFloatValue() : kDefaultGlossiness;
		vPSConst[2] = 0.0f; // NOT USED
		vPSConst[3] = IS_PARAM_DEFINED( info.m_nCorneaBumpStrength ) ? params[info.m_nCorneaBumpStrength]->GetFloatValue() : kDefaultCorneaBumpStrength;
		pShaderAPI->SetPixelShaderConstant( 0, vPSConst, 1 );

		pShaderAPI->SetPixelShaderConstant( 1, IS_PARAM_DEFINED( info.m_nEyeOrigin ) ? params[info.m_nEyeOrigin]->GetVecValue() : kDefaultEyeOrigin, 1 );
		pShaderAPI->SetPixelShaderConstant( 2, IS_PARAM_DEFINED( info.m_nIrisU ) ? params[info.m_nIrisU]->GetVecValue() : kDefaultIrisU, 1 );
		pShaderAPI->SetPixelShaderConstant( 3, IS_PARAM_DEFINED( info.m_nIrisV ) ? params[info.m_nIrisV]->GetVecValue() : kDefaultIrisV, 1 );

		float vEyePos[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
		pShaderAPI->GetWorldSpaceCameraPosition( vEyePos );
		pShaderAPI->SetPixelShaderConstant( 4, vEyePos, 1 );

		float vAmbientOcclusion[4] = { 0.33f, 0.33f, 0.33f, 0.0f };
		if ( IS_PARAM_DEFINED( info.m_nAmbientOcclColor ) )
		{
			params[info.m_nAmbientOcclColor]->GetVecValue( vAmbientOcclusion, 3 );
		}
		vAmbientOcclusion[3] = IS_PARAM_DEFINED( info.m_nAmbientOcclusion ) ? params[info.m_nAmbientOcclusion]->GetFloatValue() : 0.0f;

		float vPackedConst6[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
		//vPackedConst6[0] Unused
		vPackedConst6[1] = IS_PARAM_DEFINED( info.m_nEyeballRadius ) ? params[info.m_nEyeballRadius]->GetFloatValue() : kDefaultEyeballRadius;
		//vPackedConst6[2] = IS_PARAM_DEFINED( info.m_nRaytraceSphere ) ? params[info.m_nRaytraceSphere]->GetFloatValue() : kDefaultRaytraceSphere;
		vPackedConst6[3] = IS_PARAM_DEFINED( info.m_nParallaxStrength ) ? params[info.m_nParallaxStrength]->GetFloatValue() : kDefaultParallaxStrength;
		pShaderAPI->SetPixelShaderConstant( 6, vPackedConst6, 1 );

		if ( bDrawFlashlightAdditivePass == true )
		{
			SetFlashLightColorFromState( flashlightState, pShaderAPI, bSinglePassFlashlight );

			if ( pFlashlightDepthTexture && g_pConfig->ShadowDepthTexture() && flashlightState.m_bEnableShadows )
			{
				pShader->BindTexture( SHADER_SAMPLER6, pFlashlightDepthTexture, 0 );
				pShaderAPI->BindStandardTexture( SHADER_SAMPLER7, TEXTURE_SHADOW_NOISE_2D );
			}
		}

		if ( nFixedLightingMode == ENABLE_FIXED_LIGHTING_OUTPUTNORMAL_AND_DEPTH )
		{
			float vEyeDir[4];
			pShaderAPI->GetWorldSpaceCameraDirection( vEyeDir );

			float flFarZ = pShaderAPI->GetFarZ();
			vEyeDir[0] /= flFarZ;	// Divide by farZ for SSAO algorithm
			vEyeDir[1] /= flFarZ;
			vEyeDir[2] /= flFarZ;
			pShaderAPI->SetVertexShaderConstant( VERTEX_SHADER_SHADER_SPECIFIC_CONST_5, vEyeDir );
		}

		// Flashlight tax
#ifndef _X360
		if ( !g_pHardwareConfig->HasFastVertexTextures() )
#endif
		{
			if ( g_pHardwareConfig->SupportsPixelShaders_2_b() )
			{
				DECLARE_DYNAMIC_PIXEL_SHADER( eye_refract_ps20b );
				SET_DYNAMIC_PIXEL_SHADER_COMBO( NUM_LIGHTS, lightState.m_nNumLights );
				SET_DYNAMIC_PIXEL_SHADER_COMBO( FLASHLIGHTSHADOWS, bFlashlightShadows );
				SET_DYNAMIC_PIXEL_SHADER( eye_refract_ps20b );
			}
			else // ps.2.0
			{
				DECLARE_DYNAMIC_PIXEL_SHADER( eye_refract_ps20 );
				SET_DYNAMIC_PIXEL_SHADER_COMBO( NUM_LIGHTS, lightState.m_nNumLights );
				SET_DYNAMIC_PIXEL_SHADER( eye_refract_ps20 );
			}
		}
#ifndef _X360
		else
		{
			DECLARE_DYNAMIC_PIXEL_SHADER( eye_refract_ps30 );
			SET_DYNAMIC_PIXEL_SHADER_COMBO( NUM_LIGHTS, nFixedLightingMode ? 0 : lightState.m_nNumLights );
			SET_DYNAMIC_PIXEL_SHADER_COMBO( FLASHLIGHTSHADOWS, nFixedLightingMode ? false : bFlashlightShadows );
			SET_DYNAMIC_PIXEL_SHADER_COMBO( UBERLIGHT, flashlightState.m_bUberlight );
			SET_DYNAMIC_PIXEL_SHADER( eye_refract_ps30 );

			// Set constant to enable translation of VPOS to render target coordinates in ps_3_0
			pShaderAPI->SetScreenSizeForVPOS();

			SetupUberlightFromState( pShaderAPI, flashlightState );
		}
#endif

		pShaderAPI->SetPixelShaderFogParams( PSREG_FOG_PARAMS );

		if ( bDrawFlashlightAdditivePass == true )
		{
			float atten[4], pos[4], tweaks[4];
			atten[0] = flashlightState.m_fConstantAtten;		// Set the flashlight attenuation factors
			atten[1] = flashlightState.m_fLinearAtten;
			atten[2] = flashlightState.m_fQuadraticAtten;
			atten[3] = flashlightState.m_FarZAtten;
			pShaderAPI->SetPixelShaderConstant( 7, atten, 1 );

			pos[0] = flashlightState.m_vecLightOrigin[0];		// Set the flashlight origin
			pos[1] = flashlightState.m_vecLightOrigin[1];
			pos[2] = flashlightState.m_vecLightOrigin[2];
			pShaderAPI->SetPixelShaderConstant( 8, pos, 1 );

			pShaderAPI->SetVertexShaderConstant( VERTEX_SHADER_SHADER_SPECIFIC_CONST_6, worldToTexture.Base(), 4 );

			// Tweaks associated with a given flashlight
			tweaks[0] = ShadowFilterFromState( flashlightState );
			tweaks[1] = ShadowAttenFromState( flashlightState );
			pShader->HashShadow2DJitter( flashlightState.m_flShadowJitterSeed, &tweaks[2], &tweaks[3] );
			pShaderAPI->SetPixelShaderConstant( 9, tweaks, 1 );

			// Dimensions of screen, used for screen-space noise map sampling
			float vScreenScale[4] = {1280.0f / 32.0f, 720.0f / 32.0f, 0, 0};
			int nWidth, nHeight;
			pShaderAPI->GetBackBufferDimensions( nWidth, nHeight );

			int nTexWidth, nTexHeight;
			pShaderAPI->GetStandardTextureDimensions( &nTexWidth, &nTexHeight, TEXTURE_SHADOW_NOISE_2D );

			vScreenScale[0] = (float) nWidth  / nTexWidth;
			vScreenScale[1] = (float) nHeight / nTexHeight;
			pShaderAPI->SetPixelShaderConstant( PSREG_FLASHLIGHT_SCREEN_SCALE, vScreenScale, 1 );

			vAmbientOcclusion[3] *= flashlightState.m_flAmbientOcclusion;
		}

		vAmbientOcclusion[3] = MIN( MAX( vAmbientOcclusion[3], 0.0f ), 1.0f );
		pShaderAPI->SetPixelShaderConstant( 5, vAmbientOcclusion, 1 );

		// Intro tax
		if ( bIntro )
		{
			float curTime = params[info.m_nWarpParam]->GetFloatValue();
			float timeVec[4] = { 0.0f, 0.0f, 0.0f, curTime };
			if ( IS_PARAM_DEFINED( info.m_nEntityOrigin ) )
			{
				params[info.m_nEntityOrigin]->GetVecValue( timeVec, 3 );
			}
			pShaderAPI->SetVertexShaderConstant( VERTEX_SHADER_SHADER_SPECIFIC_CONST_5, timeVec, 1 );
		}
	}
	pShader->Draw();
}
	void DrawPass( IMaterialVar** params, IShaderDynamicAPI *pShaderAPI,
		IShaderShadow* pShaderShadow, bool hasFlashlight, VertexCompressionType_t vertexCompression )
	{
		bool bSinglePassFlashlight = false;
		bool hasBump = params[BUMPMAP]->IsTexture();
		bool hasDiffuseBumpmap = hasBump && (params[NODIFFUSEBUMPLIGHTING]->GetIntValue() == 0);
		bool hasBaseTexture = params[BASETEXTURE]->IsTexture();
		bool hasDetailTexture = /*!hasBump && */params[DETAIL]->IsTexture();
		bool hasVertexColor = IS_FLAG_SET( MATERIAL_VAR_VERTEXCOLOR ) != 0;
		bool bHasDetailAlpha = params[DETAIL_ALPHA_MASK_BASE_TEXTURE]->GetIntValue() != 0;
		bool bIsAlphaTested = IS_FLAG_SET( MATERIAL_VAR_ALPHATEST ) != 0;

		BlendType_t nBlendType = EvaluateBlendRequirements( BASETEXTURE, true );
		bool bFullyOpaque = (nBlendType != BT_BLENDADD) && (nBlendType != BT_BLEND) && !IS_FLAG_SET(MATERIAL_VAR_ALPHATEST); //dest alpha is free for special use

		bool bSeamlessMapping = params[SEAMLESS_SCALE]->GetFloatValue() != 0.0;

		bool bShaderSrgbRead = ( IsX360() && IS_PARAM_DEFINED( SHADERSRGBREAD360 ) && params[SHADERSRGBREAD360]->GetIntValue() );

		SHADOW_STATE
		{
			int nShadowFilterMode = 0;

			// Alpha test: FIXME: shouldn't this be handled in Shader_t::SetInitialShadowState
			pShaderShadow->EnableAlphaTest( bIsAlphaTested );
			if( hasFlashlight )
			{
				if ( g_pHardwareConfig->SupportsPixelShaders_2_b() )
				{
					nShadowFilterMode = g_pHardwareConfig->GetShadowFilterMode();	// Based upon vendor and device dependent formats
				}

				SetAdditiveBlendingShadowState( BASETEXTURE, true );
				pShaderShadow->EnableDepthWrites( false );

				// Be sure not to write to dest alpha
				pShaderShadow->EnableAlphaWrites( false );
			}
			else
			{
				SetDefaultBlendingShadowState( BASETEXTURE, true );
			}

			unsigned int flags = VERTEX_POSITION;
			if( hasBaseTexture )
			{
				pShaderShadow->EnableTexture( SHADER_SAMPLER0, true );
				pShaderShadow->EnableSRGBRead( SHADER_SAMPLER0, !bShaderSrgbRead );
			}
			//			if( hasLightmap )
			{
				pShaderShadow->EnableTexture( SHADER_SAMPLER1, true );
				pShaderShadow->EnableSRGBRead( SHADER_SAMPLER1, true );
			}
			if( hasFlashlight )
			{
				pShaderShadow->EnableTexture( SHADER_SAMPLER2, true );
				pShaderShadow->EnableTexture( SHADER_SAMPLER7, true );
				pShaderShadow->SetShadowDepthFiltering( SHADER_SAMPLER7 );
				flags |= VERTEX_TANGENT_S | VERTEX_TANGENT_T | VERTEX_NORMAL;
			}
			if( hasDetailTexture )
			{
				pShaderShadow->EnableTexture( SHADER_SAMPLER3, true );
			}
			if( hasBump )
			{
				pShaderShadow->EnableTexture( SHADER_SAMPLER4, true );
			}
			if( hasVertexColor )
			{
				flags |= VERTEX_COLOR;
			}

			// Normalizing cube map
			pShaderShadow->EnableTexture( SHADER_SAMPLER6, true );

			// texcoord0 : base texcoord
			// texcoord1 : lightmap texcoord
			// texcoord2 : lightmap texcoord offset
			int numTexCoords = 2;
			if( hasBump )
			{
				numTexCoords = 3;
			}

			pShaderShadow->VertexShaderVertexFormat( flags, numTexCoords, 0, 0 );

			// Pre-cache pixel shaders
			bool hasSelfIllum = IS_FLAG_SET( MATERIAL_VAR_SELFILLUM );

			pShaderShadow->EnableSRGBWrite( true );

			int nLightingPreviewMode = IS_FLAG2_SET( MATERIAL_VAR2_USE_GBUFFER0 ) + 2 * IS_FLAG2_SET( MATERIAL_VAR2_USE_GBUFFER1 );

#ifndef _X360
			if ( g_pHardwareConfig->HasFastVertexTextures() )
			{
				DECLARE_STATIC_VERTEX_SHADER( lightmappedgeneric_vs30 );
				SET_STATIC_VERTEX_SHADER_COMBO( ENVMAP_MASK,  false );
				SET_STATIC_VERTEX_SHADER_COMBO( BUMPMASK,  false );
				SET_STATIC_VERTEX_SHADER_COMBO( TANGENTSPACE,  hasFlashlight );
				SET_STATIC_VERTEX_SHADER_COMBO( BUMPMAP,  hasBump );
				SET_STATIC_VERTEX_SHADER_COMBO( DIFFUSEBUMPMAP,  hasDiffuseBumpmap );
				SET_STATIC_VERTEX_SHADER_COMBO( VERTEXCOLOR,  hasVertexColor );
				SET_STATIC_VERTEX_SHADER_COMBO( VERTEXALPHATEXBLENDFACTOR, false );
				SET_STATIC_VERTEX_SHADER_COMBO( PARALLAX_MAPPING, 0 ); //( bumpmap_variant == 2 )?1:0);
				SET_STATIC_VERTEX_SHADER_COMBO( SEAMLESS, bSeamlessMapping ); //( bumpmap_variant == 2 )?1:0);
				SET_STATIC_VERTEX_SHADER_COMBO( DETAILTEXTURE,  hasDetailTexture );
				SET_STATIC_VERTEX_SHADER_COMBO( SELFILLUM,  hasSelfIllum );
				SET_STATIC_VERTEX_SHADER_COMBO( FANCY_BLENDING,  false );
				SET_STATIC_VERTEX_SHADER_COMBO( LIGHTING_PREVIEW, nLightingPreviewMode != 0 );
				SET_STATIC_VERTEX_SHADER( lightmappedgeneric_vs30 );
			}
			else
#endif
			{
				DECLARE_STATIC_VERTEX_SHADER( lightmappedgeneric_vs20 );
				SET_STATIC_VERTEX_SHADER_COMBO( ENVMAP_MASK,  false );
				SET_STATIC_VERTEX_SHADER_COMBO( BUMPMASK,  false );
				SET_STATIC_VERTEX_SHADER_COMBO( TANGENTSPACE,  hasFlashlight );
				SET_STATIC_VERTEX_SHADER_COMBO( BUMPMAP,  hasBump );
				SET_STATIC_VERTEX_SHADER_COMBO( DIFFUSEBUMPMAP,  hasDiffuseBumpmap );
				SET_STATIC_VERTEX_SHADER_COMBO( VERTEXCOLOR,  hasVertexColor );
				SET_STATIC_VERTEX_SHADER_COMBO( VERTEXALPHATEXBLENDFACTOR, false );
				SET_STATIC_VERTEX_SHADER_COMBO( PARALLAX_MAPPING, 0 ); //( bumpmap_variant == 2 )?1:0);
				SET_STATIC_VERTEX_SHADER_COMBO( SEAMLESS, bSeamlessMapping ); //( bumpmap_variant == 2 )?1:0);
				SET_STATIC_VERTEX_SHADER_COMBO( DETAILTEXTURE,  hasDetailTexture );
				SET_STATIC_VERTEX_SHADER_COMBO( SELFILLUM,  hasSelfIllum );
				SET_STATIC_VERTEX_SHADER_COMBO( FANCY_BLENDING,  false );
				SET_STATIC_VERTEX_SHADER_COMBO( LIGHTING_PREVIEW, nLightingPreviewMode != 0 );
	#ifdef _X360
				SET_STATIC_VERTEX_SHADER_COMBO( FLASHLIGHT, hasFlashlight );
	#endif
				SET_STATIC_VERTEX_SHADER( lightmappedgeneric_vs20 );
			}

#ifndef _X360
			if ( g_pHardwareConfig->HasFastVertexTextures() )
			{
				DECLARE_STATIC_PIXEL_SHADER( worldtwotextureblend_ps30 );
				SET_STATIC_PIXEL_SHADER_COMBO( DETAILTEXTURE,  hasDetailTexture );
				SET_STATIC_PIXEL_SHADER_COMBO( BUMPMAP,  hasBump );
				SET_STATIC_PIXEL_SHADER_COMBO( DIFFUSEBUMPMAP,  hasDiffuseBumpmap );
				SET_STATIC_PIXEL_SHADER_COMBO( VERTEXCOLOR,  hasVertexColor );
				SET_STATIC_PIXEL_SHADER_COMBO( SELFILLUM,  hasSelfIllum );
				SET_STATIC_PIXEL_SHADER_COMBO( DETAIL_ALPHA_MASK_BASE_TEXTURE,  bHasDetailAlpha );
				SET_STATIC_PIXEL_SHADER_COMBO( FLASHLIGHT,  hasFlashlight );
				SET_STATIC_PIXEL_SHADER_COMBO( SEAMLESS,  bSeamlessMapping );
				SET_STATIC_PIXEL_SHADER_COMBO( FLASHLIGHTDEPTHFILTERMODE, nShadowFilterMode );
				SET_STATIC_PIXEL_SHADER_COMBO( SHADER_SRGB_READ, bShaderSrgbRead );
				SET_STATIC_PIXEL_SHADER( worldtwotextureblend_ps30 );
			}
			else
#endif
			if ( g_pHardwareConfig->SupportsPixelShaders_2_b() )
			{
				DECLARE_STATIC_PIXEL_SHADER( worldtwotextureblend_ps20b );
				SET_STATIC_PIXEL_SHADER_COMBO( DETAILTEXTURE,  hasDetailTexture );
				SET_STATIC_PIXEL_SHADER_COMBO( BUMPMAP,  hasBump );
				SET_STATIC_PIXEL_SHADER_COMBO( DIFFUSEBUMPMAP,  hasDiffuseBumpmap );
				SET_STATIC_PIXEL_SHADER_COMBO( VERTEXCOLOR,  hasVertexColor );
				SET_STATIC_PIXEL_SHADER_COMBO( SELFILLUM,  hasSelfIllum );
				SET_STATIC_PIXEL_SHADER_COMBO( DETAIL_ALPHA_MASK_BASE_TEXTURE,  bHasDetailAlpha );
				SET_STATIC_PIXEL_SHADER_COMBO( FLASHLIGHT,  hasFlashlight );
				SET_STATIC_PIXEL_SHADER_COMBO( SEAMLESS,  bSeamlessMapping );
				SET_STATIC_PIXEL_SHADER_COMBO( FLASHLIGHTDEPTHFILTERMODE, nShadowFilterMode );
				SET_STATIC_PIXEL_SHADER_COMBO( SHADER_SRGB_READ, bShaderSrgbRead );
				SET_STATIC_PIXEL_SHADER( worldtwotextureblend_ps20b );
			}
			else
			{
				DECLARE_STATIC_PIXEL_SHADER( worldtwotextureblend_ps20 );
				SET_STATIC_PIXEL_SHADER_COMBO( DETAILTEXTURE,  hasDetailTexture );
				SET_STATIC_PIXEL_SHADER_COMBO( BUMPMAP,  hasBump );
				SET_STATIC_PIXEL_SHADER_COMBO( DIFFUSEBUMPMAP,  hasDiffuseBumpmap );
				SET_STATIC_PIXEL_SHADER_COMBO( VERTEXCOLOR,  hasVertexColor );
				SET_STATIC_PIXEL_SHADER_COMBO( SELFILLUM,  hasSelfIllum );
				SET_STATIC_PIXEL_SHADER_COMBO( DETAIL_ALPHA_MASK_BASE_TEXTURE,  bHasDetailAlpha );
				SET_STATIC_PIXEL_SHADER_COMBO( FLASHLIGHT,  hasFlashlight );
				SET_STATIC_PIXEL_SHADER_COMBO( SEAMLESS,  bSeamlessMapping );
				SET_STATIC_PIXEL_SHADER_COMBO( SHADER_SRGB_READ, bShaderSrgbRead );
				SET_STATIC_PIXEL_SHADER( worldtwotextureblend_ps20 );
			}

			// HACK HACK HACK - enable alpha writes all the time so that we have them for
			// underwater stuff. 
			// But only do it if we're not using the alpha already for translucency
			pShaderShadow->EnableAlphaWrites( bFullyOpaque );

			if( hasFlashlight )
			{
				FogToBlack();
			}
			else
			{
				DefaultFog();
			}

			PI_BeginCommandBuffer();
			PI_SetModulationVertexShaderDynamicState( );
			PI_EndCommandBuffer();
		}
		DYNAMIC_STATE
		{
			if( hasBaseTexture )
			{
				BindTexture( SHADER_SAMPLER0, BASETEXTURE, FRAME );
			}
			else
			{
				pShaderAPI->BindStandardTexture( SHADER_SAMPLER0, TEXTURE_WHITE );
			}

			//			if( hasLightmap )
			{
				pShaderAPI->BindStandardTexture( SHADER_SAMPLER1, TEXTURE_LIGHTMAP );
			}

			bool bFlashlightShadows = false;
			bool bUberlight = false;
			if( hasFlashlight )
			{
				VMatrix worldToTexture;
				ITexture *pFlashlightDepthTexture;
				FlashlightState_t state = pShaderAPI->GetFlashlightStateEx( worldToTexture, &pFlashlightDepthTexture );
				bFlashlightShadows = state.m_bEnableShadows;
				bUberlight = state.m_bUberlight;

				SetFlashLightColorFromState( state, pShaderAPI, bSinglePassFlashlight );

				BindTexture( SHADER_SAMPLER2, state.m_pSpotlightTexture, state.m_nSpotlightTextureFrame );

				if( pFlashlightDepthTexture && g_pConfig->ShadowDepthTexture() )
				{
					BindTexture( SHADER_SAMPLER7, pFlashlightDepthTexture );
				}
			}
			if( hasDetailTexture )
			{
				BindTexture( SHADER_SAMPLER3, DETAIL, DETAILFRAME );
			}
			if( hasBump )
			{
				if( !g_pConfig->m_bFastNoBump )
				{
					BindTexture( SHADER_SAMPLER4, BUMPMAP, BUMPFRAME );
				}
				else
				{
					pShaderAPI->BindStandardTexture( SHADER_SAMPLER4, TEXTURE_NORMALMAP_FLAT );
				}
			}
			pShaderAPI->BindStandardTexture( SHADER_SAMPLER6, TEXTURE_NORMALIZATION_CUBEMAP_SIGNED );

			// If we don't have a texture transform, we don't have
			// to set vertex shader constants or run vertex shader instructions
			// for the texture transform.
			bool bHasTextureTransform = 
				!( params[BASETEXTURETRANSFORM]->MatrixIsIdentity() &&
				params[BUMPTRANSFORM]->MatrixIsIdentity() );

			bool bVertexShaderFastPath = !bHasTextureTransform;
			if( params[DETAIL]->IsTexture() )
			{
				bVertexShaderFastPath = false;
			}
			if( pShaderAPI->GetIntRenderingParameter(INT_RENDERPARM_ENABLE_FIXED_LIGHTING) != 0 )
			{
				bVertexShaderFastPath = false;
			}

			if( !bVertexShaderFastPath )
			{
				if ( !bSeamlessMapping )
				{
					SetVertexShaderTextureTransform( VERTEX_SHADER_SHADER_SPECIFIC_CONST_0, BASETEXTURETRANSFORM );
				}
				if( hasBump && !bHasDetailAlpha )
				{
					SetVertexShaderTextureTransform( VERTEX_SHADER_SHADER_SPECIFIC_CONST_2, BUMPTRANSFORM );
					Assert( !hasDetailTexture );
				}
			}

			MaterialFogMode_t fogType = pShaderAPI->GetSceneFogMode();

			if ( IsPC() )
			{
				bool bWorldNormal = pShaderAPI->GetIntRenderingParameter( INT_RENDERPARM_ENABLE_FIXED_LIGHTING ) == ENABLE_FIXED_LIGHTING_OUTPUTNORMAL_AND_DEPTH;
				if ( bWorldNormal )
				{
					float vEyeDir[4];
					pShaderAPI->GetWorldSpaceCameraDirection( vEyeDir );

					float flFarZ = pShaderAPI->GetFarZ();
					vEyeDir[0] /= flFarZ;	// Divide by farZ for SSAO algorithm
					vEyeDir[1] /= flFarZ;
					vEyeDir[2] /= flFarZ;
					pShaderAPI->SetVertexShaderConstant( VERTEX_SHADER_SHADER_SPECIFIC_CONST_12, vEyeDir );
				}
			}

#ifndef _X360
			if (g_pHardwareConfig->HasFastVertexTextures() )
			{
				DECLARE_DYNAMIC_VERTEX_SHADER( lightmappedgeneric_vs30 );
				SET_DYNAMIC_VERTEX_SHADER_COMBO( FASTPATH,  bVertexShaderFastPath );
				SET_DYNAMIC_VERTEX_SHADER( lightmappedgeneric_vs30 );
			}
			else
#endif
			{
				DECLARE_DYNAMIC_VERTEX_SHADER( lightmappedgeneric_vs20 );
				SET_DYNAMIC_VERTEX_SHADER_COMBO( FASTPATH,  bVertexShaderFastPath );
				SET_DYNAMIC_VERTEX_SHADER( lightmappedgeneric_vs20 );
			}

			bool bWriteDepthToAlpha;
			bool bWriteWaterFogToAlpha;
			if( bFullyOpaque ) 
			{
				bWriteDepthToAlpha = pShaderAPI->ShouldWriteDepthToDestAlpha();
				bWriteWaterFogToAlpha = (fogType == MATERIAL_FOG_LINEAR_BELOW_FOG_Z);
				AssertMsg( !(bWriteDepthToAlpha && bWriteWaterFogToAlpha), "Can't write two values to alpha at the same time." );
			}
			else
			{
				//can't write a special value to dest alpha if we're actually using as-intended alpha
				bWriteDepthToAlpha = false;
				bWriteWaterFogToAlpha = false;
			}

#ifndef _X360
			if ( g_pHardwareConfig->HasFastVertexTextures() )
			{
				DECLARE_DYNAMIC_PIXEL_SHADER( worldtwotextureblend_ps30 );

				// Don't write fog to alpha if we're using translucency
				SET_DYNAMIC_PIXEL_SHADER_COMBO( WRITEWATERFOGTODESTALPHA, bWriteWaterFogToAlpha );
				SET_DYNAMIC_PIXEL_SHADER_COMBO( WRITE_DEPTH_TO_DESTALPHA, bWriteDepthToAlpha );
				SET_DYNAMIC_PIXEL_SHADER_COMBO( FLASHLIGHTSHADOWS, bFlashlightShadows );
				SET_DYNAMIC_PIXEL_SHADER_COMBO( UBERLIGHT, bUberlight );
				SET_DYNAMIC_PIXEL_SHADER( worldtwotextureblend_ps30 );
			}
			else
#endif
			if ( g_pHardwareConfig->SupportsPixelShaders_2_b() )
			{
				DECLARE_DYNAMIC_PIXEL_SHADER( worldtwotextureblend_ps20b );

				// Don't write fog to alpha if we're using translucency
				SET_DYNAMIC_PIXEL_SHADER_COMBO( WRITEWATERFOGTODESTALPHA, bWriteWaterFogToAlpha );
				SET_DYNAMIC_PIXEL_SHADER_COMBO( WRITE_DEPTH_TO_DESTALPHA, bWriteDepthToAlpha );
				SET_DYNAMIC_PIXEL_SHADER_COMBO( FLASHLIGHTSHADOWS, bFlashlightShadows );
				SET_DYNAMIC_PIXEL_SHADER( worldtwotextureblend_ps20b );
			}
			else
			{
				DECLARE_DYNAMIC_PIXEL_SHADER( worldtwotextureblend_ps20 );

				// Don't write fog to alpha if we're using translucency
				SET_DYNAMIC_PIXEL_SHADER_COMBO( WRITEWATERFOGTODESTALPHA, (fogType == MATERIAL_FOG_LINEAR_BELOW_FOG_Z) && 
												(nBlendType != BT_BLENDADD) && (nBlendType != BT_BLEND) && !bIsAlphaTested );
				SET_DYNAMIC_PIXEL_SHADER( worldtwotextureblend_ps20 );
			}


			// always set the transform for detail textures since I'm assuming that you'll
			// always have a detailscale.
			if( hasDetailTexture )
			{
				SetVertexShaderTextureScaledTransform( VERTEX_SHADER_SHADER_SPECIFIC_CONST_2, BASETEXTURETRANSFORM, DETAILSCALE );
				Assert( !( hasBump && !bHasDetailAlpha ) );
			}

			SetPixelShaderConstantGammaToLinear( 7, SELFILLUMTINT );

			float eyePos[4];
			pShaderAPI->GetWorldSpaceCameraPosition( eyePos );
			pShaderAPI->SetPixelShaderConstant( 10, eyePos, 1 );
			pShaderAPI->SetPixelShaderFogParams( 11 );

			if ( bSeamlessMapping )
			{
				float map_scale[4]={ params[SEAMLESS_SCALE]->GetFloatValue(),0,0,0};
				pShaderAPI->SetVertexShaderConstant( VERTEX_SHADER_SHADER_SPECIFIC_CONST_0, map_scale );
			}


			if( hasFlashlight )
			{
				VMatrix worldToTexture;
				const FlashlightState_t &flashlightState = pShaderAPI->GetFlashlightState( worldToTexture );

				// Set the flashlight attenuation factors
				float atten[4];
				atten[0] = flashlightState.m_fConstantAtten;
				atten[1] = flashlightState.m_fLinearAtten;
				atten[2] = flashlightState.m_fQuadraticAtten;
				atten[3] = flashlightState.m_FarZAtten;
				pShaderAPI->SetPixelShaderConstant( 20, atten, 1 );

				// Set the flashlight origin
				float pos[4];
				pos[0] = flashlightState.m_vecLightOrigin[0];
				pos[1] = flashlightState.m_vecLightOrigin[1];
				pos[2] = flashlightState.m_vecLightOrigin[2];
				pos[3] = flashlightState.m_FarZ; // didn't have this in main. . probably need this?
				pShaderAPI->SetPixelShaderConstant( 15, pos, 1 );

				pShaderAPI->SetPixelShaderConstant( 16, worldToTexture.Base(), 4 );

				if ( IsPC() && g_pHardwareConfig->HasFastVertexTextures() )
				{
					SetupUberlightFromState( pShaderAPI, flashlightState );
				}
			}
		}
		Draw();
	}
Example #3
0
void CBaseVSShader::DrawFlashlight_dx90( IMaterialVar** params, IShaderDynamicAPI *pShaderAPI, 
										IShaderShadow* pShaderShadow, DrawFlashlight_dx90_Vars_t &vars )
{
	// FLASHLIGHTFIXME: hack . . need to fix the vertex shader so that it can deal with and without bumps for vertexlitgeneric
	if( !vars.m_bLightmappedGeneric )
	{
		vars.m_bBump = false;
	}
	bool bBump2 = vars.m_bWorldVertexTransition && vars.m_bBump && vars.m_nBumpmap2Var != -1 && params[vars.m_nBumpmap2Var]->IsTexture();
	bool bSeamless = vars.m_fSeamlessScale != 0.0;
	bool bDetail = vars.m_bLightmappedGeneric && (vars.m_nDetailVar != -1) && params[vars.m_nDetailVar]->IsDefined() && (vars.m_nDetailScale != -1);

	int nDetailBlendMode = 0;
	if ( bDetail )
	{
		nDetailBlendMode = GetIntParam( vars.m_nDetailTextureCombineMode, params );
		ITexture *pDetailTexture = params[vars.m_nDetailVar]->GetTextureValue();
		if ( pDetailTexture->GetFlags() & TEXTUREFLAGS_SSBUMP )
		{
			if ( vars.m_bBump )
				nDetailBlendMode = 10;					// ssbump
			else
				nDetailBlendMode = 11;					// ssbump_nobump
		}
	}
	
	if( pShaderShadow )
	{
		SetInitialShadowState();
		pShaderShadow->EnableDepthWrites( false );
		pShaderShadow->EnableAlphaWrites( false );

		// Alpha blend
		SetAdditiveBlendingShadowState( BASETEXTURE, true );

		// Alpha test
		pShaderShadow->EnableAlphaTest( IS_FLAG_SET( MATERIAL_VAR_ALPHATEST ) );
		if ( vars.m_nAlphaTestReference != -1 && params[vars.m_nAlphaTestReference]->GetFloatValue() > 0.0f )
		{
			pShaderShadow->AlphaFunc( SHADER_ALPHAFUNC_GEQUAL, params[vars.m_nAlphaTestReference]->GetFloatValue() );
		}

		// Spot sampler
		pShaderShadow->EnableTexture( SHADER_SAMPLER0, true );

		// Base sampler
		pShaderShadow->EnableTexture( SHADER_SAMPLER1, true );
		pShaderShadow->EnableSRGBRead( SHADER_SAMPLER1, true );

		// Normalizing cubemap sampler
		pShaderShadow->EnableTexture( SHADER_SAMPLER2, true );

		// Normalizing cubemap sampler2 or normal map sampler
		pShaderShadow->EnableTexture( SHADER_SAMPLER3, true );

		// RandomRotation sampler
		pShaderShadow->EnableTexture( SHADER_SAMPLER5, true );

		// Flashlight depth sampler
		pShaderShadow->EnableTexture( SHADER_SAMPLER7, true );
		pShaderShadow->SetShadowDepthFiltering( SHADER_SAMPLER7 );

		if( vars.m_bWorldVertexTransition )
		{
			// $basetexture2
			pShaderShadow->EnableTexture( SHADER_SAMPLER4, true );
			pShaderShadow->EnableSRGBRead( SHADER_SAMPLER4, true );
		}
		if( bBump2 )
		{
			// Normalmap2 sampler
			pShaderShadow->EnableTexture( SHADER_SAMPLER6, true );
		}
		if( bDetail )
		{
			pShaderShadow->EnableTexture( SHADER_SAMPLER8, true );				// detail sampler
			if ( nDetailBlendMode == 1 )
				pShaderShadow->EnableSRGBRead( SHADER_SAMPLER8, true );
		}

		pShaderShadow->EnableSRGBWrite( true );

		if( vars.m_bLightmappedGeneric )
		{
#ifndef _X360
			if ( g_pHardwareConfig->HasFastVertexTextures() )
			{
				DECLARE_STATIC_VERTEX_SHADER( lightmappedgeneric_flashlight_vs30 );
				SET_STATIC_VERTEX_SHADER_COMBO( WORLDVERTEXTRANSITION, vars.m_bWorldVertexTransition );
				SET_STATIC_VERTEX_SHADER_COMBO( NORMALMAP, vars.m_bBump );
				SET_STATIC_VERTEX_SHADER_COMBO( SEAMLESS, bSeamless );
				SET_STATIC_VERTEX_SHADER_COMBO( DETAIL, bDetail );
				SET_STATIC_VERTEX_SHADER( lightmappedgeneric_flashlight_vs30 );
			}
			else
#endif
			{
				DECLARE_STATIC_VERTEX_SHADER( lightmappedgeneric_flashlight_vs20 );
				SET_STATIC_VERTEX_SHADER_COMBO( WORLDVERTEXTRANSITION, vars.m_bWorldVertexTransition );
				SET_STATIC_VERTEX_SHADER_COMBO( NORMALMAP, vars.m_bBump );
				SET_STATIC_VERTEX_SHADER_COMBO( SEAMLESS, bSeamless );
				SET_STATIC_VERTEX_SHADER_COMBO( DETAIL, bDetail );
				SET_STATIC_VERTEX_SHADER( lightmappedgeneric_flashlight_vs20 );
			}

			unsigned int flags = VERTEX_POSITION | VERTEX_NORMAL;
			if( vars.m_bBump )
			{
				flags |= VERTEX_TANGENT_S | VERTEX_TANGENT_T;
			}
			int numTexCoords = 1;
			if( vars.m_bWorldVertexTransition )
			{
				flags |= VERTEX_COLOR;
				numTexCoords = 2; // need lightmap texcoords to get alpha.
			}
			pShaderShadow->VertexShaderVertexFormat( flags, numTexCoords, 0, 0 );
		}
		else
		{

			// Need a 3.0 vs here?

			DECLARE_STATIC_VERTEX_SHADER( vertexlitgeneric_flashlight_vs20 );
			SET_STATIC_VERTEX_SHADER_COMBO( TEETH, vars.m_bTeeth );
			SET_STATIC_VERTEX_SHADER( vertexlitgeneric_flashlight_vs20 );

			unsigned int flags = VERTEX_POSITION | VERTEX_NORMAL;
			int numTexCoords = 1;
			pShaderShadow->VertexShaderVertexFormat( flags, numTexCoords, 0, vars.m_bBump ? 4 : 0 );
		}

		int nBumpMapVariant = 0;
		if ( vars.m_bBump )
		{
			nBumpMapVariant = ( vars.m_bSSBump ) ? 2 : 1;
		}

#ifndef _X360
		if ( g_pHardwareConfig->HasFastVertexTextures() )
		{
			int nShadowFilterMode = g_pHardwareConfig->GetShadowFilterMode();

			DECLARE_STATIC_PIXEL_SHADER( flashlight_ps30 );
			SET_STATIC_PIXEL_SHADER_COMBO( NORMALMAP, nBumpMapVariant );
			SET_STATIC_PIXEL_SHADER_COMBO( NORMALMAP2, bBump2 );
			SET_STATIC_PIXEL_SHADER_COMBO( WORLDVERTEXTRANSITION, vars.m_bWorldVertexTransition );
			SET_STATIC_PIXEL_SHADER_COMBO( SEAMLESS, bSeamless );
			SET_STATIC_PIXEL_SHADER_COMBO( DETAILTEXTURE, bDetail );
			SET_STATIC_PIXEL_SHADER_COMBO( DETAIL_BLEND_MODE, nDetailBlendMode );
			SET_STATIC_PIXEL_SHADER_COMBO( FLASHLIGHTDEPTHFILTERMODE, nShadowFilterMode );
			SET_STATIC_PIXEL_SHADER( flashlight_ps30 );
		}
		else
#endif
		if ( g_pHardwareConfig->SupportsPixelShaders_2_b() )
		{
			int nShadowFilterMode = g_pHardwareConfig->GetShadowFilterMode();

			DECLARE_STATIC_PIXEL_SHADER( flashlight_ps20b );
			SET_STATIC_PIXEL_SHADER_COMBO( NORMALMAP, nBumpMapVariant );
			SET_STATIC_PIXEL_SHADER_COMBO( NORMALMAP2, bBump2 );
			SET_STATIC_PIXEL_SHADER_COMBO( WORLDVERTEXTRANSITION, vars.m_bWorldVertexTransition );
			SET_STATIC_PIXEL_SHADER_COMBO( SEAMLESS, bSeamless );
			SET_STATIC_PIXEL_SHADER_COMBO( DETAILTEXTURE, bDetail );
			SET_STATIC_PIXEL_SHADER_COMBO( DETAIL_BLEND_MODE, nDetailBlendMode );
			SET_STATIC_PIXEL_SHADER_COMBO( FLASHLIGHTDEPTHFILTERMODE, nShadowFilterMode );
			SET_STATIC_PIXEL_SHADER( flashlight_ps20b );
		}
		else
		{
			DECLARE_STATIC_PIXEL_SHADER( flashlight_ps20 );
			SET_STATIC_PIXEL_SHADER_COMBO( NORMALMAP, nBumpMapVariant );
			SET_STATIC_PIXEL_SHADER_COMBO( NORMALMAP2, bBump2 );
			SET_STATIC_PIXEL_SHADER_COMBO( WORLDVERTEXTRANSITION, vars.m_bWorldVertexTransition );
			SET_STATIC_PIXEL_SHADER_COMBO( SEAMLESS, bSeamless );
			SET_STATIC_PIXEL_SHADER_COMBO( DETAILTEXTURE, bDetail );
			SET_STATIC_PIXEL_SHADER_COMBO( DETAIL_BLEND_MODE, nDetailBlendMode );
			SET_STATIC_PIXEL_SHADER( flashlight_ps20 );
		}
		FogToBlack();

		PI_BeginCommandBuffer();
		PI_SetModulationPixelShaderDynamicState( PSREG_DIFFUSE_MODULATION );
		PI_EndCommandBuffer();
	}
	else
	{
		VMatrix worldToTexture;
		ITexture *pFlashlightDepthTexture;
		FlashlightState_t flashlightState = pShaderAPI->GetFlashlightStateEx( worldToTexture, &pFlashlightDepthTexture );

		SetFlashLightColorFromState( flashlightState, pShaderAPI, false );

		BindTexture( SHADER_SAMPLER0, flashlightState.m_pSpotlightTexture, flashlightState.m_nSpotlightTextureFrame );

		pShaderAPI->BindStandardTexture( SHADER_SAMPLER5, TEXTURE_SHADOW_NOISE_2D );
		if( pFlashlightDepthTexture && g_pConfig->ShadowDepthTexture() && flashlightState.m_bEnableShadows )
		{
			BindTexture( SHADER_SAMPLER7, pFlashlightDepthTexture, 0 );

			// Tweaks associated with a given flashlight
			float tweaks[4];
			tweaks[0] = ShadowFilterFromState( flashlightState );
			tweaks[1] = ShadowAttenFromState( flashlightState );
			HashShadow2DJitter( flashlightState.m_flShadowJitterSeed, &tweaks[2], &tweaks[3] );
			pShaderAPI->SetPixelShaderConstant( PSREG_ENVMAP_TINT__SHADOW_TWEAKS, tweaks, 1 );

			// Dimensions of screen, used for screen-space noise map sampling
			float vScreenScale[4] = {1280.0f / 32.0f, 720.0f / 32.0f, 0, 0};
			int nWidth, nHeight;
			pShaderAPI->GetBackBufferDimensions( nWidth, nHeight );

			int nTexWidth, nTexHeight;
			pShaderAPI->GetStandardTextureDimensions( &nTexWidth, &nTexHeight, TEXTURE_SHADOW_NOISE_2D );

			vScreenScale[0] = (float) nWidth  / nTexWidth;
			vScreenScale[1] = (float) nHeight / nTexHeight;

			pShaderAPI->SetPixelShaderConstant( PSREG_FLASHLIGHT_SCREEN_SCALE, vScreenScale, 1 );
		}
		else
		{
			pShaderAPI->BindStandardTexture( SHADER_SAMPLER7, TEXTURE_WHITE );
		}

		if( params[BASETEXTURE]->IsTexture() && mat_fullbright.GetInt() != 2 )
		{
			BindTexture( SHADER_SAMPLER1, BASETEXTURE, FRAME );
		}
		else
		{
			pShaderAPI->BindStandardTexture( SHADER_SAMPLER1, TEXTURE_GREY );
		}
		if( vars.m_bWorldVertexTransition )
		{
			Assert( vars.m_nBaseTexture2Var >= 0 && vars.m_nBaseTexture2FrameVar >= 0 );
			BindTexture( SHADER_SAMPLER4, vars.m_nBaseTexture2Var, vars.m_nBaseTexture2FrameVar );
		}
		pShaderAPI->BindStandardTexture( SHADER_SAMPLER2, TEXTURE_NORMALIZATION_CUBEMAP );
		if( vars.m_bBump )
		{
			BindTexture( SHADER_SAMPLER3, vars.m_nBumpmapVar, vars.m_nBumpmapFrame );
		}
		else
		{
			pShaderAPI->BindStandardTexture( SHADER_SAMPLER3, TEXTURE_NORMALIZATION_CUBEMAP );
		}

		if( bDetail )
		{
			BindTexture( SHADER_SAMPLER8, vars.m_nDetailVar );
		}

		if( vars.m_bWorldVertexTransition )
		{
			if( bBump2 )
			{
				BindTexture( SHADER_SAMPLER6, vars.m_nBumpmap2Var, vars.m_nBumpmap2Frame );
			}
		}

		if( vars.m_bLightmappedGeneric )
		{
#ifndef _X360
			if ( g_pHardwareConfig->HasFastVertexTextures() )
			{
				DECLARE_DYNAMIC_VERTEX_SHADER( lightmappedgeneric_flashlight_vs30 );
				SET_DYNAMIC_VERTEX_SHADER( lightmappedgeneric_flashlight_vs30 );
			}
			else
#endif
			{
				DECLARE_DYNAMIC_VERTEX_SHADER( lightmappedgeneric_flashlight_vs20 );
				SET_DYNAMIC_VERTEX_SHADER( lightmappedgeneric_flashlight_vs20 );
			}

			if ( bSeamless )
			{
				float const0[4]={ vars.m_fSeamlessScale,0,0,0};
				pShaderAPI->SetVertexShaderConstant( VERTEX_SHADER_SHADER_SPECIFIC_CONST_6, const0 );
			}

			if ( bDetail )
			{
				float vDetailConstants[4] = {1,1,1,1};

				if ( vars.m_nDetailTint != -1 )
				{
					params[vars.m_nDetailTint]->GetVecValue( vDetailConstants, 3 );
				}

				if ( vars.m_nDetailTextureBlendFactor != -1 )
				{
					vDetailConstants[3] = params[vars.m_nDetailTextureBlendFactor]->GetFloatValue();
				}

				pShaderAPI->SetPixelShaderConstant( 0, vDetailConstants, 1 );
			}
		}
		else
		{
			DECLARE_DYNAMIC_VERTEX_SHADER( vertexlitgeneric_flashlight_vs20 );
			SET_DYNAMIC_VERTEX_SHADER_COMBO( SKINNING, pShaderAPI->GetCurrentNumBones() > 0 );
			SET_DYNAMIC_VERTEX_SHADER( vertexlitgeneric_flashlight_vs20 );

			if( vars.m_bTeeth )
			{
				Assert( vars.m_nTeethForwardVar >= 0 );
				Assert( vars.m_nTeethIllumFactorVar >= 0 );
				Vector4D lighting;
				params[vars.m_nTeethForwardVar]->GetVecValue( lighting.Base(), 3 );
				lighting[3] = params[vars.m_nTeethIllumFactorVar]->GetFloatValue();
				pShaderAPI->SetVertexShaderConstant( VERTEX_SHADER_SHADER_SPECIFIC_CONST_0, lighting.Base() );
			}
		}

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

#ifndef _X360
		if ( g_pHardwareConfig->HasFastVertexTextures() )
		{
			DECLARE_DYNAMIC_PIXEL_SHADER( flashlight_ps30 );
			SET_DYNAMIC_PIXEL_SHADER_COMBO( FLASHLIGHTSHADOWS, flashlightState.m_bEnableShadows );
			SET_DYNAMIC_PIXEL_SHADER_COMBO( UBERLIGHT, flashlightState.m_bUberlight );
			SET_DYNAMIC_PIXEL_SHADER( flashlight_ps30 );

			SetupUberlightFromState( pShaderAPI, flashlightState );
		}
		else
#endif
		if ( g_pHardwareConfig->SupportsPixelShaders_2_b() )
		{
			DECLARE_DYNAMIC_PIXEL_SHADER( flashlight_ps20b );
			SET_DYNAMIC_PIXEL_SHADER_COMBO( FLASHLIGHTSHADOWS, flashlightState.m_bEnableShadows );
			SET_DYNAMIC_PIXEL_SHADER( flashlight_ps20b );
		}
		else
		{
			DECLARE_DYNAMIC_PIXEL_SHADER( flashlight_ps20 );
			SET_DYNAMIC_PIXEL_SHADER( flashlight_ps20 );
		}

		float atten[4];										// Set the flashlight attenuation factors
		atten[0] = flashlightState.m_fConstantAtten;
		atten[1] = flashlightState.m_fLinearAtten;
		atten[2] = flashlightState.m_fQuadraticAtten;
		atten[3] = flashlightState.m_FarZAtten;
		s_pShaderAPI->SetPixelShaderConstant( PSREG_FLASHLIGHT_ATTENUATION, atten, 1 );

		float pos[4];										// Set the flashlight origin
		pos[0] = flashlightState.m_vecLightOrigin[0];
		pos[1] = flashlightState.m_vecLightOrigin[1];
		pos[2] = flashlightState.m_vecLightOrigin[2];
		pos[3] = flashlightState.m_FarZ;
		pShaderAPI->SetPixelShaderConstant( PSREG_FLASHLIGHT_POSITION_RIM_BOOST, pos, 1 );	// rim boost not really used here

		SetFlashlightVertexShaderConstants( vars.m_bBump, vars.m_nBumpTransform, bDetail, vars.m_nDetailScale,  bSeamless ? false : true );
	}
	Draw();
}