Skip to content

example_shaders

devonium edited this page Mar 13, 2024 · 14 revisions

Sobel operator (PostProcess)

vmt

SobelOperator
{
	"$basetexture"			"_rt_fullframefb"
	"$SBColor" "{255 0 0}"
}

lua

if !EGSM or !(EGSM.Version > 0) then return end -- DON'T FORGET TO CHECK

shaderlib.CompileVertexShader("SobelOperatorVertexShader", 0, [==[
#include "common_vs_fxc.h"

struct VS_INPUT
{
	float4 vPos					: POSITION;
};

struct VS_OUTPUT
{
	float4 projPosSetup	: POSITION;
};

VS_OUTPUT main( const VS_INPUT v )
{
	VS_OUTPUT o = (VS_OUTPUT)0;

	float4 vProjPos = mul(  v.vPos, cViewProj );
	vProjPos.z = dot( v.vPos, cViewProjZ );
  	o.projPosSetup = vProjPos;
	return o;
}
]==])

shaderlib.CompilePixelShader("SobelOperatorPixelShader", 0, [==[
sampler FrameBuffer : register(s0);
float3  SBColor : register(c0);

struct PS_IN
{
	float2 P 			: VPOS;
};

float4 main(PS_IN i ) : COLOR
{
	float4 edge_x = float4(0,0,0,0);
	float4 edge_y = float4(0,0,0,0);

	for (int dx = -1; dx <= 1; dx++)
    {
        for (int dy = -1; dy <= 1; dy++)
        {
            float2 uv = (i.P + float2(dx,dy)) / SCR_S;

            float4 pixel = tex2D(FrameBuffer, uv);

            edge_x += float(dx + dx * abs(dy)) * pixel;
            edge_y += float(dy + dy * abs(dx)) * pixel;
        }
    }

	float edge_x_max = max(edge_x.r, max(edge_x.g, edge_x.b));
    float edge_y_max = max(edge_y.r, max(edge_y.g, edge_y.b));

	float edge = edge_x_max * edge_x_max + edge_y_max * edge_y_max;

	float4 color = float4(0, 0, 0, 1);

	if(edge < 25)
	{
		color = float4((SBColor * edge), 1);
	}

	return color;
};
]==])



local shader = shaderlib.NewShader("SobelOperator")

shader:SetPixelShader("SobelOperatorPixelShader")
shader:SetVertexShader("SobelOperatorVertexShader")

shader:BindTexture(0, PARAM_BASETEXTURE)

local SBColor = shader:AddParam("$SBColor", SHADER_PARAM_TYPE_COLOR)
shader:SetPixelShaderConstantFP(0, SBColor)

local mat = Material("example_model_material")
local screentexture = render.GetScreenEffectTexture()

hook.Add("RenderScreenspaceEffects", "SobelOperator", function()
	render.UpdateScreenEffectTexture()
	render.CopyRenderTargetToTexture(screentexture)
	render.SetMaterial(mat)
	render.DrawScreenQuad()
end )

Sobel operator (Per-object)

vmt

SobelOperator
{
	"$basetexture"			"_rt_fullframefb"
	"$SBColor" "{255 0 0}"
}

lua

if !EGSM or !(EGSM.Version > 0) then return end -- DON'T FORGET TO CHECK

shaderlib.CompileVertexShader("SobelOperatorVertexShader", 0, [==[
#include "common_vs_fxc.h"
float curtime : register(c48);

struct VS_INPUT
{
	float4 vPos					: POSITION;		// Position
	float4 vNormal				: NORMAL;		// Normal
	float4 vBoneWeights			: BLENDWEIGHT;	// Skin weights
	float4 vBoneIndices			: BLENDINDICES;	// Skin indices
};

struct VS_OUTPUT
{
	float4 projPosSetup	: POSITION;
};

VS_OUTPUT main( const VS_INPUT v )
{
	VS_OUTPUT o = (VS_OUTPUT)0;

	float3 vNormal;
	DecompressVertex_Normal( v.vNormal, vNormal );

	float3 worldNormal, worldPos;
	SkinPositionAndNormal( SKINNING, v.vPos, vNormal, v.vBoneWeights, v.vBoneIndices, worldPos, worldNormal );

	float4 vProjPos = mul( float4( worldPos, 1 ), cViewProj );
	vProjPos.z = dot( float4( worldPos, 1  ), cViewProjZ );
  	o.projPosSetup = vProjPos;

	return o;
}
]==])

