< Summary

Line coverage
100%
Covered lines: 904
Uncovered lines: 0
Coverable lines: 904
Total lines: 1385
Line coverage: 100%
Branch coverage
100%
Covered branches: 206
Total branches: 206
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
File 1: .ctor(...)100%11100%
File 1: get_Events()100%11100%
File 1: get_DrawCommands()100%11100%
File 1: DispatchEventsTo(...)100%44100%
File 1: DispatchDrawCommandsTo(...)100%44100%
File 1: get_EventCount()100%11100%
File 1: get_DrawCommandCount()100%11100%
File 1: get_EventCapacity()100%11100%
File 1: get_DrawCommandCapacity()100%11100%
File 1: Enable(...)100%44100%
File 1: Disable()100%11100%
File 1: Clear()100%11100%
File 1: Reset()100%11100%
File 1: EmitForceDelta(...)100%22100%
File 1: EmitTorqueDelta(...)100%22100%
File 1: EmitLinearVelocityDelta(...)100%22100%
File 1: EmitAngularVelocityDelta(...)100%22100%
File 1: EmitGroundProbe(...)100%88100%
File 1: EmitGroundProbe(...)100%88100%
File 1: EmitRayQuery(...)100%88100%
File 1: EmitCircleQuery(...)100%88100%
File 1: EmitQuerySummary(...)100%22100%
File 1: EmitContact(...)100%88100%
File 1: EmitResponseImpulse(...)100%22100%
File 1: EmitMixedQuery(...)100%1818100%
File 1: EmitMixedContact(...)100%22100%
File 1: EmitMixedResponseImpulse(...)100%22100%
File 1: EmitMixedResponseIsland(...)100%22100%
File 1: EmitJointRegistered(...)100%22100%
File 1: EmitJointRegistered(...)100%22100%
File 1: EmitJointRemoved(...)100%22100%
File 1: EmitJointRemoved(...)100%22100%
File 1: EmitJointImpulse(...)100%22100%
File 1: EmitJointImpulse(...)100%22100%
File 1: EmitJointLimitReached(...)100%22100%
File 1: EmitJointLimitReached(...)100%22100%
File 1: EmitRagdollActivated(...)100%22100%
File 1: AddEvent(...)100%11100%
File 1: AddDrawCommand(...)100%11100%
File 1: ResolveDimension(...)100%44100%
File 1: ToDiagnosticVector(...)100%11100%
File 2: CaptureCollider(...)100%1616100%
File 2: CaptureMixedCollider(...)100%1010100%
File 2: CaptureJoint(...)100%66100%
File 2: CaptureJoint(...)100%44100%
File 2: CaptureLine(...)100%22100%
File 2: CaptureRay(...)100%44100%
File 2: CapturePoint(...)100%22100%
File 2: CaptureMeshTriangles(...)100%44100%
File 2: CaptureJointAxis(...)100%11100%
File 2: CaptureCompoundParts(...)100%1414100%
File 2: CaptureCompoundMeshTriangles(...)100%44100%
File 2: CaptureMixedCompoundParts(...)100%88100%
File 2: CaptureMixedCapsule(...)100%1010100%
File 2: CaptureMixedPolygon(...)100%11100%
File 2: CaptureMixedPolygon(...)100%1212100%

File(s)

/home/runner/work/Gravitas/Gravitas/src/Gravitas/Diagnostics/GravitasDiagnosticSink.cs

