Components/PostProcessing/CCSLetterbox.cs
using Sandbox;
using System;
/// <summary>
/// Crop the screen using black bars like you are watching a DVD on an old tv.
/// </summary>
[Title( "Letterboxing" )]
[Category( "Post Processing" )]
[Icon( "theaters" )]
public sealed class CCSLetterbox : Component, Component.ExecuteInEditor
{
/// <summary>
/// Color of the letterboxing
/// </summary>
[Property]
public Color LetterboxColor { get; set; } = Color.Black; //black by default
//but you can change it for other cool effects, this shader can obviously
//be used for more than just letterboxing, it's props could be drivin
//actual list of aspect ratio presets
public float[] AspectRatios = {0.00f, 2.39f, 1.85f, 1.33f, 1.50f, 1.00f, 0.5625f, 0.80f, 2.76f, 3.50f,4.00f };
//FOR FUTURE REFERENCE : the array is initialized ONCE prob on add?. Otherwise relaunch sbox is you change.
private AspectPreset _aspectSelection;
/// <summary>
/// Will automatically letterbox the screen to the selected aspect ratio.
/// </summary>
[Property, Title("Aspect Ratio Preset")] public AspectPreset AspectSelection
{//im doing this goofy private var thing with both vars to get the toggle to work
get => _aspectSelection;
set
{
if (value != AspectPreset.None)
{
_aspectSelection = value;
_manualSettings = false;
}
else
{
_aspectSelection = value;
}
}
}
public enum AspectPreset
{
None,
[Description( "2.39:1 Widescreen film" )]
Scope,
[Description( "1.85:1 Theatrical film" )]
Flat,
[Description( "4:3 CLASSIC" )]
TV,
[Description( "3:2 35mm Photo" )]
FilmPhoto,
[Description( "1:1 Perfection" )]
Square,
[Description( "9:16 Vertical Video" )]
Vertical,
[Description( "4:5 Slightly less ugly" )]
InstaVertical = 7,
[Description( "2.76:1 The Cinema is yours" )]
UltraPanavision70,
[Description( "3.5:1 aka 32:9, dual monitor" )]
SuperUltraWide,
[Description( "4:1 Napoléon [1927]" )]
Polyvision
}
private bool _manualSettings;
/// <summary>
/// Manually set the vertical or horizontal letterboxing amount.
/// </summary>
[Property, Title("Aspect Ratio"), ToggleGroup("ManualSettings", Label = "Manual Settings")]
public bool ManualSettings
{
get => _manualSettings;
set
{
if (value)
{
_manualSettings = true;
AspectSelection = AspectPreset.None;
}
else
{
_manualSettings = false;
}
}
}
/// <summary>
/// Approx AspectRatio, based on current camera screen resolution which is goofy in the editor.
/// </summary>
[Property, Title("Aspect Ratio"), ReadOnly, Group("ManualSettings")]
public float AspectRatio { get; set; }
/// <summary>
/// Thickness of the bars going across the screen horizontally
/// </summary>
[Property, Title("Horizontal Bar Thickness"),Range( 0, 100.0f, 0, true), Group("ManualSettings")] // step 0 and clamp true
public float vPercent { get; set; } = 33.3f; //33 tee hee looks kinda cinematic
/// <summary>
/// Thickness of the bars going across the screen vertically
/// </summary>
[Property, Title("Vertical Bar Thickness"), Range( 0, 100.0f, 0, true ), Group("ManualSettings")] //horizontal
public float hPercent { get; set; } = 0.0f;
IDisposable renderHook;
protected override void OnUpdate()
{
var cc = Components.Get<CameraComponent>( true );
if(AspectSelection != AspectPreset.None){
float CameraAspect = cc.ScreenRect.Width / cc.ScreenRect.Height;
float DesiredAspect = AspectRatios[(int)AspectSelection];
//Log.Info($"desire int: " + (int)AspectSelection);
//Log.Info("desire: " + DesiredAspect);
if(DesiredAspect > CameraAspect)
{
vPercent = 100 * (1 - (CameraAspect / DesiredAspect));
hPercent = 0f;
}
if(DesiredAspect < CameraAspect)
{
hPercent = 100 * (1 - (DesiredAspect /CameraAspect));
vPercent = 0f;
}
}
AspectRatio = (cc.ScreenRect.Width - (cc.ScreenRect.Width * (hPercent / 100))) / (cc.ScreenRect.Height - (cc.ScreenRect.Height * (vPercent / 100 )));
}
protected override void OnEnabled()
{
renderHook?.Dispose();
var cc = Components.Get<CameraComponent>( true );
renderHook = cc.AddHookBeforeOverlay( "CCSLetterbox", 9001, RenderEffect );
}
protected override void OnDisabled()
{
renderHook?.Dispose();
renderHook = null;
}
RenderAttributes attributes = new RenderAttributes();
public void RenderEffect( SceneCamera camera )
{
if ( !camera.EnablePostProcessing )
return;
if (AspectSelection == AspectPreset.None & ManualSettings == false)
return;
attributes.Set( "vPercent", vPercent );
attributes.Set( "hPercent", hPercent );
attributes.Set( "LetterboxColor", LetterboxColor );
Graphics.GrabFrameTexture( "ColorBuffer", attributes );
// Graphics.GrabDepthTexture( "DepthBuffer", attributes );
Graphics.Blit( Material.Load( "materials/postprocess/ccs_letterbox.vmat" ), attributes );
}
}