shaderlib.CompilePixelShader("SobelOperatorPixelShader", 0, [==[
sampler FrameBuffer : register(s0);
float3  SBColor : register(c0);

struct PS_IN
{
	float2 P 			: VPOS;
};

float4 main(PS_IN i ) : COLOR
{
	float4 edge_x = float4(0,0,0,0);
	float4 edge_y = float4(0,0,0,0);

	for (int dx = -1; dx <= 1; dx++)
    {
        for (int dy = -1; dy <= 1; dy++)
        {
            float2 uv = (i.P + float2(dx,dy)) / SCR_S;

            float4 pixel = tex2D(FrameBuffer, uv);

            edge_x += float(dx + dx * abs(dy)) * pixel;
            edge_y += float(dy + dy * abs(dx)) * pixel;
        }
    }

	float edge_x_max = max(edge_x.r, max(edge_x.g, edge_x.b));
    float edge_y_max = max(edge_y.r, max(edge_y.g, edge_y.b));

	float edge = edge_x_max * edge_x_max + edge_y_max * edge_y_max;

	float4 color = float4(0, 0, 0, 1);

	if(edge < 25)
	{
		color = float4(SBColor*edge, 1);
	}

	return color;
};
]==])


local shader = shaderlib.NewShader("SobelOperator")

shader:SetPixelShader("SobelOperatorPixelShader")
shader:SetVertexShader("SobelOperatorVertexShader")

shader:BindStandardTexture(0, STDTEXTURE_FRAME_BUFFER_FULL_TEXTURE_0)

local SBColor = shader:AddParam("$SBColor", SHADER_PARAM_TYPE_COLOR)
shader:SetPixelShaderConstantFP(0, SBColor)

shader:SetFlags(MATERIAL_VAR_TRANSLUCENT)
shader:SetFlags2(MATERIAL_VAR2_SUPPORTS_HW_SKINNING)

Basic lightning + lack of vertex position precision (Per-object)

vmt

BasicLightning
{
	"$basetexture"			"hunter/myplastic"
}

lua

if !EGSM or !(EGSM.Version > 0) then return end -- DON'T FORGET TO CHECK

shaderlib.CompileVertexShader("VShading1", 0, [==[
#include "common_vs_fxc.h"

struct VS_INPUT
{
	float4 vPos			: POSITION;
	float4 vBoneWeights	: BLENDWEIGHT;
	float4 vBoneIndices	: BLENDINDICES;
	float4 vNormal		: NORMAL;
	float2 vTexCoord0	: TEXCOORD0;
};

struct VS_OUTPUT
{
	float4 projPosSetup	: POSITION;
	float2 baseTexCoord	: TEXCOORD0;
	float4 lightAtten	: TEXCOORD1;
	float3 worldNormal	: TEXCOORD2;
	float3 worldPos		: TEXCOORD3;
	float4 projPos		: TEXCOORD4;
};

VS_OUTPUT main( const VS_INPUT v )
{
	VS_OUTPUT o = ( VS_OUTPUT )0;

	float3 vNormal;
	DecompressVertex_Normal( v.vNormal, vNormal );

	float3 worldNormal, worldPos;
	SkinPositionAndNormal( SKINNING, v.vPos, vNormal, v.vBoneWeights, v.vBoneIndices, worldPos, worldNormal );

	worldPos = round(worldPos);

	// Transform into projection space
	float4 vProjPos = mul( float4( worldPos, 1 ), cViewProj );
	o.projPosSetup = vProjPos;
	vProjPos.z = dot( float4( worldPos, 1  ), cViewProjZ );
	o.projPos = vProjPos;

	// Needed for water fog alpha and diffuse lighting
	o.worldPos = worldPos;
	o.worldNormal = normalize( worldNormal );

	// Scalar attenuations for four lights
	o.lightAtten.xyz = float4(0,0,0,0);

	#if ( NUM_LIGHTS > 0 )
		o.lightAtten.x = GetVertexAttenForLight( worldPos, 0, false );
	#endif
	#if ( NUM_LIGHTS > 1 )
		o.lightAtten.y = GetVertexAttenForLight( worldPos, 1, false );
	#endif
	#if ( NUM_LIGHTS > 2 )
		o.lightAtten.z = GetVertexAttenForLight( worldPos, 2, false );
	#endif
	#if ( NUM_LIGHTS > 3 )
		o.lightAtten.w = GetVertexAttenForLight( worldPos, 3, false );
	#endif

	o.baseTexCoord = v.vTexCoord0;
	return o;
}
]==])

