Editor/UI/LandmarkOverlay.cs
using Sandbox;
namespace HumanoidRigger.Editor;
/// <summary>Screen-space handles drawn by the scene overlay above the character.</summary>
sealed class LandmarkOverlay : SceneCustomObject
{
record Handle(Vector3 Position,Color Color,bool Uncertain);
Handle[] handles=[];
float scale=1;
float pointRadius=5.5f;
public int Count=>handles.Length;
public LandmarkOverlay(SceneWorld world):base(world)
{
RenderLayer=SceneRenderLayer.OverlayWithoutDepth;
Bounds=BBox.FromPositionAndSize(Vector3.Zero,float.MaxValue);
}
public void Draw(IEnumerable<Landmark> points,float dpiScale,string selected,float radius)
{
scale=dpiScale;pointRadius=radius;
handles=points.Select(p=>new Handle(RiggerViewport.Engine(p.Position),(p.Role==selected?Color.White:PointColor(p.Role)).WithAlpha(.78f),p.Confidence<.6f)).ToArray();
}
public override void RenderSceneObject()
{
float radius=pointRadius*scale;
float pixels=Graphics.Viewport.Width/(2*MathF.Tan(Graphics.FieldOfView*MathF.PI/360));
foreach(var handle in handles)
{
var relative=handle.Position-Graphics.CameraPosition;
float depth=Vector3.Dot(relative,Graphics.CameraRotation.Forward);if(depth<=0)continue;
var position=new Vector2(Graphics.Viewport.Width*.5f-Vector3.Dot(relative,Graphics.CameraRotation.Left)*pixels/depth,
Graphics.Viewport.Height*.5f-Vector3.Dot(relative,Graphics.CameraRotation.Up)*pixels/depth);
var rect=new Rect(position-new Vector2(radius),new Vector2(radius*2));
Graphics.DrawRoundedRectangle(rect,handle.Color,new Vector4(radius),new Vector4(scale),Color.Black.WithAlpha(.8f));
if(handle.Uncertain)Graphics.DrawRoundedRectangle(new Rect(position-new Vector2(scale),new Vector2(2*scale)),Color.Black,new Vector4(scale));
}
}
internal static Color PointColor(string role)=>role.EndsWith(".L")?new(86/255f,180/255f,233/255f):role.EndsWith(".R")?new(190/255f,210/255f,85/255f):new(230/255f,159/255f,0);
public void Clear()=>handles=[];
}