//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // // $Header: $ // $NoKeywords: $ //=============================================================================// #include "shaderlib/cshader.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" DEFINE_FALLBACK_SHADER( VertexLitGeneric, VertexLitGeneric_DX6 ) BEGIN_SHADER( VertexLitGeneric_DX6, "Help for VertexLitGeneric_DX6" ) BEGIN_SHADER_PARAMS SHADER_PARAM( DETAIL, SHADER_PARAM_TYPE_TEXTURE, "shadertest/detail", "detail texture" ) SHADER_PARAM( DETAILSCALE, SHADER_PARAM_TYPE_FLOAT, "4", "scale of the detail texture" ) SHADER_PARAM( SELFILLUMTINT, SHADER_PARAM_TYPE_COLOR, "[1 1 1]", "Self-illumination tint" ) SHADER_PARAM( ENVMAP, SHADER_PARAM_TYPE_TEXTURE, "shadertest/shadertest_env", "envmap" ) SHADER_PARAM( ENVMAPFRAME, SHADER_PARAM_TYPE_INTEGER, "", "" ) SHADER_PARAM( ENVMAPMASK, SHADER_PARAM_TYPE_TEXTURE, "shadertest/shadertest_envmask", "envmap mask" ) SHADER_PARAM( ENVMAPMASKFRAME, SHADER_PARAM_TYPE_INTEGER, "", "" ) SHADER_PARAM( ENVMAPMASKSCALE, SHADER_PARAM_TYPE_FLOAT, "1", "envmap mask scale" ) SHADER_PARAM( ENVMAPTINT, SHADER_PARAM_TYPE_COLOR, "[1 1 1]", "envmap tint" ) SHADER_PARAM( ENVMAPOPTIONAL, SHADER_PARAM_TYPE_BOOL, "0", "Make the envmap only apply to dx9 and higher hardware" ) END_SHADER_PARAMS SHADER_INIT_PARAMS() { SET_FLAGS2( MATERIAL_VAR2_SUPPORTS_HW_SKINNING ); if( !params[ENVMAPMASKSCALE]->IsDefined() ) params[ENVMAPMASKSCALE]->SetFloatValue( 1.0f ); if( !params[ENVMAPTINT]->IsDefined() ) params[ENVMAPTINT]->SetVecValue( 1.0f, 1.0f, 1.0f ); if( !params[SELFILLUMTINT]->IsDefined() ) params[SELFILLUMTINT]->SetVecValue( 1.0f, 1.0f, 1.0f ); if( !params[DETAILSCALE]->IsDefined() ) params[DETAILSCALE]->SetFloatValue( 4.0f ); // No envmap uses mode 0, it's one less pass // Also, if multipass = 0, then go to mode 0 also if ( ( !params[ENVMAP]->IsDefined() ) || ( !IS_FLAG_SET(MATERIAL_VAR_MULTIPASS) ) ) { CLEAR_FLAGS( MATERIAL_VAR_ENVMAPMODE ); } // Vertex color requires mode 1 if ( IS_FLAG_SET(MATERIAL_VAR_VERTEXCOLOR) ) { SET_FLAGS( MATERIAL_VAR_ENVMAPMODE ); } // No texture means no self-illum or env mask in base alpha if ( !params[BASETEXTURE]->IsDefined() ) { CLEAR_FLAGS( MATERIAL_VAR_SELFILLUM ); CLEAR_FLAGS( MATERIAL_VAR_BASEALPHAENVMAPMASK ); } // If in decal mode, no debug override... if ( IS_FLAG_SET(MATERIAL_VAR_DECAL) ) { SET_FLAGS( MATERIAL_VAR_NO_DEBUG_OVERRIDE ); } SET_FLAGS2( MATERIAL_VAR2_LIGHTING_VERTEX_LIT ); SET_FLAGS2( MATERIAL_VAR2_NEEDS_SOFTWARE_LIGHTING ); // Get rid of the envmap if it's optional for this dx level. if( params[ENVMAPOPTIONAL]->IsDefined() && params[ENVMAPOPTIONAL]->GetIntValue() ) { params[ENVMAP]->SetUndefined(); } // If mat_specular 0, then get rid of envmap if( !g_pConfig->UseSpecular() && params[ENVMAP]->IsDefined() && params[BASETEXTURE]->IsDefined() ) { params[ENVMAP]->SetUndefined(); } } SHADER_FALLBACK { return 0; } SHADER_INIT { if (params[BASETEXTURE]->IsDefined()) { LoadTexture( BASETEXTURE ); if (!params[BASETEXTURE]->GetTextureValue()->IsTranslucent()) { CLEAR_FLAGS( MATERIAL_VAR_SELFILLUM ); CLEAR_FLAGS( MATERIAL_VAR_BASEALPHAENVMAPMASK ); } } if (params[DETAIL]->IsDefined()) { LoadTexture( DETAIL ); } // Don't alpha test if the alpha channel is used for other purposes if (IS_FLAG_SET(MATERIAL_VAR_SELFILLUM) || IS_FLAG_SET(MATERIAL_VAR_BASEALPHAENVMAPMASK) ) CLEAR_FLAGS( MATERIAL_VAR_ALPHATEST ); if (params[ENVMAP]->IsDefined()) { if( !IS_FLAG_SET(MATERIAL_VAR_ENVMAPSPHERE) ) LoadCubeMap( ENVMAP ); else LoadTexture( ENVMAP ); if( !g_pHardwareConfig->SupportsCubeMaps() ) { SET_FLAGS( MATERIAL_VAR_ENVMAPSPHERE ); } if (params[ENVMAPMASK]->IsDefined()) LoadTexture( ENVMAPMASK ); } } int GetDrawFlagsPass1(IMaterialVar** params) { int flags = SHADER_DRAW_POSITION | SHADER_DRAW_COLOR; if (params[BASETEXTURE]->IsTexture()) flags |= SHADER_DRAW_TEXCOORD0; return flags; } void DrawVertexLightingOnly( IMaterialVar** params, IShaderDynamicAPI *pShaderAPI, IShaderShadow* pShaderShadow ) { SHADOW_STATE { pShaderShadow->EnableTexture( SHADER_SAMPLER0, false ); SetModulationShadowState(); SetDefaultBlendingShadowState( ); pShaderShadow->DrawFlags( GetDrawFlagsPass1( params ) ); DefaultFog(); } DYNAMIC_STATE { SetModulationDynamicState(); } Draw(); } void MultiplyByVertexLighting( IMaterialVar** params, IShaderDynamicAPI *pShaderAPI, IShaderShadow* pShaderShadow ) { SHADOW_STATE { // FIXME: How to deal with texture alpha?? pShaderShadow->EnableTexGen( SHADER_TEXTURE_STAGE0, false ); pShaderShadow->EnableTexGen( SHADER_TEXTURE_STAGE1, false ); pShaderShadow->EnableTexture( SHADER_SAMPLER0, false ); pShaderShadow->EnableTexture( SHADER_SAMPLER1, false ); // NOTE: We're not doing lightmapping here, but we want to use the // same blend mode as we used for lightmapping pShaderShadow->EnableBlending( true ); SingleTextureLightmapBlendMode(); pShaderShadow->EnableCustomPixelPipe( true ); pShaderShadow->CustomTextureStages( 1 ); // This here will perform color = vertex light * (cc alpha) + 1 * (1 - cc alpha) pShaderShadow->CustomTextureOperation( SHADER_TEXTURE_STAGE0, SHADER_TEXCHANNEL_COLOR, SHADER_TEXOP_BLEND_CONSTANTALPHA, SHADER_TEXARG_VERTEXCOLOR, SHADER_TEXARG_CONSTANTCOLOR ); // Alpha isn't used, it doesn't matter what we set it to. pShaderShadow->CustomTextureOperation( SHADER_TEXTURE_STAGE0, SHADER_TEXCHANNEL_ALPHA, SHADER_TEXOP_SELECTARG1, SHADER_TEXARG_NONE, SHADER_TEXARG_NONE ); pShaderShadow->DrawFlags( SHADER_DRAW_POSITION | SHADER_DRAW_COLOR ); FogToOOOverbright(); } DYNAMIC_STATE { // Put the alpha in the color channel to modulate the color down.... float alpha = GetAlpha(); pShaderAPI->Color4f( OO_OVERBRIGHT, OO_OVERBRIGHT, OO_OVERBRIGHT, alpha ); } Draw(); SHADOW_STATE { pShaderShadow->EnableCustomPixelPipe( false ); } } //----------------------------------------------------------------------------- // Used by mode 1 //----------------------------------------------------------------------------- void DrawBaseTimesVertexLighting( IMaterialVar** params, IShaderDynamicAPI *pShaderAPI, IShaderShadow* pShaderShadow ) { // Base times vertex lighting, no vertex color SHADOW_STATE { // alpha test pShaderShadow->EnableAlphaTest( IS_FLAG_SET(MATERIAL_VAR_ALPHATEST) ); // base pShaderShadow->EnableTexture( SHADER_SAMPLER0, true ); pShaderShadow->OverbrightValue( SHADER_TEXTURE_STAGE0, OVERBRIGHT ); // Independenly configure alpha and color // Color = Color mod * Vertex Light * Tex (x2) // Alpha = Constant Alpha * Tex Alpha (no tex alpha if self illum == 1) // Can't have color modulation here pShaderShadow->EnableConstantColor( IsColorModulating() ); // Independenly configure alpha and color pShaderShadow->EnableAlphaPipe( true ); pShaderShadow->EnableConstantAlpha( IsAlphaModulating() ); pShaderShadow->EnableVertexAlpha( IS_FLAG_SET(MATERIAL_VAR_VERTEXALPHA) ); if (!IS_FLAG_SET(MATERIAL_VAR_SELFILLUM) && !IS_FLAG_SET(MATERIAL_VAR_BASEALPHAENVMAPMASK)) pShaderShadow->EnableTextureAlpha( SHADER_TEXTURE_STAGE0, true ); SetDefaultBlendingShadowState( BASETEXTURE, true ); pShaderShadow->DrawFlags( GetDrawFlagsPass1( params ) ); DefaultFog(); } DYNAMIC_STATE { SetFixedFunctionTextureTransform( MATERIAL_TEXTURE0, BASETEXTURETRANSFORM ); BindTexture( SHADER_SAMPLER0, BASETEXTURE, FRAME ); SetModulationDynamicState(); } Draw(); SHADOW_STATE { pShaderShadow->EnableAlphaPipe( false ); } } //----------------------------------------------------------------------------- // Envmap times vertex lighting, no vertex color //----------------------------------------------------------------------------- void DrawEnvmapTimesVertexLighting( IMaterialVar** params, IShaderDynamicAPI *pShaderAPI, IShaderShadow* pShaderShadow ) { SHADOW_STATE { int materialVarFlags = params[FLAGS]->GetIntValue(); // alpha test pShaderShadow->EnableAlphaTest( false ); int flags = SetShadowEnvMappingState( ENVMAPMASK ) | SHADER_DRAW_COLOR; bool hasEnvMapMask = params[ENVMAPMASK]->IsTexture(); pShaderShadow->OverbrightValue( hasEnvMapMask ? SHADER_TEXTURE_STAGE1 : SHADER_TEXTURE_STAGE0, OVERBRIGHT ); // Independenly configure alpha and color // Color = Env map * Vertex Light * Envmapmask (x2) // Alpha = Constant Alpha * Vertex light alpha * Env Map mask Alpha pShaderShadow->EnableConstantColor( IsColorModulating() ); pShaderShadow->EnableAlphaPipe( true ); pShaderShadow->EnableConstantAlpha( IsAlphaModulating() ); pShaderShadow->EnableVertexAlpha( (materialVarFlags & MATERIAL_VAR_VERTEXALPHA) != 0 ); if (hasEnvMapMask) pShaderShadow->EnableTextureAlpha( SHADER_TEXTURE_STAGE1, true ); SetDefaultBlendingShadowState( BASETEXTURE, true ); pShaderShadow->DrawFlags( flags ); DefaultFog(); } DYNAMIC_STATE { SetDynamicEnvMappingState( ENVMAP, ENVMAPMASK, BASETEXTURE, ENVMAPFRAME, ENVMAPMASKFRAME, FRAME, BASETEXTURETRANSFORM, ENVMAPMASKSCALE ); } Draw(); SHADOW_STATE { pShaderShadow->EnableCustomPixelPipe( false ); pShaderShadow->EnableAlphaPipe( false ); } } void DrawMode1( IMaterialVar** params, IShaderDynamicAPI *pShaderAPI, IShaderShadow* pShaderShadow ) { bool texDefined = params[BASETEXTURE]->IsTexture(); bool envDefined = params[ENVMAP]->IsTexture(); // bool maskDefined = params[ENVMAPMASK]->IsTexture(); // Pass 1 : Base + env // FIXME: Could make it 1 pass for base + env, if it wasn't // for the envmap tint. So this is 3 passes for now.... // If it's base + mask * env, gotta do that in 2 passes // Gotta do funky stuff to fade out self-illuminated stuff bool hasEnvMapTint = !IsWhite(ENVMAPTINT); // Special case, can do in one pass if (!hasEnvMapTint && !texDefined && !IS_FLAG_SET(MATERIAL_VAR_VERTEXCOLOR) && !IsColorModulating() ) { DrawEnvmapTimesVertexLighting( params, pShaderAPI, pShaderShadow ); return; } if (texDefined) { FixedFunctionBaseTimesDetailPass( BASETEXTURE, FRAME, BASETEXTURETRANSFORM, DETAIL, DETAILSCALE ); } else { FixedFunctionMaskedEnvmapPass( ENVMAP, ENVMAPMASK, BASETEXTURE, ENVMAPFRAME, ENVMAPMASKFRAME, FRAME, BASETEXTURETRANSFORM, ENVMAPMASKSCALE, ENVMAPTINT ); } // We can get here if multipass isn't set if we specify a vertex color if ( IS_FLAG_SET(MATERIAL_VAR_MULTIPASS) ) { if ( texDefined && envDefined ) { FixedFunctionAdditiveMaskedEnvmapPass( ENVMAP, ENVMAPMASK, BASETEXTURE, ENVMAPFRAME, ENVMAPMASKFRAME, FRAME, BASETEXTURETRANSFORM, ENVMAPMASKSCALE, ENVMAPTINT ); } } // Pass 2 : * vertex lighting MultiplyByVertexLighting( params, pShaderAPI, pShaderShadow ); // FIXME: We could add it to the lightmap // Draw the selfillum pass (blows away envmap at self-illum points) if ( IS_FLAG_SET(MATERIAL_VAR_SELFILLUM) ) { FixedFunctionSelfIlluminationPass( SHADER_SAMPLER0, BASETEXTURE, FRAME, BASETEXTURETRANSFORM, SELFILLUMTINT ); } } void DrawMode0( IMaterialVar** params, IShaderDynamicAPI *pShaderAPI, IShaderShadow* pShaderShadow ) { // Pass 1 : Base * lightmap or just lightmap if ( params[BASETEXTURE]->IsTexture() ) { DrawBaseTimesVertexLighting( params, pShaderAPI, pShaderShadow ); // Detail map FixedFunctionMultiplyByDetailPass( BASETEXTURE, FRAME, BASETEXTURETRANSFORM, DETAIL, DETAILSCALE ); // Draw the selfillum pass if ( IS_FLAG_SET(MATERIAL_VAR_SELFILLUM) ) { FixedFunctionSelfIlluminationPass( SHADER_SAMPLER0, BASETEXTURE, FRAME, BASETEXTURETRANSFORM, SELFILLUMTINT ); } } else { DrawVertexLightingOnly( params, pShaderAPI, pShaderShadow ); // Detail map FixedFunctionMultiplyByDetailPass( BASETEXTURE, FRAME, BASETEXTURETRANSFORM, DETAIL, DETAILSCALE ); } // Pass 2 : Masked environment map if ( params[ENVMAP]->IsTexture() && (IS_FLAG_SET(MATERIAL_VAR_MULTIPASS)) ) { FixedFunctionAdditiveMaskedEnvmapPass( ENVMAP, ENVMAPMASK, BASETEXTURE, ENVMAPFRAME, ENVMAPMASKFRAME, FRAME, BASETEXTURETRANSFORM, ENVMAPMASKSCALE, ENVMAPTINT ); } } SHADER_DRAW { bool useMode1 = IS_FLAG_SET(MATERIAL_VAR_ENVMAPMODE); if (!useMode1) { // Base * Vertex Lighting + env DrawMode0( params, pShaderAPI, pShaderShadow ); } else { // ( Base + env ) * Vertex Lighting DrawMode1( params, pShaderAPI, pShaderShadow ); } } END_SHADER