shaderlib.CompilePixelShader("PShading1", 0, [==[
#include "common_fxc.h"
#include "shader_constant_register_map.h"
#include "common_vertexlitgeneric_dx9.h"
#include "common_flashlight_fxc.h"
sampler BaseTexture : register(s0);

sampler ShadowDepthSampler		: register( s4 );
sampler NormalizeRandRotSampler	: register( s5 );
sampler FlashlightSampler		: register( s6 );

const float4 g_DiffuseModulation			: register( PSREG_DIFFUSE_MODULATION );
const float4 g_ShadowTweaks					: register( PSREG_ENVMAP_TINT__SHADOW_TWEAKS );
const float3 cAmbientCube[6]				: register( PSREG_AMBIENT_CUBE );
const float4 g_EyePos						: register( PSREG_EYEPOS_SPEC_EXPONENT );
const float4 g_FogParams					: register( PSREG_FOG_PARAMS );
const float4 g_FlashlightAttenuationFactors	: register( PSREG_FLASHLIGHT_ATTENUATION );			// On non-flashlight pass
const float4 g_FlashlightPos_RimBoost		: register( PSREG_FLASHLIGHT_POSITION_RIM_BOOST );
const float4x4 g_FlashlightWorldToTexture	: register( PSREG_FLASHLIGHT_TO_WORLD_TEXTURE );
PixelShaderLightInfo cLightInfo[3]			: register( PSREG_LIGHT_INFO_ARRAY );				// 2 registers each - 6 registers total (4th light spread across w's)

#define g_FlashlightPos					g_FlashlightPos_RimBoost.xyz
const float4 g_ShaderControls				: register( PSREG_SHADER_CONTROLS);

struct PS_INPUT
{
	float3 spos			: VPOS;
	float2 baseTexCoord	: TEXCOORD0;
	float4 lightAtten	: TEXCOORD1;
	float3 worldNormal	: TEXCOORD2;
	float3 worldPos		: TEXCOORD3;
	float4 projPos		: TEXCOORD4;
};

float4 main( PS_INPUT i ) : COLOR
{
	float4 baseColor = tex2D( BaseTexture, i.baseTexCoord);
	float3 diffuseLighting = float3(0,0,0);


#if FLASHLIGHT || X64
        float4 flashlightSpacePosition = mul( float4( i.worldPos, 1.0f ), g_FlashlightWorldToTexture );
	diffuseLighting = DoFlashlight( g_FlashlightPos, i.worldPos, flashlightSpacePosition, i.worldNormal,
	g_FlashlightAttenuationFactors.xyz,
		g_FlashlightAttenuationFactors.w, FlashlightSampler, ShadowDepthSampler,
		FlashlightSampler, 0, false, false, i.spos, false);
#endif

#if !FLASHLIGHT || X64
	// Summation of diffuse illumination from all local lights
	diffuseLighting += PixelShaderDoLighting( i.worldPos, i.worldNormal,
		float3( 0.0f, 0.0f, 0.0f ), false, true, i.lightAtten,
		cAmbientCube, NormalizeRandRotSampler, NUM_LIGHTS, cLightInfo, true,

		// These are dummy parameters:
		false, 1.0f,
		false, BaseTexture );
#endif

	float3 result = baseColor.rgb *  g_DiffuseModulation * diffuseLighting;
	float alpha = baseColor.a * g_DiffuseModulation.a;

	float fogFactor =  CalcPixelFogFactor( g_fPixelFogType, g_FogParams, g_EyePos.z, i.projPos.z, i.projPos.z );
	alpha = lerp( alpha, fogFactor, g_fWriteWaterFogToDestAlpha );
	return FinalOutput( float4( result, alpha ), fogFactor, g_fPixelFogType, TONEMAP_SCALE_LINEAR, g_fWriteDepthToAlpha, i.projPos.z );
}
]==])