#LineLine coverage
 1//=======================================================================
 2// GravitasDiagnosticSink.cs
 3//=======================================================================
 4// MIT License, Copyright (c) 2026–present David Oravsky (mrdav30)
 5// See LICENSE file in the project root for full license information.
 6//=======================================================================
 7
 8using FixedMathSharp;
 9using Gravitas.Colliders;
 10using Gravitas.CollisionHandling;
 11using Gravitas.Constraints;
 12using Gravitas.Queries;
 13using SwiftCollections;
 14using System;
 15
 16namespace Gravitas.Diagnostics;
 17
 18/// <summary>
 19/// Context-owned deterministic diagnostics buffer for physics events and debug draw commands.
 20/// </summary>
 21public sealed partial class GravitasDiagnosticSink
 22{
 23    private readonly GravitasWorldContext _context;
 508324    private readonly SwiftList<GravitasDiagnosticEvent> _events = new();
 508325    private readonly SwiftList<GravitasDebugDrawCommand> _drawCommands = new();
 26    private int _eventSequence;
 27    private int _drawSequence;
 28
 508329    internal GravitasDiagnosticSink(GravitasWorldContext context)
 30    {
 508331        SwiftThrowHelper.ThrowIfNull(context, nameof(context));
 508332        _context = context;
 508333    }
 34
 35    /// <summary>
 36    /// Gets whether this sink records events and draw commands.
 37    /// </summary>
 38    public bool Enabled { get; private set; }
 39
 40    /// <summary>
 41    /// Gets captured diagnostic events for this context.
 42    /// </summary>
 5843    public ReadOnlySpan<GravitasDiagnosticEvent> Events => _events.AsReadOnlySpan();
 44
 45    /// <summary>
 46    /// Gets captured engine-agnostic draw commands for this context.
 47    /// </summary>
 4548    public ReadOnlySpan<GravitasDebugDrawCommand> DrawCommands => _drawCommands.AsReadOnlySpan();
 49
 50    /// <summary>
 51    /// Dispatches captured events in buffer order to a typed diagnostic visitor.
 52    /// </summary>
 53    public void DispatchEventsTo(GravitasDiagnosticEventVisitor visitor)
 54    {
 255        if (visitor == null)
 156            throw new ArgumentNullException(nameof(visitor));
 57
 158        ReadOnlySpan<GravitasDiagnosticEvent> events = Events;
 659        for (int i = 0; i < events.Length; i++)
 260            events[i].DispatchTo(visitor);
 161    }
 62
 63    /// <summary>
 64    /// Dispatches captured draw commands in buffer order to a typed debug draw visitor.
 65    /// </summary>
 66    public void DispatchDrawCommandsTo(GravitasDebugDrawCommandVisitor visitor)
 67    {
 268        if (visitor == null)
 169            throw new ArgumentNullException(nameof(visitor));
 70
 171        ReadOnlySpan<GravitasDebugDrawCommand> commands = DrawCommands;
 672        for (int i = 0; i < commands.Length; i++)
 273            commands[i].DispatchTo(visitor);
 174    }
 75
 76    /// <summary>Gets the number of captured diagnostic events.</summary>
 1377    public int EventCount => _events.Count;
 78
 79    /// <summary>Gets the number of captured debug draw commands.</summary>
 880    public int DrawCommandCount => _drawCommands.Count;
 81
 382    internal int EventCapacity => _events.Capacity;
 83
 484    internal int DrawCommandCapacity => _drawCommands.Capacity;
 85
 86    /// <summary>
 87    /// Enables diagnostics and optionally reserves buffer capacity for hot-path capture.
 88    /// </summary>
 89    public void Enable(int eventCapacity = 128, int drawCommandCapacity = 128)
 90    {
 7691        Enabled = true;
 7692        if (eventCapacity > 0)
 5493            _events.EnsureCapacity(eventCapacity);
 7694        if (drawCommandCapacity > 0)
 3495            _drawCommands.EnsureCapacity(drawCommandCapacity);
 7696    }
 97
 98    /// <summary>
 99    /// Disables diagnostics and clears captured data.
 100    /// </summary>
 101    public void Disable()
 102    {
 1103        Enabled = false;
 1104        Clear();
 1105    }
 106
 107    /// <summary>
 108    /// Clears captured data while retaining allocated buffer capacity.
 109    /// </summary>
 110    public void Clear()
 111    {
 42112        _events.FastClear();
 42113        _drawCommands.FastClear();
 42114        _eventSequence = 0;
 42115        _drawSequence = 0;
 42116    }
 117
 31118    internal void Reset() => Clear();
 119
 120    internal void EmitForceDelta(SolidBody body, Vector3d force, Vector3d accelerationDelta)
 121    {
 311122        if (!Enabled)
 307123            return;
 124
 4125        AddEvent(
 4126            GravitasDiagnosticEventKind.ForceDelta,
 4127            bodyId: body.DynamicId,
 4128            colliderAId: body.Collider.Id,
 4129            colliderAType: body.Collider.Shape,
 4130            vector: force,
 4131            pointA: accelerationDelta,
 4132            scalarA: force.Magnitude);
 4133    }
 134
 135    internal void EmitTorqueDelta(SolidBody body, Vector3d torque)
 136    {
 102137        if (!Enabled)
 98138            return;
 139
 4140        AddEvent(
 4141            GravitasDiagnosticEventKind.TorqueDelta,
 4142            bodyId: body.DynamicId,
 4143            colliderAId: body.Collider.Id,
 4144            colliderAType: body.Collider.Shape,
 4145            vector: torque,
 4146            scalarA: torque.Magnitude);
 4147    }
 148
 149    internal void EmitLinearVelocityDelta(SolidBody body, Vector3d before, Vector3d after)
 150    {
 247812151        if (!Enabled)
 247687152            return;
 153
 125154        AddEvent(
 125155            GravitasDiagnosticEventKind.LinearVelocityDelta,
 125156            bodyId: body.DynamicId,
 125157            colliderAId: body.Collider.Id,
 125158            colliderAType: body.Collider.Shape,
 125159            start: before,
 125160            end: after,
 125161            vector: after - before,
 125162            scalarA: after.Magnitude);
 125163    }
 164
 165    internal void EmitAngularVelocityDelta(SolidBody body, Vector3d before, Vector3d after)
 166    {
 240863167        if (!Enabled)
 240076168            return;
 169
 787170        AddEvent(
 787171            GravitasDiagnosticEventKind.AngularVelocityDelta,
 787172            bodyId: body.DynamicId,
 787173            colliderAId: body.Collider.Id,
 787174            colliderAType: body.Collider.Shape,
 787175            start: before,
 787176            end: after,
 787177            vector: after - before,
 787178            scalarA: after.Magnitude);
 787179    }
 180
 181    internal void EmitGroundProbe(
 182        SolidBody body,
 183        GroundProbeMode mode,
 184        Vector3d origin,
 185        Vector3d end,
 186        Fixed64 radius,
 187        bool hit,
 188        Physics3DHit raycastHit)
 189    {
 8760190        if (!Enabled)
 8728191            return;
 192
 32193        Vector3d point = default;
 32194        bool hasPoint = hit && raycastHit.TryGetPoint(out point);
 32195        AddEvent(
 32196            GravitasDiagnosticEventKind.GroundProbe,
 32197            bodyId: body.DynamicId,
 32198            colliderAId: body.Collider.Id,
 32199            colliderBId: raycastHit.Collider?.Id ?? -1,
 32200            colliderAType: body.Collider.Shape,
 32201            colliderBType: raycastHit.Collider?.Shape ?? ColliderType.None,
 32202            start: origin,
 32203            end: end,
 32204            pointA: point,
 32205            hasPointA: hasPoint,
 32206            vector: raycastHit.Normal,
 32207            scalarA: radius,
 32208            scalarB: raycastHit.Distance,
 32209            dataA: (int)mode,
 32210            hit: hit);
 32211    }
 212
 213    internal void EmitGroundProbe(
 214        SolidBody2D body,
 215        GroundProbeMode2D mode,
 216        Vector2d start,
 217        Vector2d end,
 218        Fixed64 radius,
 219        bool hit,
 220        Physics2DHit raycastHit)
 221    {
 5233222        if (!Enabled)
 5195223            return;
 224
 38225        AddEvent(
 38226            GravitasDiagnosticEventKind.GroundProbe,
 38227            bodyId: body.DynamicId,
 38228            colliderAId: body.Collider.Id,
 38229            colliderBId: raycastHit.Collider?.Id ?? -1,
 38230            colliderADimension: GravitasColliderDimension.TwoD,
 38231            colliderBDimension: raycastHit.Collider == null ? GravitasColliderDimension.None : GravitasColliderDimension
 38232            colliderA2DType: body.Collider.Shape,
 38233            colliderB2DType: raycastHit.Collider?.Shape ?? ColliderType2D.None,
 38234            start: ToDiagnosticVector(start),
 38235            end: ToDiagnosticVector(end),
 38236            pointA: ToDiagnosticVector(raycastHit.Point),
 38237            hasPointA: hit,
 38238            vector: ToDiagnosticVector(raycastHit.Normal),
 38239            scalarA: radius,
 38240            scalarB: raycastHit.Distance,
 38241            dataA: (int)mode,
 38242            dataB: (int)GravitasColliderDimension.TwoD,
 38243            hit: hit);
 38244    }
 245
 246    internal void EmitRayQuery(
 247        Vector3d start,
 248        Vector3d end,
 249        Fixed64 radius,
 250        int layerMaskBits,
 251        bool hit,
 252        int hitCount,
 253        Physics3DHit raycastHit)
 254    {
 15779255        if (!Enabled)
 15747256            return;
 257
 32258        Vector3d point = default;
 32259        bool hasPoint = hit && raycastHit.TryGetPoint(out point);
 32260        AddEvent(
 32261            GravitasDiagnosticEventKind.RayQuery,
 32262            colliderAId: raycastHit.Collider?.Id ?? -1,
 32263            colliderAType: raycastHit.Collider?.Shape ?? ColliderType.None,
 32264            start: start,
 32265            end: end,
 32266            pointA: point,
 32267            hasPointA: hasPoint,
 32268            vector: raycastHit.Normal,
 32269            scalarA: radius,
 32270            scalarB: raycastHit.Distance,
 32271            dataA: layerMaskBits,
 32272            dataB: hitCount,
 32273            hit: hit);
 32274    }
 275
 276    internal void EmitCircleQuery(
 277        Vector3d center,
 278        Fixed64 radius,
 279        Vector3d direction,
 280        Fixed64 maxDistance,
 281        int layerMaskBits,
 282        bool hit,
 283        int hitCount,
 284        Physics3DHit raycastHit)
 285    {
 35286        if (!Enabled)
 31287            return;
 288
 4289        Vector3d point = default;
 4290        bool hasPoint = hit && raycastHit.TryGetPoint(out point);
 4291        AddEvent(
 4292            GravitasDiagnosticEventKind.CircleQuery,
 4293            colliderAId: raycastHit.Collider?.Id ?? -1,
 4294            colliderAType: raycastHit.Collider?.Shape ?? ColliderType.None,
 4295            start: center,
 4296            end: center + direction * maxDistance,
 4297            pointA: point,
 4298            hasPointA: hasPoint,
 4299            vector: direction,
 4300            scalarA: radius,
 4301            scalarB: raycastHit.Distance,
 4302            dataA: layerMaskBits,
 4303            dataB: hitCount,
 4304            hit: hit);
 4305    }
 306
 307    internal void EmitQuerySummary(
 308        GravitasColliderDimension sourceDimension,
 309        GravitasColliderDimension targetDimension,
 310        Vector3d start,
 311        Vector3d end,
 312        int exactReducerAttempts,
 313        int acceptedHits,
 314        int fallbackHits,
 315        int rejectedConservativeCandidates)
 316    {
 6317        AddEvent(
 6318            GravitasDiagnosticEventKind.QuerySummary,
 6319            colliderADimension: sourceDimension,
 6320            colliderBDimension: targetDimension,
 6321            start: start,
 6322            end: end,
 6323            scalarA: (Fixed64)fallbackHits,
 6324            scalarB: (Fixed64)rejectedConservativeCandidates,
 6325            dataA: exactReducerAttempts,
 6326            dataB: acceptedHits,
 6327            hit: fallbackHits > 0 || rejectedConservativeCandidates > 0);
 6328    }
 329
 330    internal void EmitContact(CollisionPair pair, bool hit)
 331    {
 2489332        if (!Enabled)
 2472333            return;
 334
 17335        bool hasContact = pair.Manifold.HasContact;
 17336        ManifoldContact contact = hasContact
 17337            ? pair.Manifold.PrimaryContact
 17338            : default;
 17339        Vector3d pointA = default;
 17340        Vector3d pointB = default;
 17341        bool hasPointA = hasContact && contact.TryGetPointA(out pointA);
 17342        bool hasPointB = hasContact && contact.TryGetPointB(out pointB);
 343
 17344        AddEvent(
 17345            GravitasDiagnosticEventKind.Contact,
 17346            colliderAId: pair.ColliderA.Id,
 17347            colliderBId: pair.ColliderB.Id,
 17348            colliderAType: pair.ColliderA.Shape,
 17349            colliderBType: pair.ColliderB.Shape,
 17350            pointA: pointA,
 17351            pointB: pointB,
 17352            hasPointA: hasPointA,
 17353            hasPointB: hasPointB,
 17354            vector: contact.Normal,
 17355            scalarA: contact.Depth,
 17356            dataA: pair.Manifold.Count,
 17357            dataB: contact.DepthIsClamped ? 1 : 0,
 17358            hit: hit && hasContact);
 17359    }
 360
 361    internal void EmitResponseImpulse(CollisionPair pair, Vector3d impulse, Fixed64 normalVelocity)
 362    {
 6826363        if (!Enabled)
 6813364            return;
 365
 13366        ManifoldContact contact = pair.Manifold.PrimaryContact;
 13367        bool hasPointA = contact.TryGetPointA(out Vector3d pointA);
 13368        bool hasPointB = contact.TryGetPointB(out Vector3d pointB);
 369
 13370        AddEvent(
 13371            GravitasDiagnosticEventKind.ResponseImpulse,
 13372            colliderAId: pair.ColliderA.Id,
 13373            colliderBId: pair.ColliderB.Id,
 13374            colliderAType: pair.ColliderA.Shape,
 13375            colliderBType: pair.ColliderB.Shape,
 13376            pointA: pointA,
 13377            pointB: pointB,
 13378            hasPointA: hasPointA,
 13379            hasPointB: hasPointB,
 13380            vector: impulse,
 13381            scalarA: impulse.Magnitude,
 13382            scalarB: normalVelocity,
 13383            hit: true);
 13384    }
 385
 386    internal void EmitMixedQuery(
 387        Vector3d start,
 388        Vector3d end,
 389        Fixed64 radius,
 390        int layerMaskBits,
 391        bool hit,
 392        int hitCount,
 393        PhysicsMixedHit mixedHit)
 394    {
 1336395        if (!Enabled)
 1331396            return;
 397
 5398        Vector3d point3D = default;
 5399        Vector3d point2D = default;
 5400        bool hasPoint3D = hit && mixedHit.TryGetPoint3D(out point3D);
 5401        bool hasPoint2D = hit && mixedHit.TryGetPoint2D(out point2D);
 5402        AddEvent(
 5403            GravitasDiagnosticEventKind.MixedQuery,
 5404            colliderAId: mixedHit.Collider3D?.Id ?? -1,
 5405            colliderBId: mixedHit.Collider2D?.Id ?? -1,
 5406            colliderADimension: mixedHit.Collider3D == null ? GravitasColliderDimension.None : GravitasColliderDimension
 5407            colliderBDimension: mixedHit.Collider2D == null ? GravitasColliderDimension.None : GravitasColliderDimension
 5408            colliderAType: mixedHit.Collider3D?.Shape ?? ColliderType.None,
 5409            colliderB2DType: mixedHit.Collider2D?.Shape ?? ColliderType2D.None,
 5410            start: start,
 5411            end: end,
 5412            pointA: point3D,
 5413            pointB: point2D,
 5414            hasPointA: hasPoint3D,
 5415            hasPointB: hasPoint2D,
 5416            vector: mixedHit.Normal3DTo2D,
 5417            scalarA: radius,
 5418            scalarB: mixedHit.Distance,
 5419            dataA: layerMaskBits,
 5420            dataB: hitCount,
 5421            hit: hit);
 5422    }
 423
 424    internal void EmitMixedContact(CollisionPairMixed pair, MixedContact contact)
 425    {
 184426        if (!Enabled)
 161427            return;
 428
 23429        bool hasPoint3D = contact.TryGetPoint3D(out Vector3d point3D);
 23430        bool hasPoint2D = contact.TryGetPoint2D(out Vector3d point2D);
 23431        AddEvent(
 23432            GravitasDiagnosticEventKind.MixedContact,
 23433            colliderAId: pair.Collider3DId,
 23434            colliderBId: pair.Collider2DId,
 23435            colliderADimension: GravitasColliderDimension.ThreeD,
 23436            colliderBDimension: GravitasColliderDimension.TwoD,
 23437            colliderAType: pair.Collider3D.Shape,
 23438            colliderB2DType: pair.Collider2D.Shape,
 23439            pointA: point3D,
 23440            pointB: point2D,
 23441            hasPointA: hasPoint3D,
 23442            hasPointB: hasPoint2D,
 23443            vector: contact.Normal3DTo2D,
 23444            scalarA: contact.Depth,
 23445            dataA: contact.DepthIsClamped ? 1 : 0,
 23446            hit: true);
 23447    }
 448
 449    internal void EmitMixedResponseImpulse(
 450        CollisionPairMixed pair,
 451        MixedContact contact,
 452        Vector3d impulse,
 453        Fixed64 normalVelocity,
 454        int iteration,
 455        int iterationLimit)
 456    {
 110457        if (!Enabled)
 94458            return;
 459
 16460        bool hasPoint3D = contact.TryGetPoint3D(out Vector3d point3D);
 16461        bool hasPoint2D = contact.TryGetPoint2D(out Vector3d point2D);
 16462        AddEvent(
 16463            GravitasDiagnosticEventKind.MixedResponseImpulse,
 16464            colliderAId: pair.Collider3DId,
 16465            colliderBId: pair.Collider2DId,
 16466            colliderADimension: GravitasColliderDimension.ThreeD,
 16467            colliderBDimension: GravitasColliderDimension.TwoD,
 16468            colliderAType: pair.Collider3D.Shape,
 16469            colliderB2DType: pair.Collider2D.Shape,
 16470            pointA: point3D,
 16471            pointB: point2D,
 16472            hasPointA: hasPoint3D,
 16473            hasPointB: hasPoint2D,
 16474            vector: impulse,
 16475            scalarA: impulse.Magnitude,
 16476            scalarB: normalVelocity,
 16477            dataA: iteration,
 16478            dataB: iterationLimit,
 16479            hit: true);
 16480    }
 481
 482    internal void EmitMixedResponseIsland(
 483        int rootKey,
 484        int constraintCount,
 485        int iterationCount,
 486        bool reachedIterationLimit)
 487    {
 13488        if (!Enabled)
 6489            return;
 490
 7491        AddEvent(
 7492            GravitasDiagnosticEventKind.MixedResponseIsland,
 7493            bodyId: rootKey,
 7494            dataA: constraintCount,
 7495            dataB: iterationCount,
 7496            hit: reachedIterationLimit);
 7497    }
 498
 499    internal void EmitJointRegistered(Joint3D joint)
 500    {
 312501        if (!Enabled)
 307502            return;
 503
 5504        AddEvent(
 5505            GravitasDiagnosticEventKind.JointRegistered,
 5506            jointId: joint.Id,
 5507            colliderAId: joint.BodyA.Collider.Id,
 5508            colliderBId: joint.BodyB.Collider.Id,
 5509            colliderAType: joint.BodyA.Collider.Shape,
 5510            colliderBType: joint.BodyB.Collider.Shape,
 5511            dataA: (int)joint.Type,
 5512            dataB: (int)joint.CollisionPolicy);
 5513    }
 514
 515    internal void EmitJointRegistered(Joint2D joint)
 516    {
 195517        if (!Enabled)
 190518            return;
 519
 5520        AddEvent(
 5521            GravitasDiagnosticEventKind.JointRegistered,
 5522            jointId: joint.Id,
 5523            colliderAId: joint.BodyA.Collider.Id,
 5524            colliderBId: joint.BodyB.Collider.Id,
 5525            colliderADimension: GravitasColliderDimension.TwoD,
 5526            colliderBDimension: GravitasColliderDimension.TwoD,
 5527            colliderA2DType: joint.BodyA.Collider.Shape,
 5528            colliderB2DType: joint.BodyB.Collider.Shape,
 5529            dataA: (int)joint.Type,
 5530            dataB: (int)joint.CollisionPolicy);
 5531    }
 532
 533    internal void EmitJointRemoved(Joint3D joint)
 534    {
 29535        if (!Enabled)
 24536            return;
 537
 5538        AddEvent(
 5539            GravitasDiagnosticEventKind.JointRemoved,
 5540            jointId: joint.Id,
 5541            colliderAId: joint.BodyA.Collider.Id,
 5542            colliderBId: joint.BodyB.Collider.Id,
 5543            colliderAType: joint.BodyA.Collider.Shape,
 5544            colliderBType: joint.BodyB.Collider.Shape,
 5545            dataA: (int)joint.Type,
 5546            dataB: (int)joint.CollisionPolicy);
 5547    }
 548
 549    internal void EmitJointRemoved(Joint2D joint)
 550    {
 28551        if (!Enabled)
 23552            return;
 553
 5554        AddEvent(
 5555            GravitasDiagnosticEventKind.JointRemoved,
 5556            jointId: joint.Id,
 5557            colliderAId: joint.BodyA.Collider.Id,
 5558            colliderBId: joint.BodyB.Collider.Id,
 5559            colliderADimension: GravitasColliderDimension.TwoD,
 5560            colliderBDimension: GravitasColliderDimension.TwoD,
 5561            colliderA2DType: joint.BodyA.Collider.Shape,
 5562            colliderB2DType: joint.BodyB.Collider.Shape,
 5563            dataA: (int)joint.Type,
 5564            dataB: (int)joint.CollisionPolicy);
 5565    }
 566
 567    internal void EmitJointImpulse(Joint3D joint, JointSolveMetrics3D metrics)
 568    {
 48069569        if (!Enabled)
 47679570            return;
 571
 390572        AddEvent(
 390573            GravitasDiagnosticEventKind.JointImpulse,
 390574            jointId: joint.Id,
 390575            colliderAId: joint.BodyA.Collider.Id,
 390576            colliderBId: joint.BodyB.Collider.Id,
 390577            colliderAType: joint.BodyA.Collider.Shape,
 390578            colliderBType: joint.BodyB.Collider.Shape,
 390579            vector: new Vector3d(
 390580                metrics.MotorImpulseMagnitude,
 390581                metrics.MotorErrorMagnitude,
 390582                metrics.AngularLimitErrorMagnitude),
 390583            scalarA: metrics.AccumulatedImpulseMagnitude,
 390584            scalarB: metrics.LinearAnchorErrorMagnitude,
 390585            dataA: metrics.PreparedRowCount,
 390586            dataB: metrics.ClampedRowCount,
 390587            hit: metrics.IncrementalImpulseMagnitude > Fixed64.Zero);
 390588    }
 589
 590    internal void EmitJointImpulse(Joint2D joint, JointSolveMetrics2D metrics)
 591    {
 576592        if (!Enabled)
 571593            return;
 594
 5595        AddEvent(
 5596            GravitasDiagnosticEventKind.JointImpulse,
 5597            jointId: joint.Id,
 5598            colliderAId: joint.BodyA.Collider.Id,
 5599            colliderBId: joint.BodyB.Collider.Id,
 5600            colliderADimension: GravitasColliderDimension.TwoD,
 5601            colliderBDimension: GravitasColliderDimension.TwoD,
 5602            colliderA2DType: joint.BodyA.Collider.Shape,
 5603            colliderB2DType: joint.BodyB.Collider.Shape,
 5604            vector: new Vector3d(
 5605                metrics.MotorImpulseMagnitude,
 5606                metrics.MotorErrorMagnitude,
 5607                metrics.LimitErrorMagnitude),
 5608            scalarA: metrics.AccumulatedImpulseMagnitude,
 5609            scalarB: metrics.LinearAnchorErrorMagnitude,
 5610            dataA: metrics.PreparedRowCount,
 5611            dataB: metrics.ClampedRowCount,
 5612            hit: metrics.IncrementalImpulseMagnitude > Fixed64.Zero);
 5613    }
 614
 615    internal void EmitJointLimitReached(Joint3D joint, Fixed64 limitError)
 616    {
 89617        if (!Enabled)
 88618            return;
 619
 1620        AddEvent(
 1621            GravitasDiagnosticEventKind.JointLimitReached,
 1622            jointId: joint.Id,
 1623            colliderAId: joint.BodyA.Collider.Id,
 1624            colliderBId: joint.BodyB.Collider.Id,
 1625            colliderAType: joint.BodyA.Collider.Shape,
 1626            colliderBType: joint.BodyB.Collider.Shape,
 1627            scalarB: limitError,
 1628            dataA: (int)joint.Limits.Kind,
 1629            hit: limitError != Fixed64.Zero);
 1630    }
 631
 632    internal void EmitJointLimitReached(Joint2D joint, Fixed64 limitError)
 633    {
 177634        if (!Enabled)
 176635            return;
 636
 1637        AddEvent(
 1638            GravitasDiagnosticEventKind.JointLimitReached,
 1639            jointId: joint.Id,
 1640            colliderAId: joint.BodyA.Collider.Id,
 1641            colliderBId: joint.BodyB.Collider.Id,
 1642            colliderADimension: GravitasColliderDimension.TwoD,
 1643            colliderBDimension: GravitasColliderDimension.TwoD,
 1644            colliderA2DType: joint.BodyA.Collider.Shape,
 1645            colliderB2DType: joint.BodyB.Collider.Shape,
 1646            scalarB: limitError,
 1647            dataA: (int)joint.Limits.Kind,
 1648            hit: limitError != Fixed64.Zero);
 1649    }
 650
 651    internal void EmitRagdollActivated(int ragdollId, int linkCount, int jointCount, bool isActive)
 652    {
 16653        if (!Enabled)
 11654            return;
 655
 5656        AddEvent(
 5657            GravitasDiagnosticEventKind.RagdollActivated,
 5658            bodyId: ragdollId,
 5659            dataA: linkCount,
 5660            dataB: jointCount,
 5661            hit: isActive);
 5662    }
 663
 664    private void AddEvent(
 665        GravitasDiagnosticEventKind kind,
 666        int bodyId = -1,
 667        int jointId = -1,
 668        int colliderAId = -1,
 669        int colliderBId = -1,
 670        GravitasColliderDimension colliderADimension = GravitasColliderDimension.None,
 671        GravitasColliderDimension colliderBDimension = GravitasColliderDimension.None,
 672        ColliderType colliderAType = ColliderType.None,
 673        ColliderType colliderBType = ColliderType.None,
 674        ColliderType2D colliderA2DType = ColliderType2D.None,
 675        ColliderType2D colliderB2DType = ColliderType2D.None,
 676        Vector3d start = default,
 677        Vector3d end = default,
 678        Vector3d pointA = default,
 679        Vector3d pointB = default,
 680        bool hasPointA = false,
 681        bool hasPointB = false,
 682        Vector3d vector = default,
 683        Fixed64 scalarA = default,
 684        Fixed64 scalarB = default,
 685        int dataA = 0,
 686        int dataB = 0,
 687        bool hit = false)
 688    {
 1535689        _events.Add(new GravitasDiagnosticEvent(
 1535690            _context.FrameCount,
 1535691            _eventSequence++,
 1535692            kind,
 1535693            bodyId,
 1535694            jointId,
 1535695            colliderAId,
 1535696            colliderBId,
 1535697            ResolveDimension(colliderADimension, colliderAType),
 1535698            ResolveDimension(colliderBDimension, colliderBType),
 1535699            colliderAType,
 1535700            colliderBType,
 1535701            colliderA2DType,
 1535702            colliderB2DType,
 1535703            start,
 1535704            end,
 1535705            pointA,
 1535706            pointB,
 1535707            hasPointA,
 1535708            hasPointB,
 1535709            vector,
 1535710            scalarA,
 1535711            scalarB,
 1535712            dataA,
 1535713            dataB,
 1535714            hit));
 1535715    }
 716
 717    private void AddDrawCommand(
 718        GravitasDebugDrawKind kind,
 719        int colliderId = -1,
 720        ColliderType colliderType = ColliderType.None,
 721        GravitasColliderDimension colliderDimension = GravitasColliderDimension.None,
 722        ColliderType2D collider2DType = ColliderType2D.None,
 723        Vector3d start = default,
 724        Vector3d end = default,
 725        Vector3d center = default,
 726        Vector3d halfExtents = default,
 727        Vector3d pointA = default,
 728        Vector3d pointB = default,
 729        Vector3d pointC = default,
 730        FixedQuaternion rotation = default,
 731        Fixed64 radius = default,
 732        Fixed64 axisLength = default,
 733        Fixed64 height = default,
 734        GravitasDiagnosticColor color = default)
 735    {
 383736        _drawCommands.Add(new GravitasDebugDrawCommand(
 383737            _context.FrameCount,
 383738            _drawSequence++,
 383739            kind,
 383740            colliderId,
 383741            ResolveDimension(colliderDimension, colliderType),
 383742            colliderType,
 383743            collider2DType,
 383744            start,
 383745            end,
 383746            center,
 383747            halfExtents,
 383748            pointA,
 383749            pointB,
 383750            pointC,
 383751            rotation,
 383752            radius,
 383753            axisLength,
 383754            height,
 383755            color));
 383756    }
 757
 758    private static GravitasColliderDimension ResolveDimension(
 759        GravitasColliderDimension dimension,
 760        ColliderType colliderType)
 761    {
 3453762        if (dimension != GravitasColliderDimension.None)
 231763            return dimension;
 3222764        if (colliderType != ColliderType.None)
 2126765            return GravitasColliderDimension.ThreeD;
 1096766        return GravitasColliderDimension.None;
 767    }
 768
 152769    private static Vector3d ToDiagnosticVector(Vector2d value) => new(value.X, Fixed64.Zero, value.Y);
 770}

