public void Render(IGameViewport viewport, LocAndOffsets location, ITexture texture)
    {
        var screenPos = viewport.WorldToScreen(location.ToInches3D());

        var contentRect = texture.GetContentRect();
        var renderArgs  = new Render2dArgs
        {
            srcRect  = contentRect,
            flags    = Render2dFlag.BUFFERTEXTURE,
            destRect = new Rectangle(
                (int)(screenPos.X - contentRect.Width / 2),
                (int)(screenPos.Y - contentRect.Height / 2),
                contentRect.Width,
                contentRect.Height
                ),
            customTexture = texture
        };

        Tig.ShapeRenderer2d.DrawRectangle(ref renderArgs);
    }
    public void Render(IGameViewport viewport, LocAndOffsets loc, LocAndOffsets tgtLoc,
                       float degreesTarget,
                       IMdfRenderMaterial materialInside,
                       IMdfRenderMaterial materialOutside)
    {
        Span <IntgameVertex> vertices = stackalloc IntgameVertex[38];

        var elevation      = MathF.Sin(-0.77539754f) * -1.5f;
        var outerConeAngle = Angles.ToRadians(degreesTarget);

        var originPos = loc.ToInches3D();

        var targetPos = tgtLoc.ToInches3D();

        var d          = targetPos - originPos;
        var coneRadius = d.Length();
        // The normal pointing in the direction of the target straight down the middle of the cone
        var coneNormal = d / coneRadius;

        // A portion of the full cone will be rendered as a "rim" on the outside, which
        // will have this radius:
        var ringRadius = MathF.Min(24.0f, coneRadius / 7.0f);

        var innerConeRadius = coneRadius - ringRadius;

        // Set the origin point
        vertices[0].pos     = new Vector4(originPos.X, elevation, originPos.Z, 1);
        vertices[0].normal  = Vector4.UnitY;
        vertices[0].uv      = new Vector2(0, 0);
        vertices[0].diffuse = PackedLinearColorA.White;

        var   innerConeAngle     = (1.0f - (ringRadius + ringRadius) / (outerConeAngle * coneRadius)) * outerConeAngle;
        var   innerConeAngleHalf = innerConeAngle * 0.5f;
        float angleStepInner     = innerConeAngle / 18;

        // This is the point at the center of the cone, but on the inner rim
        var coneNearX = innerConeRadius * coneNormal.X;
        var coneNearY = innerConeRadius * coneNormal.Z;

        for (var i = 1; i < 20; i++)
        {
            // angle=0 is straight down the center of the cone, so it is shifted to the left by coneAngle/2
            var angle = (i - 1) * angleStepInner - innerConeAngleHalf;
            vertices[i].pos = new Vector4(
                originPos.X + MathF.Cos(angle) * coneNearX - MathF.Sin(angle) * coneNearY,
                elevation,
                originPos.Z + MathF.Sin(angle) * coneNearX + MathF.Cos(angle) * coneNearY,
                1
                );

            vertices[i].normal  = Vector4.UnitY;
            vertices[i].diffuse = PackedLinearColorA.White;
            vertices[i].uv      = new Vector2(
                (i + 1) % 2,
                1.0f
                );
        }

        _fanVertexBuffer.Resource.Update <IntgameVertex>(vertices.Slice(0, 20));
        _fanBufferBinding.Resource.Bind();
        _device.SetIndexBuffer(_fanIndexBuffer);
        materialInside.Bind(viewport, _device, new List <Light3d>());
        _device.DrawIndexed(PrimitiveType.TriangleList, 20, FanIndices.Length);

        var slice = 0.0f;
        // Far center point of the cone, on the outside rim
        var coneFarX = coneRadius * coneNormal.X;
        var coneFarY = coneRadius * coneNormal.Z;

        for (var i = 0; i < 38; i += 2)
        {
            var angle = slice * angleStepInner - innerConeAngleHalf;

            vertices[i].pos = new Vector4(
                originPos.X + MathF.Cos(angle) * coneNearX - MathF.Sin(angle) * coneNearY,
                elevation,
                originPos.Z + MathF.Sin(angle) * coneNearX + MathF.Cos(angle) * coneNearY,
                1
                );
            vertices[i].normal  = Vector4.UnitY;
            vertices[i].uv      = new Vector2(slice, 0);
            vertices[i].diffuse = PackedLinearColorA.White;

            vertices[i + 1].pos = new Vector4(
                originPos.X + MathF.Cos(angle) * coneFarX - MathF.Sin(angle) * coneFarY,
                elevation,
                originPos.Z + MathF.Cos(angle) * coneFarY + MathF.Sin(angle) * coneFarX,
                1
                );
            vertices[i + 1].normal  = Vector4.UnitY;
            vertices[i + 1].uv      = new Vector2(slice, 1);
            vertices[i + 1].diffuse = PackedLinearColorA.White;

            slice += 1;
        }

        _ringVertexBuffer.Resource.Update <IntgameVertex>(vertices.Slice(0, 38));
        _ringBufferBinding.Resource.Bind();
        _device.SetIndexBuffer(_ringIndexBuffer);
        materialOutside.Bind(viewport, _device, new List <Light3d>());
        _device.DrawIndexed(PrimitiveType.TriangleList, 38, RingIndices.Length);

        // Render the left and right side of the cone using the same texture as the outside ring

        var innerConeAngleHalfInv = -innerConeAngleHalf;
        var outerConeAngleHalf    = outerConeAngle * 0.5f;
        var outerConeAngleHalfInv = -outerConeAngleHalf;
        var v71 = innerConeRadius / ringRadius;

        // Right flank of the cone
        vertices[0] = new IntgameVertex
        {
            pos = new Vector4(
                originPos.X + MathF.Cos(innerConeAngleHalfInv) * coneFarX - MathF.Sin(innerConeAngleHalfInv) * coneFarY,
                elevation,
                originPos.Z + MathF.Sin(innerConeAngleHalfInv) * coneFarX + MathF.Cos(innerConeAngleHalfInv) * coneFarY,
                1
                ),
            normal  = Vector4.UnitY,
            uv      = new Vector2(0, 1),
            diffuse = PackedLinearColorA.White
        };
        vertices[1] = new IntgameVertex
        {
            pos = new Vector4(
                originPos.X + MathF.Cos(outerConeAngleHalfInv) * coneFarX - MathF.Sin(outerConeAngleHalfInv) * coneFarY,
                elevation,
                originPos.Z + MathF.Sin(outerConeAngleHalfInv) * coneFarX + MathF.Cos(outerConeAngleHalfInv) * coneFarY,
                1
                ),
            normal  = Vector4.UnitY,
            uv      = new Vector2(0, 1),
            diffuse = PackedLinearColorA.White
        };
        vertices[2] = new IntgameVertex
        {
            pos = new Vector4(
                originPos.X + MathF.Cos(innerConeAngleHalfInv) * coneNearX - MathF.Sin(innerConeAngleHalfInv) * coneNearY,
                elevation,
                originPos.Z + MathF.Sin(innerConeAngleHalfInv) * coneNearX + MathF.Cos(innerConeAngleHalfInv) * coneNearY,
                1
                ),
            normal  = Vector4.UnitY,
            uv      = new Vector2(0, 0),
            diffuse = PackedLinearColorA.White
        };
        vertices[3] = new IntgameVertex
        {
            pos = new Vector4(
                originPos.X + MathF.Cos(outerConeAngleHalfInv) * coneNearX - MathF.Sin(outerConeAngleHalfInv) * coneNearY,
                elevation,
                originPos.Z + MathF.Sin(outerConeAngleHalfInv) * coneNearX + MathF.Cos(outerConeAngleHalfInv) * coneNearY,
                1
                ),
            normal  = Vector4.UnitY,
            uv      = new Vector2(0, 1),
            diffuse = PackedLinearColorA.White
        };
        vertices[4] = new IntgameVertex
        {
            pos = new Vector4(
                originPos.X,
                elevation,
                originPos.Z,
                1
                ),
            normal  = Vector4.UnitY,
            uv      = new Vector2(-v71, 0.5f),
            diffuse = PackedLinearColorA.White
        };

        // Left flank of the cone
        vertices[5] = new IntgameVertex
        {
            pos = new Vector4(
                originPos.X + MathF.Cos(innerConeAngleHalf) * coneFarX - MathF.Sin(innerConeAngleHalf) * coneFarY,
                elevation,
                originPos.Z + MathF.Sin(innerConeAngleHalf) * coneFarX + MathF.Cos(innerConeAngleHalf) * coneFarY,
                1
                ),
            normal  = Vector4.UnitY,
            uv      = new Vector2(0, 1),
            diffuse = PackedLinearColorA.White
        };
        vertices[6] = new IntgameVertex
        {
            pos = new Vector4(
                originPos.X + MathF.Cos(outerConeAngleHalf) * coneFarX - MathF.Sin(outerConeAngleHalf) * coneFarY,
                elevation,
                originPos.Z + MathF.Sin(outerConeAngleHalf) * coneFarX + MathF.Cos(outerConeAngleHalf) * coneFarY,
                1
                ),
            normal  = Vector4.UnitY,
            uv      = new Vector2(0, 1),
            diffuse = PackedLinearColorA.White
        };
        vertices[7] = new IntgameVertex
        {
            pos = new Vector4(
                originPos.X + MathF.Cos(innerConeAngleHalf) * coneNearX - MathF.Sin(innerConeAngleHalf) * coneNearY,
                elevation,
                originPos.Z + MathF.Sin(innerConeAngleHalf) * coneNearX + MathF.Cos(innerConeAngleHalf) * coneNearY,
                1
                ),
            normal  = Vector4.UnitY,
            uv      = new Vector2(0, 0),
            diffuse = PackedLinearColorA.White
        };
        vertices[8] = new IntgameVertex
        {
            pos = new Vector4(
                originPos.X + MathF.Cos(outerConeAngleHalf) * coneNearX - MathF.Sin(outerConeAngleHalf) * coneNearY,
                elevation,
                originPos.Z + MathF.Sin(outerConeAngleHalf) * coneNearX + MathF.Cos(outerConeAngleHalf) * coneNearY,
                1
                ),
            normal  = Vector4.UnitY,
            uv      = new Vector2(0, 1),
            diffuse = PackedLinearColorA.White
        };
        // This could reuse vertices[4], but was here in vanilla also
        vertices[9] = new IntgameVertex
        {
            pos = new Vector4(
                originPos.X,
                elevation,
                originPos.Z,
                1
                ),
            normal  = Vector4.UnitY,
            uv      = new Vector2(v71, 0.5f),
            diffuse = PackedLinearColorA.White
        };

        _flankVertexBuffer.Resource.Update <IntgameVertex>(vertices.Slice(0, 10));
        _flankBufferBinding.Resource.Bind();
        _device.SetIndexBuffer(_flankIndexBuffer);
        materialOutside.Bind(viewport, _device, new List <Light3d>());
        _device.DrawIndexed(PrimitiveType.TriangleList, 10, FlankIndices.Length);
    }
    private LocAndOffsets AverageLocation(LocAndOffsets a, LocAndOffsets b)
    {
        var averaged = (a.ToInches3D() + b.ToInches3D()) / 2;

        return(LocAndOffsets.FromInches(averaged));
    }