test/VHSEffect.cs
/// <summary>
/// Simulates the look of VHS camcorder footage: chromatic aberration, scanlines,
/// tape wobble, analog noise, tracking interference, and more. Attach to a camera
/// or use inside a PostProcessVolume for found-footage style visuals.
/// </summary>
[Title( "VHS Camcorder" )]
[Category( "Post Processing" )]
[Icon( "videocam" )]
public sealed class VHSEffect : BasePostProcess<VHSEffect>
{
	[Property, Range( 0, 1 ), Group( "General" )]
	public float Intensity { get; set; } = 1.0f;

	[Property, Range( 0, 1 ), Group( "Scanlines" )]
	public float ScanlineIntensity { get; set; } = 0.3f;

	[Property, Range( 0, 1 ), Group( "Distortion" )]
	public float WobbleAmount { get; set; } = 0.5f;

	[Property, Range( 0, 1 ), Group( "Noise" )]
	public float NoiseIntensity { get; set; } = 0.15f;

	[Property, Range( 0, 1 ), Group( "Tracking" )]
	public float TrackingIntensity { get; set; } = 0.3f;

	[Property, Range( 0, 1 ), Group( "Color" )]
	public float ChromaticAberration { get; set; } = 0.5f;

	[Property, Range( 0, 1 ), Group( "Color" )]
	public float VignetteIntensity { get; set; } = 0.6f;

	[Property, Range( 0, 1 ), Group( "Color" )]
	public float ColorDegradation { get; set; } = 0.5f;

	[Property, Range( 0, 1 ), Group( "Scanlines" )]
	public float InterlaceStrength { get; set; } = 0.25f;

	[Property, Range( 0, 1 ), Group( "Distortion" )]
	public float HeadSwitchNoise { get; set; } = 0.4f;

	[Property, Range( 0, 1 ), Group( "General" )]
	public float BlurAmount { get; set; } = 0.3f;

	[Property, Range( 0, 1 ), Group( "Tracking" )]
	public float RollingBarIntensity { get; set; } = 0.4f;

	public override void Render()
	{
		float intensity = GetWeighted( x => x.Intensity );
		if ( intensity.AlmostEqual( 0.0f ) )
		{
			return;
		}

		Attributes.Set( "intensity", intensity );
		Attributes.Set( "scanlineIntensity", GetWeighted( x => x.ScanlineIntensity ) );
		Attributes.Set( "wobbleAmount", GetWeighted( x => x.WobbleAmount ) );
		Attributes.Set( "noiseIntensity", GetWeighted( x => x.NoiseIntensity ) );
		Attributes.Set( "trackingIntensity", GetWeighted( x => x.TrackingIntensity ) );
		Attributes.Set( "chromaShift", GetWeighted( x => x.ChromaticAberration ) );
		Attributes.Set( "vignetteIntensity", GetWeighted( x => x.VignetteIntensity ) );
		Attributes.Set( "colorDegradation", GetWeighted( x => x.ColorDegradation ) );
		Attributes.Set( "interlaceStrength", GetWeighted( x => x.InterlaceStrength ) );
		Attributes.Set( "headSwitchNoise", GetWeighted( x => x.HeadSwitchNoise ) );
		Attributes.Set( "blurAmount", GetWeighted( x => x.BlurAmount ) );
		Attributes.Set( "rollingBarIntensity", GetWeighted( x => x.RollingBarIntensity ) );

		// Render after built-in post-processing effects (FilmGrain is at 200).
		// Stage lives in Sandbox.Rendering, not Sandbox directly.
		var shader = Material.FromShader( "test/shaders/postprocess/pp_vhs.shader" );
		var blit = BlitMode.WithBackbuffer( shader, Sandbox.Rendering.Stage.AfterPostProcess, 300, false );
		Blit( blit, "VHS Camcorder" );
	}
}