/home/runner/work/Gravitas/Gravitas/src/Gravitas/Diagnostics/GravitasDiagnosticSink.Draw.cs

#LineLine coverage
 1//=======================================================================
 2// GravitasDiagnosticSink.Draw.cs
 3//=======================================================================
 4// MIT License, Copyright (c) 2026-present David Oravsky (mrdav30)
 5// See LICENSE file in the project root for full license information.
 6//=======================================================================
 7
 8using FixedMathSharp;
 9using FixedMathSharp.Geometry;
 10using Gravitas.Colliders;
 11using Gravitas.Constraints;
 12
 13namespace Gravitas.Diagnostics;
 14
 15/// <content>
 16/// Provides host-driven collider, joint, and primitive debug draw capture.
 17/// </content>
 18public sealed partial class GravitasDiagnosticSink
 19{
 20    /// <summary>
 21    /// Emits an engine-agnostic draw command for the supplied collider shape.
 22    /// </summary>
 23    public void CaptureCollider(LSCollider collider, GravitasDiagnosticColor color)
 24    {
 9825        if (!Enabled)
 8326            return;
 27
 1528        SwiftThrowHelper.ThrowIfNull(collider, nameof(collider));
 29        switch (collider)
 30        {
 31            case LSSphereCollider sphere:
 232                AddDrawCommand(
 233                    GravitasDebugDrawKind.WireSphere,
 234                    sphere.Id,
 235                    sphere.Shape,
 236                    center: sphere.Center,
 237                    radius: sphere.ScaledRadius,
 238                    color: color);
 239                break;
 40            case LSCapsuleCollider capsule:
 141                AddDrawCommand(
 142                    GravitasDebugDrawKind.WireCapsule,
 143                    capsule.Id,
 144                    capsule.Shape,
 145                    center: capsule.Center,
 146                    rotation: capsule.Rotation,
 147                    radius: capsule.ScaledRadius,
 148                    axisLength: capsule.AxisLength,
 149                    color: color);
 150                break;
 51            case LSCuboidCollider cuboid:
 152                AddDrawCommand(
 153                    GravitasDebugDrawKind.WireBox,
 154                    cuboid.Id,
 155                    cuboid.Shape,
 156                    center: cuboid.Center,
 157                    halfExtents: cuboid.OrientedBox.HalfExtents,
 158                    rotation: cuboid.Rotation,
 159                    color: color);
 160                break;
 61            case LSCylinderCollider cylinder:
 162                AddDrawCommand(
 163                    GravitasDebugDrawKind.WireCylinder,
 164                    cylinder.Id,
 165                    cylinder.Shape,
 166                    center: cylinder.Center,
 167                    rotation: cylinder.Rotation,
 168                    radius: cylinder.ScaledRadius,
 169                    height: cylinder.Height,
 170                    color: color);
 171                break;
 72            case LSConeCollider cone:
 173                AddDrawCommand(
 174                    GravitasDebugDrawKind.WireCone,
 175                    cone.Id,
 176                    cone.Shape,
 177                    center: cone.Center,
 178                    rotation: cone.Rotation,
 179                    radius: cone.ScaledRadius,
 180                    height: cone.Height,
 181                    color: color);
 182                break;
 83            case LSCompoundCollider compound:
 484                CaptureCompoundParts(compound, color);
 485                break;
 86            case LSMeshCollider mesh:
 387                CaptureMeshTriangles(mesh, color);
 88                break;
 89        }
 390    }
 91
 92    /// <summary>
 93    /// Emits engine-agnostic draw commands for the finite 2D slab used by mixed 2D/3D collision.
 94    /// </summary>
 95    public void CaptureMixedCollider(LSCollider2D collider, GravitasDiagnosticColor color)
 96    {
 1797        if (!Enabled)
 198            return;
 99
 16100        SwiftThrowHelper.ThrowIfNull(collider, nameof(collider));
 15101        Vector3d center = new(collider.Center.X, collider.MixedSlabCenterY, collider.Center.Y);
 15102        Fixed64 height = collider.MixedHalfThickness * 2;
 103        switch (collider)
 104        {
 105            case LSCircleCollider2D circle:
 1106                AddDrawCommand(
 1107                    GravitasDebugDrawKind.WireCylinder,
 1108                    circle.Id,
 1109                    colliderDimension: GravitasColliderDimension.TwoD,
 1110                    collider2DType: circle.Shape,
 1111                    center: center,
 1112                    radius: circle.ScaledRadius,
 1113                    height: height,
 1114                    color: color);
 1115                break;
 116            case LSCapsuleCollider2D capsule:
 5117                CaptureMixedCapsule(capsule, color, capsule.Id, capsule.Shape);
 5118                break;
 119            case LSAABBoxCollider2D box:
 1120                AddDrawCommand(
 1121                    GravitasDebugDrawKind.WireBox,
 1122                    box.Id,
 1123                    colliderDimension: GravitasColliderDimension.TwoD,
 1124                    collider2DType: box.Shape,
 1125                    center: center,
 1126                    halfExtents: new Vector3d(
 1127                        box.ScaledHalfExtents.X,
 1128                        collider.MixedHalfThickness,
 1129                        box.ScaledHalfExtents.Y),
 1130                    color: color);
 1131                break;
 132            case LSCompoundCollider2D compound:
 2133                CaptureMixedCompoundParts(compound, color);
 2134                break;
 135            default:
 6136                CaptureMixedPolygon(collider, color);
 137                break;
 138        }
 6139    }
 140
 141    /// <summary>
 142    /// Emits engine-agnostic draw commands for a 3D joint's anchors and active angular axes.
 143    /// </summary>
 144    public void CaptureJoint(Joint3D joint, GravitasDiagnosticColor color)
 145    {
 7146        if (!Enabled)
 1147            return;
 148
 6149        SwiftThrowHelper.ThrowIfNull(joint, nameof(joint));
 5150        SolidBody bodyA = joint.BodyA;
 5151        SolidBody bodyB = joint.BodyB;
 5152        FixedQuaternion rotationA = (bodyA.Rotation * joint.LocalFrameA.Rotation).Normalized;
 5153        FixedQuaternion rotationB = (bodyB.Rotation * joint.LocalFrameB.Rotation).Normalized;
 5154        Vector3d anchorA = bodyA.Position3d + bodyA.Rotation * joint.LocalFrameA.Position;
 5155        Vector3d anchorB = bodyB.Position3d + bodyB.Rotation * joint.LocalFrameB.Position;
 5156        Fixed64 pointRadius = Fixed64.One / (Fixed64)10;
 5157        Fixed64 axisLength = Fixed64.One;
 158
 5159        AddDrawCommand(
 5160            GravitasDebugDrawKind.Point,
 5161            bodyA.Collider.Id,
 5162            bodyA.Collider.Shape,
 5163            center: anchorA,
 5164            radius: pointRadius,
 5165            color: color);
 5166        AddDrawCommand(
 5167            GravitasDebugDrawKind.Point,
 5168            bodyB.Collider.Id,
 5169            bodyB.Collider.Shape,
 5170            center: anchorB,
 5171            radius: pointRadius,
 5172            color: color);
 5173        AddDrawCommand(
 5174            GravitasDebugDrawKind.Line,
 5175            bodyA.Collider.Id,
 5176            bodyA.Collider.Shape,
 5177            start: anchorA,
 5178            end: anchorB,
 5179            color: color);
 180
 5181        switch (joint.Type)
 182        {
 183            case JointType3D.Hinge:
 2184                CaptureJointAxis(anchorA, rotationA * Vector3d.Right, axisLength, bodyA.Collider, color);
 2185                CaptureJointAxis(anchorB, rotationB * Vector3d.Right, axisLength, bodyB.Collider, color);
 2186                break;
 187            case JointType3D.ConeTwist:
 1188                CaptureJointAxis(anchorA, rotationA * Vector3d.Forward, axisLength, bodyA.Collider, color);
 1189                CaptureJointAxis(anchorB, rotationB * Vector3d.Forward, axisLength, bodyB.Collider, color);
 1190                break;
 191            case JointType3D.Fixed:
 1192                CaptureJointAxis(anchorA, rotationA * Vector3d.Right, axisLength, bodyA.Collider, color);
 1193                CaptureJointAxis(anchorA, rotationA * Vector3d.Up, axisLength, bodyA.Collider, color);
 1194                CaptureJointAxis(anchorA, rotationA * Vector3d.Forward, axisLength, bodyA.Collider, color);
 195                break;
 196        }
 1197    }
 198
 199    /// <summary>
 200    /// Emits engine-agnostic draw commands for a pure 2D joint's anchors and active planar axis.
 201    /// </summary>
 202    public void CaptureJoint(Joint2D joint, GravitasDiagnosticColor color)
 203    {
 5204        if (!Enabled)
 1205            return;
 206
 4207        SwiftThrowHelper.ThrowIfNull(joint, nameof(joint));
 3208        SolidBody2D bodyA = joint.BodyA;
 3209        SolidBody2D bodyB = joint.BodyB;
 3210        Fixed64 y = bodyA.Agent.Transform.WorldPosition.Y;
 3211        Vector2d anchorA2D = bodyA.Position + Vector2d.Rotate(joint.LocalFrameA.Anchor, bodyA.Rotation);
 3212        Vector2d anchorB2D = bodyB.Position + Vector2d.Rotate(joint.LocalFrameB.Anchor, bodyB.Rotation);
 3213        Vector3d anchorA = new(anchorA2D.X, y, anchorA2D.Y);
 3214        Vector3d anchorB = new(anchorB2D.X, y, anchorB2D.Y);
 3215        Fixed64 pointRadius = Fixed64.One / (Fixed64)10;
 216
 3217        AddDrawCommand(
 3218            GravitasDebugDrawKind.Point,
 3219            bodyA.Collider.Id,
 3220            colliderDimension: GravitasColliderDimension.TwoD,
 3221            collider2DType: bodyA.Collider.Shape,
 3222            center: anchorA,
 3223            radius: pointRadius,
 3224            color: color);
 3225        AddDrawCommand(
 3226            GravitasDebugDrawKind.Point,
 3227            bodyB.Collider.Id,
 3228            colliderDimension: GravitasColliderDimension.TwoD,
 3229            collider2DType: bodyB.Collider.Shape,
 3230            center: anchorB,
 3231            radius: pointRadius,
 3232            color: color);
 3233        AddDrawCommand(
 3234            GravitasDebugDrawKind.Line,
 3235            bodyA.Collider.Id,
 3236            colliderDimension: GravitasColliderDimension.TwoD,
 3237            collider2DType: bodyA.Collider.Shape,
 3238            start: anchorA,
 3239            end: anchorB,
 3240            color: color);
 241
 3242        if (joint.Type != JointType2D.Prismatic)
 2243            return;
 244
 1245        Vector2d axis2D = Vector2d.Rotate(Vector2d.Right, bodyA.Rotation + joint.LocalFrameA.Angle);
 1246        Vector3d axis = new(axis2D.X, Fixed64.Zero, axis2D.Y);
 247
 1248        AddDrawCommand(
 1249            GravitasDebugDrawKind.Ray,
 1250            bodyA.Collider.Id,
 1251            colliderDimension: GravitasColliderDimension.TwoD,
 1252            collider2DType: bodyA.Collider.Shape,
 1253            start: anchorA,
 1254            end: anchorA + axis.Normalized,
 1255            color: color);
 1256    }
 257
 258    /// <summary>
 259    /// Emits an engine-agnostic line draw command.
 260    /// </summary>
 261    public void CaptureLine(Vector3d start, Vector3d end, GravitasDiagnosticColor color)
 262    {
 7263        if (!Enabled)
 1264            return;
 265
 6266        AddDrawCommand(
 6267            GravitasDebugDrawKind.Line,
 6268            start: start,
 6269            end: end,
 6270            color: color);
 6271    }
 272
 273    /// <summary>
 274    /// Emits an engine-agnostic ray draw command from an origin, direction, and length.
 275    /// </summary>
 276    public void CaptureRay(Vector3d origin, Vector3d direction, Fixed64 length, GravitasDiagnosticColor color)
 277    {
 3278        if (!Enabled)
 1279            return;
 280
 2281        Vector3d end = direction.MagnitudeSquared == Fixed64.Zero
 2282            ? origin
 2283            : origin + direction.Normalized * length;
 284
 2285        AddDrawCommand(
 2286            GravitasDebugDrawKind.Ray,
 2287            start: origin,
 2288            end: end,
 2289            color: color);
 2290    }
 291
 292    /// <summary>
 293    /// Emits an engine-agnostic point draw command.
 294    /// </summary>
 295    public void CapturePoint(Vector3d point, Fixed64 radius, GravitasDiagnosticColor color)
 296    {
 4297        if (!Enabled)
 1298            return;
 299
 3300        AddDrawCommand(
 3301            GravitasDebugDrawKind.Point,
 3302            center: point,
 3303            radius: radius,
 3304            color: color);
 3305    }
 306
 307    private void CaptureMeshTriangles(LSMeshCollider mesh, GravitasDiagnosticColor color)
 308    {
 3309        int triangleCount = mesh.Mesh.TriangleCount;
 522310        for (int i = 0; i < triangleCount; i++)
 311        {
 258312            if (!mesh.Mesh.TryGetTriangleVertices(
 258313                    i,
 258314                    out Vector3d first,
 258315                    out Vector3d second,
 258316                    out Vector3d third))
 317            {
 318                continue;
 319            }
 257320            AddDrawCommand(
 257321                GravitasDebugDrawKind.WireTriangle,
 257322                mesh.Id,
 257323                mesh.Shape,
 257324                pointA: first,
 257325                pointB: second,
 257326                pointC: third,
 257327                color: color);
 328        }
 3329    }
 330
 331    private void CaptureJointAxis(
 332        Vector3d anchor,
 333        Vector3d axis,
 334        Fixed64 length,
 335        LSCollider collider,
 336        GravitasDiagnosticColor color)
 337    {
 9338        AddDrawCommand(
 9339            GravitasDebugDrawKind.Ray,
 9340            collider.Id,
 9341            collider.Shape,
 9342            start: anchor,
 9343            end: anchor + axis.Normalized * length,
 9344            color: color);
 9345    }
 346
 347    private void CaptureCompoundParts(LSCompoundCollider compound, GravitasDiagnosticColor color)
 348    {
 24349        for (int i = 0; i < compound.PartCount; i++)
 350        {
 8351            LSCollider part = compound.GetPartCollider(i);
 352            switch (part)
 353            {
 354                case LSSphereCollider sphere:
 1355                    AddDrawCommand(
 1356                        GravitasDebugDrawKind.WireSphere,
 1357                        compound.Id,
 1358                        compound.Shape,
 1359                        center: sphere.Center,
 1360                        radius: sphere.ScaledRadius,
 1361                        color: color);
 1362                    break;
 363                case LSCapsuleCollider capsule:
 1364                    AddDrawCommand(
 1365                        GravitasDebugDrawKind.WireCapsule,
 1366                        compound.Id,
 1367                        compound.Shape,
 1368                        center: capsule.Center,
 1369                        rotation: capsule.Rotation,
 1370                        radius: capsule.ScaledRadius,
 1371                        axisLength: capsule.AxisLength,
 1372                        color: color);
 1373                    break;
 374                case LSCuboidCollider cuboid:
 1375                    AddDrawCommand(
 1376                        GravitasDebugDrawKind.WireBox,
 1377                        compound.Id,
 1378                        compound.Shape,
 1379                        center: cuboid.Center,
 1380                        halfExtents: cuboid.OrientedBox.HalfExtents,
 1381                        rotation: cuboid.Rotation,
 1382                        color: color);
 1383                    break;
 384                case LSCylinderCollider cylinder:
 1385                    AddDrawCommand(
 1386                        GravitasDebugDrawKind.WireCylinder,
 1387                        compound.Id,
 1388                        compound.Shape,
 1389                        center: cylinder.Center,
 1390                        rotation: cylinder.Rotation,
 1391                        radius: cylinder.ScaledRadius,
 1392                        height: cylinder.Height,
 1393                        color: color);
 1394                    break;
 395                case LSConeCollider cone:
 1396                    AddDrawCommand(
 1397                        GravitasDebugDrawKind.WireCone,
 1398                        compound.Id,
 1399                        compound.Shape,
 1400                        center: cone.Center,
 1401                        rotation: cone.Rotation,
 1402                        radius: cone.ScaledRadius,
 1403                        height: cone.Height,
 1404                        color: color);
 1405                    break;
 406                case LSMeshCollider mesh:
 3407                    CaptureCompoundMeshTriangles(compound, mesh, color);
 408                    break;
 409            }
 410        }
 4411    }
 412
 413    private void CaptureCompoundMeshTriangles(
 414        LSCompoundCollider compound,
 415        LSMeshCollider mesh,
 416        GravitasDiagnosticColor color)
 417    {
 3418        int triangleCount = mesh.Mesh.TriangleCount;
 34419        for (int i = 0; i < triangleCount; i++)
 420        {
 14421            if (!mesh.Mesh.TryGetTriangleVertices(
 14422                    i,
 14423                    out Vector3d first,
 14424                    out Vector3d second,
 14425                    out Vector3d third))
 426            {
 427                continue;
 428            }
 13429            AddDrawCommand(
 13430                GravitasDebugDrawKind.WireTriangle,
 13431                compound.Id,
 13432                compound.Shape,
 13433                pointA: first,
 13434                pointB: second,
 13435                pointC: third,
 13436                color: color);
 437        }
 3438    }
 439
 440    private void CaptureMixedCompoundParts(LSCompoundCollider2D compound, GravitasDiagnosticColor color)
 441    {
 12442        for (int i = 0; i < compound.PartCount; i++)
 443        {
 4444            LSCollider2D part = compound.GetPartCollider(i);
 4445            Vector3d center = new(part.Center.X, part.MixedSlabCenterY, part.Center.Y);
 4446            Fixed64 height = part.MixedHalfThickness * 2;
 447            switch (part)
 448            {
 449                case LSCircleCollider2D circle:
 1450                    AddDrawCommand(
 1451                        GravitasDebugDrawKind.WireCylinder,
 1452                        compound.Id,
 1453                        colliderDimension: GravitasColliderDimension.TwoD,
 1454                        collider2DType: compound.Shape,
 1455                        center: center,
 1456                        radius: circle.ScaledRadius,
 1457                        height: height,
 1458                        color: color);
 1459                    break;
 460                case LSCapsuleCollider2D capsule:
 1461                    CaptureMixedCapsule(capsule, color, compound.Id, compound.Shape);
 1462                    break;
 463                case LSAABBoxCollider2D box:
 1464                    AddDrawCommand(
 1465                        GravitasDebugDrawKind.WireBox,
 1466                        compound.Id,
 1467                        colliderDimension: GravitasColliderDimension.TwoD,
 1468                        collider2DType: compound.Shape,
 1469                        center: center,
 1470                        halfExtents: new Vector3d(
 1471                            box.ScaledHalfExtents.X,
 1472                            box.MixedHalfThickness,
 1473                            box.ScaledHalfExtents.Y),
 1474                        color: color);
 1475                    break;
 476                default:
 1477                    CaptureMixedPolygon(part, color, compound.Id, compound.Shape);
 478                    break;
 479            }
 480        }
 2481    }
 482
 483    private void CaptureMixedCapsule(
 484        LSCapsuleCollider2D capsule,
 485        GravitasDiagnosticColor color,
 486        int colliderId,
 487        ColliderType2D colliderType)
 488    {
 6489        bool hasFirstEndpoint = FixedSegment2d.TryGetCenteredAxisEndpoint(
 6490                capsule.Center,
 6491                capsule.WorldAxis,
 6492                capsule.AxisLength,
 6493                positive: false,
 6494                out Vector2d firstEndpoint);
 6495        bool hasSecondEndpoint = FixedSegment2d.TryGetCenteredAxisEndpoint(
 6496                capsule.Center,
 6497                capsule.WorldAxis,
 6498                capsule.AxisLength,
 6499                positive: true,
 6500                out Vector2d secondEndpoint);
 501
 6502        Fixed64 height = capsule.MixedHalfThickness * 2;
 6503        if (hasFirstEndpoint)
 504        {
 5505            AddDrawCommand(
 5506                GravitasDebugDrawKind.WireCylinder,
 5507                colliderId,
 5508                colliderDimension: GravitasColliderDimension.TwoD,
 5509                collider2DType: colliderType,
 5510                center: new Vector3d(firstEndpoint.X, capsule.MixedSlabCenterY, firstEndpoint.Y),
 5511                radius: capsule.ScaledRadius,
 5512                height: height,
 5513                color: color);
 514        }
 515
 6516        if (hasSecondEndpoint)
 517        {
 5518            AddDrawCommand(
 5519                GravitasDebugDrawKind.WireCylinder,
 5520                colliderId,
 5521                colliderDimension: GravitasColliderDimension.TwoD,
 5522                collider2DType: colliderType,
 5523                center: new Vector3d(secondEndpoint.X, capsule.MixedSlabCenterY, secondEndpoint.Y),
 5524                radius: capsule.ScaledRadius,
 5525                height: height,
 5526                color: color);
 527        }
 528
 6529        Fixed64 segmentLength = capsule.AxisLength;
 6530        if (segmentLength <= Fixed64.Epsilon || !hasFirstEndpoint || !hasSecondEndpoint)
 3531            return;
 532
 3533        AddDrawCommand(
 3534            GravitasDebugDrawKind.WireBox,
 3535            colliderId,
 3536            colliderDimension: GravitasColliderDimension.TwoD,
 3537            collider2DType: colliderType,
 3538            center: new Vector3d(capsule.Center.X, capsule.MixedSlabCenterY, capsule.Center.Y),
 3539            halfExtents: new Vector3d(
 3540                capsule.ScaledRadius,
 3541                capsule.MixedHalfThickness,
 3542                segmentLength / Fixed64.Two),
 3543            rotation: FixedQuaternion.FromEulerAngles(Fixed64.Zero, capsule.Rotation, Fixed64.Zero),
 3544            color: color);
 3545    }
 546
 547    private void CaptureMixedPolygon(LSCollider2D collider, GravitasDiagnosticColor color) =>
 6548        CaptureMixedPolygon(collider, color, collider.Id, collider.Shape);
 549
 550    private void CaptureMixedPolygon(
 551        LSCollider2D collider,
 552        GravitasDiagnosticColor color,
 553        int colliderId,
 554        ColliderType2D colliderType)
 555    {
 7556        int vertexCount = collider.VertexCount;
 7557        bool hasTop = Fixed64.TryAdd(
 7558            collider.MixedSlabCenterY,
 7559            collider.MixedHalfThickness,
 7560            out Fixed64 topY);
 7561        bool hasBottom = Fixed64.TrySubtract(
 7562            collider.MixedSlabCenterY,
 7563            collider.MixedHalfThickness,
 7564            out Fixed64 bottomY);
 62565        for (int i = 0; i < vertexCount; i++)
 566        {
 24567            if (!collider.TryGetVertex(i, out Vector2d current))
 568                continue;
 569
 20570            if (hasTop && hasBottom)
 571            {
 12572                AddDrawCommand(
 12573                    GravitasDebugDrawKind.Line,
 12574                    colliderId,
 12575                    colliderDimension: GravitasColliderDimension.TwoD,
 12576                    collider2DType: colliderType,
 12577                    start: new Vector3d(current.X, topY, current.Y),
 12578                    end: new Vector3d(current.X, bottomY, current.Y),
 12579                    color: color);
 580            }
 581
 20582            if (!collider.TryGetVertex(
 20583                    (i + 1) % vertexCount,
 20584                    out Vector2d next))
 585            {
 586                continue;
 587            }
 588
 18589            if (hasTop)
 590            {
 14591                AddDrawCommand(
 14592                    GravitasDebugDrawKind.Line,
 14593                    colliderId,
 14594                    colliderDimension: GravitasColliderDimension.TwoD,
 14595                    collider2DType: colliderType,
 14596                    start: new Vector3d(current.X, topY, current.Y),
 14597                    end: new Vector3d(next.X, topY, next.Y),
 14598                    color: color);
 599            }
 600
 18601            if (hasBottom)
 602            {
 14603                AddDrawCommand(
 14604                    GravitasDebugDrawKind.Line,
 14605                    colliderId,
 14606                    colliderDimension: GravitasColliderDimension.TwoD,
 14607                    collider2DType: colliderType,
 14608                    start: new Vector3d(current.X, bottomY, current.Y),
 14609                    end: new Vector3d(next.X, bottomY, next.Y),
 14610                    color: color);
 611            }
 612        }
 7613    }
 614
 615}