local shader = shaderlib.NewShader("BasicLightning")

shader:SetPixelShader("PShading1")
shader:SetVertexShader("VShading1")

shader:BindTexture(0, PARAM_BASETEXTURE)
shader:EnableFlashlightSupport(true)

shader:SetPixelShaderStandardConstant(PSREG_LIGHT_INFO_ARRAY, STDCONST_LIGHT_INFO)
shader:SetPixelShaderStandardConstant(PSREG_FOG_PARAMS, STDCONST_FOG_PARAMS)
shader:SetPixelShaderStandardConstant(PSREG_DIFFUSE_MODULATION, STDCONST_DIFFUSE_MODULATION)
shader:SetPixelShaderStandardConstant(PSREG_AMBIENT_CUBE, STDCONST_AMBIENT_CUBE)
shader:SetPixelShaderStandardConstant(PSREG_SHADER_CONTROLS, STDCONST_SHADER_CONTROLS)

shader:SetFlags(MATERIAL_VAR_HALFLAMBERT)
shader:SetFlags2(MATERIAL_VAR2_SUPPORTS_HW_SKINNING+MATERIAL_VAR2_LIGHTING_VERTEX_LIT)

Shader override

if !EGSM or !(EGSM.Version > 1) then return end -- DON'T FORGET TO CHECK

shaderlib.CompileVertexShader("VertexLitGeneric_VertexShader", 0, [==[
#include "common_vs_fxc.h"
float curtime : register(c48);

struct VS_INPUT
{
	float4 vPos					: POSITION;		// Position
	float4 vNormal				: NORMAL;		// Normal
	float4 vBoneWeights			: BLENDWEIGHT;	// Skin weights
	float4 vBoneIndices			: BLENDINDICES;	// Skin indices
	float2 vTexCoord0	: TEXCOORD0;
};

struct VS_OUTPUT
{
	float4 projPosSetup	: POSITION;
	float2 vTexCoord0	: TEXCOORD0;
};

VS_OUTPUT main( const VS_INPUT v )
{
	VS_OUTPUT o = (VS_OUTPUT)0;

	float3 vNormal;
	DecompressVertex_Normal( v.vNormal, vNormal );

	float3 worldNormal, worldPos;
	SkinPositionAndNormal( SKINNING, v.vPos, vNormal, v.vBoneWeights, v.vBoneIndices, worldPos, worldNormal );

	float4 vProjPos = mul( float4( worldPos, 1 ), cViewProj );
	vProjPos.z = dot( float4( worldPos, 1  ), cViewProjZ );
  	o.projPosSetup = vProjPos;
	o.vTexCoord0 = v.vTexCoord0;
	return o;
}
]==])

