Files
2026-07-13 13:13:17 +08:00

91 lines
3.6 KiB
C#

using T3.Core.Utils;
using T3.Core.Utils.Geometry;
namespace Lib.io.input;
[Guid("eff2ffff-dc39-4b90-9b1c-3c0a9a0108c6")]
internal sealed class MouseInput : Instance<MouseInput>
{
[Output(Guid = "CDC87CE1-FAB8-4B96-9137-9965E064BFA3", DirtyFlagTrigger = DirtyFlagTrigger.Animated)]
public readonly Slot<Vector2> Position = new();
[Output(Guid = "78CAABCF-9C3B-4E50-9D80-BDCBABAEB003", DirtyFlagTrigger = DirtyFlagTrigger.Animated)]
public readonly Slot<bool> IsLeftButtonDown = new();
[Output(Guid = "BE90EED3-26BF-4DC3-9771-073C04D359BC", DirtyFlagTrigger = DirtyFlagTrigger.Animated)]
public readonly Slot<Vector3> Position3d = new();
public MouseInput()
{
Position.UpdateAction += Update;
Position3d.UpdateAction += Update;
IsLeftButtonDown.UpdateAction += Update;
}
private void Update(EvaluationContext context)
{
var mode = OutputMode.GetEnumValue<OutputModes>(context);
var scale = Scale.GetValue(context);
var aspectRatio = (float)context.RequestedResolution.Width / context.RequestedResolution.Height;
var lastPosition = T3.SystemUi.MouseInput.LastPosition;
switch (mode)
{
case OutputModes.Normalized:
Position.Value = lastPosition;
Position3d.Value = new Vector3(lastPosition.X, lastPosition.Y, 0);
break;
case OutputModes.SignedPosition:
Position.Value = (lastPosition - new Vector2(0.5f, 0.5f)) * new Vector2(aspectRatio, -1) * scale;
Position3d.Value = new Vector3(lastPosition.X, lastPosition.Y, 0);
break;
case OutputModes.OnWorldXYPlane:
case OutputModes.OnWorldFloorPlane:
{
Matrix4x4.Invert(context.CameraToClipSpace, out var clipSpaceToCamera);
Matrix4x4.Invert(context.WorldToCamera, out var cameraToWorld);
var clipSpaceToWorld = clipSpaceToCamera * cameraToWorld;
var posInClip = (lastPosition - new Vector2(0.5f, 0.5f)) * new Vector2(2, -2);
var posInWorld = GraphicsMath.TransformCoordinate(new Vector3(posInClip, 0f), clipSpaceToWorld);
var targetInWorld = GraphicsMath.TransformCoordinate(new Vector3(posInClip, 1f), clipSpaceToWorld);
var ray = new Ray(posInWorld, targetInWorld - posInWorld);
var planeNormal = mode == OutputModes.OnWorldXYPlane ? Vector3.UnitZ : Vector3.UnitY;
var xyPlane = PlaneExtensions.CreateFromPointAndNormal(Vector3.Zero, planeNormal);
if (xyPlane.Intersects(ray, out Vector3 intersectionPoint))
{
Position.Value = new Vector2(intersectionPoint.X, intersectionPoint.Y);
Position3d.Value = intersectionPoint;
}
break;
}
default:
throw new ArgumentOutOfRangeException(nameof(mode));
}
IsLeftButtonDown.Value = T3.SystemUi.MouseInput.IsLeftButtonDown;
Position3d.DirtyFlag.Clear();
Position.DirtyFlag.Clear();
IsLeftButtonDown.DirtyFlag.Clear();
}
[Input(Guid = "49775CC2-35B7-4C9F-A502-59FE8FBBE2A7")]
public readonly InputSlot<bool> DoUpdate = new();
[Input(Guid = "1327525C-716C-43E4-A5D1-58CF35440462", MappedType = typeof(OutputModes))]
public readonly InputSlot<int> OutputMode = new();
[Input(Guid = "6B1E81BD-2430-4439-AD0C-859B2433C38B")]
public readonly InputSlot<float> Scale = new();
private enum OutputModes
{
Normalized,
SignedPosition,
OnWorldXYPlane,
OnWorldFloorPlane
}
}