Methods/Properties

.ctor(Gravitas.GravitasWorldContext)
get_Events()
get_DrawCommands()
DispatchEventsTo(Gravitas.Diagnostics.GravitasDiagnosticEventVisitor)
DispatchDrawCommandsTo(Gravitas.Diagnostics.GravitasDebugDrawCommandVisitor)
get_EventCount()
get_DrawCommandCount()
get_EventCapacity()
get_DrawCommandCapacity()
Enable(System.Int32,System.Int32)
Disable()
Clear()
Reset()
EmitForceDelta(Gravitas.SolidBody,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d)
EmitTorqueDelta(Gravitas.SolidBody,FixedMathSharp.Vector3d)
EmitLinearVelocityDelta(Gravitas.SolidBody,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d)
EmitAngularVelocityDelta(Gravitas.SolidBody,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d)
EmitGroundProbe(Gravitas.SolidBody,Gravitas.GroundProbeMode,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,System.Boolean,Gravitas.Queries.Physics3DHit)
EmitGroundProbe(Gravitas.SolidBody2D,Gravitas.GroundProbeMode2D,FixedMathSharp.Vector2d,FixedMathSharp.Vector2d,FixedMathSharp.Fixed64,System.Boolean,Gravitas.Queries.Physics2DHit)
EmitRayQuery(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,System.Int32,System.Boolean,System.Int32,Gravitas.Queries.Physics3DHit)
EmitCircleQuery(FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,System.Int32,System.Boolean,System.Int32,Gravitas.Queries.Physics3DHit)
EmitQuerySummary(Gravitas.Diagnostics.GravitasColliderDimension,Gravitas.Diagnostics.GravitasColliderDimension,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,System.Int32,System.Int32,System.Int32,System.Int32)
EmitContact(Gravitas.CollisionHandling.CollisionPair,System.Boolean)
EmitResponseImpulse(Gravitas.CollisionHandling.CollisionPair,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64)
EmitMixedQuery(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,System.Int32,System.Boolean,System.Int32,Gravitas.Queries.PhysicsMixedHit)
EmitMixedContact(Gravitas.CollisionHandling.CollisionPairMixed,Gravitas.CollisionHandling.MixedContact)
EmitMixedResponseImpulse(Gravitas.CollisionHandling.CollisionPairMixed,Gravitas.CollisionHandling.MixedContact,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,System.Int32,System.Int32)
EmitMixedResponseIsland(System.Int32,System.Int32,System.Int32,System.Boolean)
EmitJointRegistered(Gravitas.Constraints.Joint3D)
EmitJointRegistered(Gravitas.Constraints.Joint2D)
EmitJointRemoved(Gravitas.Constraints.Joint3D)
EmitJointRemoved(Gravitas.Constraints.Joint2D)
EmitJointImpulse(Gravitas.Constraints.Joint3D,Gravitas.Constraints.JointSolveMetrics3D)
EmitJointImpulse(Gravitas.Constraints.Joint2D,Gravitas.Constraints.JointSolveMetrics2D)
EmitJointLimitReached(Gravitas.Constraints.Joint3D,FixedMathSharp.Fixed64)
EmitJointLimitReached(Gravitas.Constraints.Joint2D,FixedMathSharp.Fixed64)
EmitRagdollActivated(System.Int32,System.Int32,System.Int32,System.Boolean)
AddEvent(Gravitas.Diagnostics.GravitasDiagnosticEventKind,System.Int32,System.Int32,System.Int32,System.Int32,Gravitas.Diagnostics.GravitasColliderDimension,Gravitas.Diagnostics.GravitasColliderDimension,Gravitas.Colliders.ColliderType,Gravitas.Colliders.ColliderType,Gravitas.Colliders.ColliderType2D,Gravitas.Colliders.ColliderType2D,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,System.Boolean,System.Boolean,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,System.Int32,System.Int32,System.Boolean)
AddDrawCommand(Gravitas.Diagnostics.GravitasDebugDrawKind,System.Int32,Gravitas.Colliders.ColliderType,Gravitas.Diagnostics.GravitasColliderDimension,Gravitas.Colliders.ColliderType2D,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.FixedQuaternion,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,FixedMathSharp.Fixed64,Gravitas.Diagnostics.GravitasDiagnosticColor)
ResolveDimension(Gravitas.Diagnostics.GravitasColliderDimension,Gravitas.Colliders.ColliderType)
ToDiagnosticVector(FixedMathSharp.Vector2d)
CaptureCollider(Gravitas.Colliders.LSCollider,Gravitas.Diagnostics.GravitasDiagnosticColor)
CaptureMixedCollider(Gravitas.Colliders.LSCollider2D,Gravitas.Diagnostics.GravitasDiagnosticColor)
CaptureJoint(Gravitas.Constraints.Joint3D,Gravitas.Diagnostics.GravitasDiagnosticColor)
CaptureJoint(Gravitas.Constraints.Joint2D,Gravitas.Diagnostics.GravitasDiagnosticColor)
CaptureLine(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,Gravitas.Diagnostics.GravitasDiagnosticColor)
CaptureRay(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,Gravitas.Diagnostics.GravitasDiagnosticColor)
CapturePoint(FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,Gravitas.Diagnostics.GravitasDiagnosticColor)
CaptureMeshTriangles(Gravitas.Colliders.LSMeshCollider,Gravitas.Diagnostics.GravitasDiagnosticColor)
CaptureJointAxis(FixedMathSharp.Vector3d,FixedMathSharp.Vector3d,FixedMathSharp.Fixed64,Gravitas.Colliders.LSCollider,Gravitas.Diagnostics.GravitasDiagnosticColor)
CaptureCompoundParts(Gravitas.Colliders.LSCompoundCollider,Gravitas.Diagnostics.GravitasDiagnosticColor)
CaptureCompoundMeshTriangles(Gravitas.Colliders.LSCompoundCollider,Gravitas.Colliders.LSMeshCollider,Gravitas.Diagnostics.GravitasDiagnosticColor)
CaptureMixedCompoundParts(Gravitas.Colliders.LSCompoundCollider2D,Gravitas.Diagnostics.GravitasDiagnosticColor)
CaptureMixedCapsule(Gravitas.Colliders.LSCapsuleCollider2D,Gravitas.Diagnostics.GravitasDiagnosticColor,System.Int32,Gravitas.Colliders.ColliderType2D)
CaptureMixedPolygon(Gravitas.Colliders.LSCollider2D,Gravitas.Diagnostics.GravitasDiagnosticColor)
CaptureMixedPolygon(Gravitas.Colliders.LSCollider2D,Gravitas.Diagnostics.GravitasDiagnosticColor,System.Int32,Gravitas.Colliders.ColliderType2D)