shaderlib.CompilePixelShader("VertexLitGeneric_PixelShader", 0, [==[
sampler FrameBuffer : register(s0);
float vel : register(c0);

struct PS_IN
{
	float2 vTexCoord 			: TEXCOORD0;
	float2 pPos					: VPOS;
};

float4 main(PS_IN i ) : COLOR
{
	float4 c = tex2D(FrameBuffer, i.vTexCoord);
	c.rgb = (vel/500+0.1)-c.rgb;
	return c;
};
]==])


local shader = shaderlib.NewShader("VertexLitGeneric")

shader:SetPixelShader("VertexLitGeneric_PixelShader")
shader:SetVertexShader("VertexLitGeneric_VertexShader")

shader:BindTexture(0, PARAM_BASETEXTURE)
shader:EnableFlashlightSupport(true)

hook.Add("Think", "", function()
	shader:SetPixelShaderConstant(0, LocalPlayer():GetVelocity():Length())
end)

shader:SetFlags(0)
shader:SetFlags2(MATERIAL_VAR2_SUPPORTS_HW_SKINNING+MATERIAL_VAR2_LIGHTING_VERTEX_LIT)

How to use WorldPosDepthBuffer and _rt_Normals(PostProcess)

vmt

WDDemo
{
}  
if !EGSM or !(EGSM.Version >= 8) then return end -- DON'T FORGET TO CHECK

shaderlib.CompileVertexShader("WDDemoVSH", 0, [==[
#include "common_vs_fxc.h"
struct VS_INPUT
{
	float4 vPos					: POSITION;		// Position
	float4 vTexCoord				: TEXCOORD0;
};

struct VS_OUTPUT
{
	float4 projPosSetup	: POSITION;
	float4 vTexCoord				: TEXCOORD0;
};

VS_OUTPUT main( const VS_INPUT v )
{
	VS_OUTPUT o = (VS_OUTPUT)0;
	float4 vProjPos = mul( v.vPos, cViewProj );
	vProjPos.z = dot(  v.vPos, cViewProjZ );
  	o.projPosSetup = vProjPos;
	o.vTexCoord = v.vTexCoord;
	return o;
}
]==]) 

shaderlib.CompilePixelShader("WDDemoPSH", 0, [==[
sampler WDBuffer : register(s0);
sampler WDBufferN : register(s1);

float4 eyepos_curtime : register(c0);

struct PS_IN
{
	float2 vTexCoord				: TEXCOORD0;
};

float4 main(PS_IN i ) : COLOR
{
	float2 uv = i.vTexCoord;
	float4 wd = tex2D(WDBuffer, uv);
	float3 normal = tex2D(WDBufferN, uv);
	
	float3 linear_wpos = 1/wd.xyz;
    float  linear_depth = 1/wd.w;
	
	float dist = distance(linear_wpos.xy, eyepos_curtime.yzw) ;
	
	float far = 1000;
	
	if(dist > far)
	{
		wd.rgb = 1/distance(1/wd.xyz,float3(0,0,0))*4000;
		wd.rgb = normal;
		wd.a = 1;
		return wd; 
	}

	wd = 0;
	return wd;
};  
]==])


local shader = shaderlib.NewShader("WDDemo")
 
shader:SetPixelShader("WDDemoPSH")
shader:SetVertexShader("WDDemoVSH")

shader:SetParamDefValue(PARAM_BASETEXTURE, "_rt_WPNDepth")
shader:BindTexture(0, PARAM_BASETEXTURE)

local SBColor = shader:AddParam("$rtnormal", SHADER_PARAM_TYPE_TEXTURE, "_rt_Normals")
shader:BindTexture(1, SBColor)

shader:SetFlags(MATERIAL_VAR_TRANSLUCENT)

local mat = Material( "testmat" )
hook.Add( "RenderScreenspaceEffects", "", function() 
	render.SetMaterial(mat)
	render.DrawScreenQuadEx(0,0,ScrW(),ScrH())
end)

How to use RT

if !EGSM or !(EGSM.Version >= 8) then return end -- DON'T FORGET TO CHECK

