Code/Components/PostProcessing/CCSColorKey.cs
using Sandbox;
using System;


/// <summary>
/// Key out a color from the image or an image or apply an image on top of the screen.
/// </summary>

[Title( "Color Keyer" )]
[Category( "Post Processing" )]
[Icon( "colorize" )]




public sealed class CCSColorKey : Component, Component.ExecuteInEditor
{


	
	/// <summary>
	/// Color to key out.
	/// </summary>
    [Property, Title("Key Color")] 
    public Color keyColor { get; set; } = new Color(0.0f, 0.83f, 0.0f, 1.0f); 	
	
	/// <summary>
	/// vTex_C to use for the image to be keyed.
	/// </summary>
	[Property]
	public Texture image_texture;	
	
	
	
	/// <summary>
	/// Somewhat control the the color tolerance. Does NOT play well with tonemapping etc...
	/// </summary>
	[Header("Blending")]
	[Property, Title("Background Blend"), Range( 0.0f, 1.0f, 0, true )]  
    public float bBlend { get; set; } = 0.203f;
	

	
	/// <summary>
	/// Somewhat control the the color tolerance. Set both of these pretty close to each other for best results.
	/// </summary>
	[Property, Title("Foreground Blend") , Range( 0.0f, 1.0f, 0, true )]  
    public float fBlend { get; set; } = 0.203f;		
	
	/// <summary>
	/// Adjusts the opacity of the area which is keyed out.
	/// </summary>
	[Property, Title("Mask Opacity"), Range( 0.0f, 1.0f, 0, true )]  
    public float bOpacity { get; set; } = 1.0f;	
	
	/// <summary>
	/// Adjusts the opacity of the main image.
	/// </summary>
	[Property, Title("Foreground Opacity"), Range( 0.0f, 1.0f, 0, true )]  
    public float fOpacity { get; set; } = 1.0f;	
	


	
	/// <summary>
	/// Horizontal scale of the image.
	/// </summary>
	[Header("Image Transform")]
	[Property, Title("Horizontal Scale"), Range( 0.01f, 20.0f, 0, true )]  
    public float xScale { get; set; } = 1.0f;

	/// <summary>
	/// Vertical scale of the image.
	/// </summary>
	[Property, Title("Vertical Scale"), Range( 0.01f, 20.0f, 0, true )]  
    public float yScale { get; set; } = 1.0f;

	/// <summary>
	/// Horizontal image position offset from center.
	/// </summary>
	[Property, Title("Horizontal Position"), Range( -1.0f, 1.0f, 0, false )]  
    public float xPos { get; set; } = 0.0f;

	/// <summary>
	/// Vertical image position offset from center.
	/// </summary>
	[Property, Title("Vertical Position"), Range( -1.0f, 1.0f, 0, false )]  
    public float yPos { get; set; } = 0.0f;	

	
	/// <summary>
	/// Instead of applying the key to the game with the image under it, apply the key to the image and have the game under it.
	/// </summary>
	[Header("Extras")]
    [Property, Title("Overlay Mode")]  
    public bool kSwap { get; set; }		//kinda broken
	
	/// <summary>
	/// Allow the image texture to repeat. 
	/// </summary>
    [Property, Title("Tile Image")]  
    public bool iTile { get; set; }	= true;	
	
	/// <summary>
	/// Don't color key at all, just overlay.
	/// </summary>
    [Property, Title("Disable Keying")]  
    public bool dKey { get; set; }			
	
	/// <summary>
	/// Blend mode, works strangely in Overlay Mode!
	/// </summary>
	[Property, Title("Blend Mode")]
	public BlendMode BlendModeSelection { get; set; } = BlendMode.Normal;
	public enum BlendMode
	{
		[Description( "Normal Opacity blending" )]
		Normal,
		[Description( "Light areas become Brighter" )]
		Additive,
		[Description( "Light areas become darker" )] 
		Subtract, 	
		[Description( "Brightness of the overlay controls the Brightness" )]
		Multiply,
		[Description( "Dark parts of the image lighten and light parts become transparent" )]
		Divide,
		[Description( "Overlay lighter parts of the image" )]
		Screen,
		[Description( "like screen but takes the color of the image below")]
		ColorDodge
		//todo add more complex blend modes that are worthwile 	 
		//  https://www.clipstudio.net/how-to-draw/archives/154182
		//  https://www.deepskycolors.com/tools-tutorials/formulas-for-photoshop-blending-modes/
		
	}		
	
	
    IDisposable renderHook;
	
//	protected override void OnUpdate()
//	{
//
//	}

    protected override void OnEnabled()
    {
		
		renderHook?.Dispose();
		var cc = Components.Get<CameraComponent>( true );
		
		renderHook = cc.AddHookBeforeOverlay( "CCSColorKey", 2001, RenderEffect );
		
    }
	
    protected override void OnDisabled()
    {
        renderHook?.Dispose();
        renderHook = null;
    }

    RenderAttributes attributes = new RenderAttributes();

	
    public void RenderEffect( SceneCamera camera )
    {
        if ( !camera.EnablePostProcessing )
            return;

		
		attributes.Set( "image_texture", image_texture );
		attributes.Set( "keyColor", keyColor );
		attributes.Set( "bBlend", bBlend );
		attributes.Set( "fBlend", fBlend );
		attributes.Set( "kSwap", kSwap );
		attributes.Set( "iTile", iTile ); //the latest in apple bathroom smart floor technology
		attributes.Set( "dKey", dKey );
		
		attributes.Set( "xPos", xPos );
		attributes.Set( "xScale", xScale );
		attributes.Set( "yPos", yPos );
		attributes.Set( "yScale", yScale );
		
		attributes.Set( "fOpacity", fOpacity );
		attributes.Set( "bOpacity", bOpacity );		
		
		attributes.Set( "BlendMode", (int)BlendModeSelection );
		
		Graphics.GrabFrameTexture( "ColorBuffer", attributes );
       // Graphics.GrabDepthTexture( "DepthBuffer", attributes );
        Graphics.Blit( Material.Load( "materials/postprocess/ccs_colorkey.vmat" ), attributes );

    }
}