Thursday, April 10, 2014

Interlacing Shader for CRTs

In the comments of my TVs and Retro Gaming post, GPDP and Monroe88 mentioned the need for a shader that would take a 480p signal from an emulator and either add 100% black scanlines on "240p" content or blank alternating fields each frame. In other words, they needed a shader that would interlace the default progressive signal, which would allow them to run their displays at 480p for all retro console emulation instead of having to switch back and forth between 320x240 (most games for NES, SNES, Genesis/Mega Drive etc.) and 640x480 (for games that utilized the added lines of resolution that interlacing provided, such as 2-player mode in Sonic 2, SNES' R.P.M. Racing, and tons of PSX games).

So, here's the shader in RetroArch-compatible Cg format:
/* COMPATIBILITY
- HLSL compilers
- Cg compilers
*/
/*
Interlacing
Author: hunterk
License: Public domain
*/
struct input
{
float2 video_size;
float2 texture_size;
float2 output_size;
float frame_count;
float frame_direction;
float frame_rotation;
sampler2D texture : TEXUNIT0;
};
void main_vertex
(
float4 position : POSITION,
out float4 oPosition : POSITION,
uniform float4x4 modelViewProj,
float4 color : COLOR,
out float4 oColor : COLOR,
float2 texCoord : TEXCOORD,
out float2 oTexCoord : TEXCOORD,
uniform input IN
)
{
oPosition = mul(modelViewProj, position);
oColor = color;
oTexCoord = texCoord;
}
float4 main_fragment (in float2 texCoord : TEXCOORD, uniform input IN) : COLOR
{
float4 res = tex2D(IN.texture, texCoord);
float y = 0.0;
// assume anything with a vertical resolution greater than 400 lines is interlaced
if (IN.video_size.y > 400.0) y = IN.texture_size.y * texCoord.y + IN.frame_count;
else
y = 2.0 * IN.texture_size.y * texCoord.y;
if (fmod(y, 2.0) > 0.99999) return res;
else
return float4(0.0);
}
It has two branching 'if' statements, which is horrible for performance in shaders, but this one is simple enough--and only needs to run at 2x--that it shouldn't matter.

UPDATE: In the comments, Monroe88 mentioned another very useful shader for use with 31 kHz CRT monitors: aliaspider's TVoutTweaks, which lets you add some nice effects, such as composite color correction and horizontal bandwidth (blends things like SNES' pseudo-hires transparency and other dithering effects), which will make the image a little closer to a 15 kHz TV. See Monroe88's comment below for more info and a pic.

Cari Farmasi

Farmasi Di Kuala Lumpur dan Selangor Selangor / KL Area NO SHOPS NAMES ...