DiamondPanel.Strokes.cs
using System;
using Sandbox;
namespace Diamonds;
public sealed partial class DiamondPanel
{
// Used only by editor comparisons; never exposed as a gameplay setting.
static bool drawingReferenceStrokes = false;
// Small mitered strips stay on Painter's inline polygon path instead of allocating
// a stroke primitive tree. This is restricted to the simple gem/fragment geometry.
static void DrawGemStroke( Painter p, ReadOnlySpan<Vector2> points, Color color, float width, bool closed )
{
if ( drawingReferenceStrokes || (!closed && points.Length > 4) )
{
p.Fill = Fill.None;
p.Stroke = Stroke.Solid( color, width );
if ( closed ) p.Polygon( points ); else p.Line( points );
return;
}
Span<Vector2> offsets = stackalloc Vector2[points.Length];
for ( int i = 0; i < points.Length; i++ )
{
var incoming = (points[i] - points[(i + points.Length - 1) % points.Length]).Normal;
var outgoing = (points[(i + 1) % points.Length] - points[i]).Normal;
if ( !closed && i == 0 ) incoming = outgoing;
if ( !closed && i == points.Length - 1 ) outgoing = incoming;
var n0 = new Vector2( -incoming.y, incoming.x );
var n1 = new Vector2( -outgoing.y, outgoing.x );
float denominator = 1 + Vector2.Dot( n0, n1 );
var miter = denominator > 0.00001f ? (n0 + n1) / denominator : n0;
// Match the default four-width miter limit; extreme shard tips use the original path.
if ( denominator <= 0.00001f || miter.Length > 4 )
{
p.Fill = Fill.None; p.Stroke = Stroke.Solid( color, width );
if ( closed ) p.Polygon( points ); else p.Line( points );
return;
}
offsets[i] = miter * (width * 0.5f);
}
p.Stroke = Stroke.None;
p.Fill = color;
if ( !closed )
{
// A single polygon keeps crack joins seamless. Longer cracks retain Painter's
// stroke path rather than splitting them across independently antialiased edges.
Span<Vector2> polygon = stackalloc Vector2[points.Length * 2];
for ( int i = 0; i < points.Length; i++ )
{
polygon[i] = points[i] + offsets[i];
polygon[polygon.Length - 1 - i] = points[i] - offsets[i];
}
p.Polygon( polygon );
return;
}
for ( int i = 0; i < points.Length; i++ )
{
int next = (i + 1) % points.Length;
p.Quad( points[i] + offsets[i], points[next] + offsets[next],
points[next] - offsets[next], points[i] - offsets[i] );
}
}
}