shaderlib.CompileVertexShader("VertexLitGeneric_VertexShader", 0, [==[
#include "common_vs_fxc.h"
float curtime : register(c48);

struct VS_INPUT
{
	float4 vPos					: POSITION;		// Position
	float4 vNormal				: NORMAL;		// Normal
	float4 vBoneWeights			: BLENDWEIGHT;	// Skin weights
	float4 vBoneIndices			: BLENDINDICES;	// Skin indices
	float2 vTexCoord0	: TEXCOORD0;

	float3 vTangentS					: TANGENT;
	float3 vTangentT					: BINORMAL;
	float4 vColor						: COLOR0;
};

struct VS_OUTPUT
{
	float4 projPosSetup	: POSITION;
	float2 vTexCoord0	: TEXCOORD0;
	float4 color 		: COLOR0;
	float3 wPos 		: COLOR1;
};

VS_OUTPUT main( const VS_INPUT v )
{
	VS_OUTPUT o = (VS_OUTPUT)0;

	float3 vNormal;
	DecompressVertex_Normal( v.vNormal, vNormal );

	float3 worldNormal, worldPos;
	SkinPositionAndNormal( SKINNING, v.vPos, vNormal, v.vBoneWeights, v.vBoneIndices, worldPos, worldNormal );

	float4 vProjPos = mul( float4( worldPos, 1 ), cViewProj );
	vProjPos.z = dot( float4( worldPos, 1  ), cViewProjZ );
  	o.projPosSetup = vProjPos;
	o.vTexCoord0 = v.vTexCoord0;
	o.color = float4(worldNormal,1);
	o.wPos = worldPos;
	return o;
}
]==])

shaderlib.CompilePixelShader("VertexLitGeneric_PixelShader", 0, [==[
sampler FrameBuffer : register(s0);
float vel : register(c0);

struct PS_IN
{
	float2 vTexCoord 			: TEXCOORD0;
	float2 pPos					: VPOS;
	float4 color 		: COLOR0;
	float3 wPos 		: COLOR1;
};

struct PS_OUT
{
	float4 c0 			: COLOR0;
	float4 c1			: COLOR1;
	float4 c2			: COLOR2;
	float4 c3			: COLOR3;
};

PS_OUT main(PS_IN i )
{
	float4 c = tex2D(FrameBuffer, i.vTexCoord);
	PS_OUT l = (PS_OUT)0;
	//c.rgb = (vel/500+0.1)-c.rgb;
	l.c0 = c;
	l.c1 = i.color;
	l.c2 = float4(i.vTexCoord,0,1);
	l.c3 = float4(1/i.wPos,1);
	return l;
};
]==])


local shader = shaderlib.NewShader("VertexLitGeneric")

shader:SetPixelShader("VertexLitGeneric_PixelShader")
shader:SetVertexShader("VertexLitGeneric_VertexShader")

shader:BindTexture(0, PARAM_BASETEXTURE)
shader:EnableFlashlightSupport(false)

local tex = GetRenderTargetEx("ExampleRT",
    ScrW(), ScrH(),
    RT_SIZE_NO_CHANGE,
    MATERIAL_RT_DEPTH_SHARED,
    bit.bor(2, 256),
    0,
    IMAGE_FORMAT_BGRA8888
)
local tex2 = GetRenderTargetEx("ExampleRT2",
    ScrW(), ScrH(),
    RT_SIZE_NO_CHANGE,
    MATERIAL_RT_DEPTH_SHARED,
    bit.bor(2, 256),
    0,
    IMAGE_FORMAT_BGRA8888
)
local tex3 = GetRenderTargetEx("ExampleRT3",
    ScrW(), ScrH(),
    RT_SIZE_NO_CHANGE,
    MATERIAL_RT_DEPTH_SHARED,
    bit.bor(2, 256),
    0,
    IMAGE_FORMAT_BGRA8888
)
shader:SetRenderTarget(1, "ExampleRT")
shader:SetRenderTarget(2, "ExampleRT2")
shader:SetRenderTarget(3, "ExampleRT3")

