mirror of
https://github.com/Facepunch/sbox-public.git
synced 2026-08-01 00:08:05 -04:00
Panel can record custom commandlist like so:
```csharp
public class GlowPanel : Panel, IPanelDraw
{
static Material GlowMat = Material.FromShader( "shaders/ui_glow.shader" );
public void Draw( CommandList cl )
{
cl.Attributes.Set( "GlowColor", Color.Cyan );
cl.DrawQuad( Box.Rect, GlowMat, Color.White );
}
}```
157 lines
3.9 KiB
C#
157 lines
3.9 KiB
C#
using Sandbox.Rendering;
|
|
|
|
namespace Sandbox.UI;
|
|
|
|
/// <summary>
|
|
/// All descriptor types build into this
|
|
/// This is higher than the GPUBoxInstance because of the texture refs
|
|
/// but I want the texture refs so we can refresh bindless indices at render time
|
|
/// But this should be refactored down into the descriptor itself somehow, since we want to support custom ones..
|
|
/// </summary>
|
|
internal struct RenderInstance
|
|
{
|
|
public GPUBoxInstance GPU;
|
|
public BlendMode BlendMode;
|
|
public int Pass;
|
|
public Texture BackgroundImage;
|
|
public Texture BorderImage;
|
|
public bool HasInverseScissor;
|
|
public PanelRenderer.GPUScissor InverseScissor;
|
|
}
|
|
|
|
/// <summary>Pairs a user draw descriptor with its position in the instance stream.</summary>
|
|
internal struct UserRenderEntry
|
|
{
|
|
public IPanelDraw Descriptor;
|
|
public int InsertionIndex;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Collects all draw instances for a panel's cached render data.
|
|
/// Rebuilt when dirty, drawn during the gather phase.
|
|
/// </summary>
|
|
internal class RenderLayer
|
|
{
|
|
// Per-panel spatial/render state
|
|
public Matrix TransformMat;
|
|
public PanelRenderer.GPUScissor Scissor;
|
|
|
|
// Draw descriptors
|
|
public List<RenderInstance> Instances = [];
|
|
|
|
// These should be in the above list, but I'm bored of coding this
|
|
public List<BackdropDrawDescriptor> Backdrops = [];
|
|
|
|
// User draw descriptors, ordered by InsertionIndex into Instances
|
|
public List<UserRenderEntry> CustomEntries = [];
|
|
|
|
// Trackers whilst building
|
|
int _buildPass;
|
|
BlendMode _buildBlendMode = BlendMode.Normal;
|
|
bool _buildAnyBox;
|
|
|
|
public int Total => Instances.Count + Backdrops.Count + CustomEntries.Count;
|
|
public bool IsEmpty => Instances.Count == 0 && Backdrops.Count == 0 && CustomEntries.Count == 0;
|
|
|
|
public void AddShadow( in ShadowDrawDescriptor desc )
|
|
{
|
|
Instances.Add( new RenderInstance
|
|
{
|
|
GPU = GPUBoxInstance.FromShadow( desc ),
|
|
BlendMode = desc.Inset ? _buildBlendMode : BlendMode.Normal,
|
|
Pass = desc.Inset ? _buildPass : 0,
|
|
HasInverseScissor = !desc.Inset,
|
|
InverseScissor = !desc.Inset ? new PanelRenderer.GPUScissor
|
|
{
|
|
Rect = new Rect( desc.ScissorRect.x, desc.ScissorRect.y, desc.ScissorRect.z - desc.ScissorRect.x, desc.ScissorRect.w - desc.ScissorRect.y ),
|
|
CornerRadius = desc.ScissorCornerRadius,
|
|
Matrix = desc.ScissorTransformMat,
|
|
Invert = true,
|
|
} : default,
|
|
} );
|
|
}
|
|
|
|
public void AddBox( in BoxDrawDescriptor desc )
|
|
{
|
|
if ( desc.IsTwoPass ) return;
|
|
|
|
if ( _buildAnyBox && desc.OverrideBlendMode != _buildBlendMode )
|
|
_buildPass++;
|
|
|
|
_buildBlendMode = desc.OverrideBlendMode;
|
|
_buildAnyBox = true;
|
|
|
|
Instances.Add( new RenderInstance
|
|
{
|
|
GPU = GPUBoxInstance.From( desc ),
|
|
BlendMode = desc.OverrideBlendMode,
|
|
Pass = _buildPass,
|
|
BackgroundImage = desc.HasImage ? desc.BackgroundImage : null,
|
|
BorderImage = desc.HasBorderImage ? desc.BorderImageTexture : null,
|
|
} );
|
|
}
|
|
|
|
public void AddOutline( in OutlineDrawDescriptor desc )
|
|
{
|
|
Instances.Add( new RenderInstance
|
|
{
|
|
GPU = GPUBoxInstance.FromOutline( desc ),
|
|
BlendMode = _buildBlendMode,
|
|
Pass = _buildPass,
|
|
} );
|
|
}
|
|
|
|
public void AddCustom( IPanelDraw desc )
|
|
{
|
|
if ( desc is null ) return;
|
|
|
|
CustomEntries.Add( new UserRenderEntry
|
|
{
|
|
Descriptor = desc,
|
|
InsertionIndex = Instances.Count,
|
|
} );
|
|
}
|
|
|
|
/// <summary>
|
|
/// Clear all instances from this layer.
|
|
/// </summary>
|
|
public void Clear()
|
|
{
|
|
Instances.Clear();
|
|
Backdrops.Clear();
|
|
CustomEntries.Clear();
|
|
_buildPass = 0;
|
|
_buildBlendMode = BlendMode.Normal;
|
|
_buildAnyBox = false;
|
|
}
|
|
|
|
// Pool management
|
|
static readonly List<RenderLayer> Pool = new();
|
|
static int activeCount;
|
|
|
|
internal static int ActiveCount => activeCount;
|
|
internal static int PoolCount => Pool.Count;
|
|
|
|
public static RenderLayer Rent()
|
|
{
|
|
activeCount++;
|
|
|
|
if ( Pool.Count > 0 )
|
|
{
|
|
var layer = Pool[^1];
|
|
Pool.RemoveAt( Pool.Count - 1 );
|
|
layer.Clear();
|
|
return layer;
|
|
}
|
|
|
|
return new RenderLayer();
|
|
}
|
|
|
|
public static void Return( RenderLayer layer )
|
|
{
|
|
activeCount--;
|
|
layer.Clear();
|
|
Pool.Add( layer );
|
|
}
|
|
}
|