6
2025-11-07 12:32:48 +03:00

132 lines
4.9 KiB
C#

// SPDX-FileCopyrightText: 2025 Ark
// SPDX-FileCopyrightText: 2025 Redrover1760
// SPDX-FileCopyrightText: 2025 ark1368
//
// SPDX-License-Identifier: AGPL-3.0-or-later
using System.Numerics;
using System.Runtime.InteropServices;
using Content.Client.Resources;
using Content.Shared._Crescent.ShipShields;
using Robust.Client.Graphics;
using Robust.Client.ResourceManagement;
using Robust.Shared.Enums;
using Robust.Shared.Physics;
using Robust.Shared.Physics.Collision.Shapes;
using Robust.Shared.Physics.Systems;
using Robust.Shared.Prototypes;
namespace Content.Client._Crescent.ShipShields;
public sealed class ShipShieldOverlay : Overlay
{
private readonly FixtureSystem _fixture;
private readonly SharedPhysicsSystem _physics;
private readonly IResourceCache _resourceCache;
private readonly IEntityManager _entManager;
private readonly ShaderInstance _unshadedShader;
private readonly List<DrawVertexUV2D> _verts = new(128); // Mono
public override OverlaySpace Space => OverlaySpace.WorldSpaceBelowWorld;
public ShipShieldOverlay(IEntityManager entityManager, IPrototypeManager prototypeManager, IResourceCache resourceCache)
{
_resourceCache = resourceCache;
_entManager = entityManager;
_fixture = _entManager.EntitySysManager.GetEntitySystem<FixtureSystem>();
_physics = _entManager.EntitySysManager.GetEntitySystem<Robust.Client.Physics.PhysicsSystem>();
_unshadedShader = prototypeManager.Index<ShaderPrototype>("unshaded").Instance();
ZIndex = 8;
}
protected override void Draw(in OverlayDrawArgs args)
{
var handle = args.WorldHandle;
handle.UseShader(_unshadedShader);
var enumerator = _entManager.AllEntityQueryEnumerator<ShipShieldVisualsComponent, FixturesComponent, TransformComponent>();
while (enumerator.MoveNext(out var uid, out var visuals, out var fixtures, out var xform))
{
// VANTABLACK OVERDRAW FROM THE DEPTHS OF LAGHELL
if (xform.MapID != args.MapId)
continue;
// TODO: We can probably at least test its parent grid is in PVS range...?
var fixture = _fixture.GetFixtureOrNull(uid, "shield", fixtures);
if (fixture is not { Shape: ChainShape chain })
continue;
var texture = _resourceCache.GetTexture("/Textures/_Crescent/ShipShields/shieldtex.png");
DrawShield(handle, uid, chain, xform, texture, visuals.ShieldColor, _verts);
_verts.Clear(); // Clear for next shield - Mono
}
}
private void DrawShield(
DrawingHandleWorld handle,
EntityUid uid,
ChainShape chain,
TransformComponent xform,
Texture tex,
Color color,
List<DrawVertexUV2D> verts)
{
// The vertices of this fixture are defined relative to local position,
// so we'll have to add them to this and then use the matrix to put them back in world position.
var localPos = xform.LocalPosition;
// If "Transforms" ever get deprecated go ahead and check how DebugPHysicsSystem is drawing chains in this hellworld future
var transform = _physics.GetPhysicsTransform(uid);
for (int i = 1; i < chain.Count; i++)
{
// top left corner
var leftVertex = VertexToWorldPos(chain.Vertices[i - 1], transform);
// top right corner
var rightVertex = VertexToWorldPos(chain.Vertices[i], transform);
// bottom left corner
var leftCorner = Corner(localPos, leftVertex, transform);
// bottom right corner
var rightCorner = Corner(localPos, rightVertex, transform);
// Assemble 2 triangles.
// Triangle one: top left, top right, bottom left
verts.Add(new DrawVertexUV2D(leftVertex, new Vector2(0, 1)));
verts.Add(new DrawVertexUV2D(rightVertex, new Vector2(1, 1)));
verts.Add(new DrawVertexUV2D(leftCorner, Vector2.Zero));
// Triangle two: top right, bottom left, bottom right
verts.Add(new DrawVertexUV2D(rightVertex, new Vector2(1, 1)));
verts.Add(new DrawVertexUV2D(leftCorner, Vector2.Zero));
verts.Add(new DrawVertexUV2D(rightCorner, new Vector2(1, 0)));
}
handle.DrawPrimitives(DrawPrimitiveTopology.TriangleList, texture: tex, CollectionsMarshal.AsSpan(verts), color);
}
private static Vector2 VertexToWorldPos(Vector2 vertexPos, Transform transform)
{
return Transform.Mul(transform, vertexPos);
}
private static Vector2 Corner(Vector2 localPos, Vector2 vertexPos, Transform transform, float radius = 1.3f)
{
var localXform = Transform.Mul(transform, localPos);
var cornerPos = Vector2.Subtract(vertexPos, localXform);
cornerPos.Normalize();
cornerPos *= radius;
return Vector2.Subtract(vertexPos, cornerPos);
}
}