shader:SetFlags(0)
shader:SetFlags2(MATERIAL_VAR2_SUPPORTS_HW_SKINNING+MATERIAL_VAR2_LIGHTING_VERTEX_LIT)

hook.Add("RenderScreenspaceEffects", shader:GetName(), function()
	render.DrawTextureToScreenRect( tex , 0, 0, ScrW()/4, ScrH())
	render.DrawTextureToScreenRect( tex2 , ScrW()/4, 0, ScrW()/4, ScrH())
	render.DrawTextureToScreenRect( tex3 , ScrW()/4*2, 0, ScrW()/4, ScrH())
	render.DrawTextureToScreenRect( render.GetScreenEffectTexture() , ScrW()/4 * 3, 0, ScrW()/4, ScrH())
	render.PushRenderTarget(tex)
	render.Clear(0,0,0,0)
	render.PopRenderTarget()	
	
	render.PushRenderTarget(tex2)
	render.Clear(0,0,0,0)
	render.PopRenderTarget()	
	
	render.PushRenderTarget(tex3)
	render.Clear(0,0,0,0)
	render.PopRenderTarget()
	
end )

Lightmap

if !EGSM or !(EGSM.Version > 1) then return end -- DON'T FORGET TO CHECK

shaderlib.CompileVertexShader("LightmappedGeneric_VertexShader", 0, [==[
#include "common_vs_fxc.h"

struct VS_INPUT
{
    float3 vPos                    		: POSITION;        
    float4 vNormal                		: NORMAL;        
    float2 vBaseTexCoord                : TEXCOORD0;
    float2 vLightmapTexCoord            : TEXCOORD1;
};

struct VS_OUTPUT
{
    float4 projPos                    : POSITION;    
    
    float2 baseTexCoord                : TEXCOORD0;
    float2 lightmapTexCoord            : TEXCOORD1;

};

VS_OUTPUT main( const VS_INPUT v )
{
    VS_OUTPUT o = (VS_OUTPUT)0;

    float3 worldPos = mul( float4( v.vPos, 1 ), cModel[0] );
    float4 vProjPos = mul( float4( v.vPos, 1 ), cModelViewProj );
    
    o.projPos = vProjPos;
    vProjPos.z = dot( float4( v.vPos, 1 ), cModelViewProjZ );
    
    float3 worldNormal = mul( v.vNormal, ( float3x3 )cModel[0] );
    
    o.baseTexCoord = v.vBaseTexCoord;
    o.lightmapTexCoord.xy = v.vLightmapTexCoord;

    return o;
}
]==])

shaderlib.CompilePixelShader("LightmappedGeneric_PixelShader", 0, [==[
sampler BaseTex : register(s0);
sampler LightMap : register(s1);

struct PS_INPUT
{
    float2 vTexCoord                 	: TEXCOORD0;
    float2 lightmapTexCoord         	: TEXCOORD1;
};

float4 main(PS_INPUT i ) : COLOR
{
    float4 al = tex2D(BaseTex, i.vTexCoord);
    float4 lm = tex2D(LightMap, i.lightmapTexCoord) * 4;
#if 1
	lm.rgb *= round(((lm.r+lm.g+lm.b)/3)*8) / 8;
	al.rgb *=lm.rgb;
    return al;
#else
	al.rgb *=lm.rgb;
    return al;
#endif

};
]==])

local shader = shaderlib.NewShader("LightmappedGeneric")

shader:SetPixelShader("LightmappedGeneric_PixelShader")
shader:SetVertexShader("LightmappedGeneric_VertexShader")

shader:BindTexture(0, PARAM_BASETEXTURE)
shader:BindStandardTexture(1, STDTEXTURE_LIGHTMAP)

shader:SetTexCoordCount(2)
shader:SetFlags2(MATERIAL_VAR2_LIGHTING_LIGHTMAP)