sampler2D Image : register(s0); sampler1D Palette : register(s1); #if PS14 sampler1D Gamma1 : register(s2); sampler1D Gamma2 : register(s3); sampler1D Gamma3 : register(s4); #endif float4 Desaturation : register(c1); // { Desat, 1 - Desat } float4 PaletteMod : register(c2); float4 Weights : register(c6); // RGB->Gray weighting { 77/256.0, 143/256.0, 37/256.0, 1 } float4 Gamma : register(c7); float4 TextureLookup(float2 tex_coord) { #if PALTEX float index = tex2D(Image, tex_coord).x; index = index * PaletteMod.x + PaletteMod.y; return tex1D(Palette, index); #else return tex2D(Image, tex_coord); #endif } float4 Invert(float4 rgb) { #if INVERT rgb.rgb = Weights.www - rgb.xyz; #endif return rgb; } float Grayscale(float4 rgb) { return dot(rgb.rgb, Weights.rgb); } float4 SampleTexture(float2 tex_coord) { return Invert(TextureLookup(tex_coord)); } // Normal color calculation for most drawing modes. float4 NormalColor(float2 tex_coord : TEXCOORD0, float4 Flash : COLOR0, float4 InvFlash : COLOR1) : COLOR { return Flash + SampleTexture(tex_coord) * InvFlash; } // Copy the red channel to the alpha channel. Pays no attention to palettes. float4 RedToAlpha(float2 tex_coord : TEXCOORD0, float4 Flash : COLOR0, float4 InvFlash : COLOR1) : COLOR { float4 color = Invert(tex2D(Image, tex_coord)); color.a = color.r; return Flash + color * InvFlash; } // Just return the value of c0. float4 VertexColor(float4 color : COLOR0) : COLOR { return color; } // Emulate one of the special colormaps. (Invulnerability, gold, etc.) float4 SpecialColormap(float2 tex_coord : TEXCOORD0, float4 start : COLOR0, float4 end : COLOR1) : COLOR { float4 color = SampleTexture(tex_coord); float4 range = end - start; // We can't store values greater than 1.0 in a color register, so we multiply // the final result by 2 and expect the caller to divide the start and end by 2. color.rgb = 2 * (start + Grayscale(color) * range).rgb; // Duplicate alpha semantics of NormalColor. color.a = start.a + color.a * end.a; return color; } // In-game colormap effect: fade to a particular color and multiply by another, with // optional desaturation of the original color. Desaturation is stored in c1. // Fade level is packed int fade.a. Fade.rgb has been premultiplied by alpha. // Overall alpha is in color.a. float4 InGameColormap(float2 tex_coord : TEXCOORD0, float4 color : COLOR0, float4 fade : COLOR1) : COLOR { float4 rgb = SampleTexture(tex_coord); // Desaturate #if DESAT float3 intensity; intensity.rgb = Grayscale(rgb) * Desaturation.x; rgb.rgb = intensity.rgb + rgb.rgb * Desaturation.y; #endif // Fade rgb.rgb = rgb.rgb * fade.aaa + fade.rgb; // Shade and Alpha rgb = rgb * color; return rgb; } // Windowed gamma correction. float4 GammaCorrection(float2 tex_coord : TEXCOORD0) : COLOR { float4 color = tex2D(Image, tex_coord); #if !PS14 color.rgb = pow(color.rgb, Gamma.rgb); #else // On PS14 targets, we can only sample once from each sampler // per stage. Fortunately, we have 16 samplers to play with, // so we can just set three of them to the gamma texture and // use one for each component. Unfortunately, all these // texture lookups are probably not as efficient as the pow() // solution that later targets make possible. color.r = tex1D(Gamma1, color.r * Gamma.w).r; color.g = tex1D(Gamma2, color.g * Gamma.w).g; color.b = tex1D(Gamma3, color.b * Gamma.w).b; #endif return color; } // The burn wipe effect. sampler2D NewScreen : register(s0); sampler2D Burn : register(s1); float4 BurnWipe(float2 coord[2] : TEXCOORD0) : COLOR { float4 color = tex2D(NewScreen, coord[0]); float4 alpha = tex2D(Burn, coord[1]); color.a = alpha.r * 2; return color; }