Initial HSMappy release (fork of Mappy)
Made-with: Cursor
This commit is contained in:
@@ -0,0 +1,170 @@
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using FFXIVClientStructs.FFXIV.Client.UI.Agent;
|
||||
using FFXIVClientStructs.FFXIV.Client.UI.Arrays;
|
||||
using Mappy.Classes;
|
||||
using Mappy.Extensions;
|
||||
|
||||
namespace Mappy.MapRenderer;
|
||||
|
||||
public partial class MapRenderer
|
||||
{
|
||||
private unsafe void DrawPlayer()
|
||||
{
|
||||
if (AgentMap.Instance()->SelectedMapId != AgentMap.Instance()->CurrentMapId) return;
|
||||
|
||||
if (Service.ObjectTable.LocalPlayer is { } localPlayer) {
|
||||
var position = ImGui.GetWindowPos() +
|
||||
DrawPosition +
|
||||
(localPlayer.GetMapPosition() -
|
||||
DrawHelpers.GetMapOffsetVector() +
|
||||
DrawHelpers.GetMapCenterOffsetVector()) * Scale;
|
||||
|
||||
DrawLookLine(position);
|
||||
DrawPlayerIcon(position);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawLookLine(Vector2 position)
|
||||
{
|
||||
var angle = GetCameraRotation();
|
||||
|
||||
var lineLength = System.SystemConfig.ConeSize * (System.SystemConfig.ScalePlayerCone ? 1.0f : Scale);
|
||||
var halfConeAngle = DegreesToRadians(90.0f) / 2.0f;
|
||||
|
||||
DrawAngledLineFromCenter(position, lineLength, angle - halfConeAngle);
|
||||
DrawAngledLineFromCenter(position, lineLength, angle + halfConeAngle);
|
||||
DrawLineArcFromCenter(position, lineLength, angle);
|
||||
|
||||
DrawFilledSemiCircle(position, lineLength, angle);
|
||||
}
|
||||
|
||||
private static void DrawAngledLineFromCenter(Vector2 center, float lineLength, float angle, Vector4? outlineColor = null)
|
||||
{
|
||||
var lineSegment = new Vector2(lineLength * MathF.Cos(angle), lineLength * MathF.Sin(angle));
|
||||
var color = outlineColor ?? System.SystemConfig.PlayerConeOutlineColor;
|
||||
ImGui.GetWindowDrawList().AddLine(center, center + lineSegment, ImGui.GetColorU32(color), 3.0f);
|
||||
}
|
||||
|
||||
private static void DrawLineArcFromCenter(Vector2 center, float distance, float rotation, Vector4? outlineColor = null)
|
||||
{
|
||||
var halfConeAngle = DegreesToRadians(90.0f) / 2.0f;
|
||||
var color = outlineColor ?? System.SystemConfig.PlayerConeOutlineColor;
|
||||
|
||||
var start = rotation - halfConeAngle;
|
||||
var stop = rotation + halfConeAngle;
|
||||
|
||||
ImGui.GetWindowDrawList().PathArcTo(center, distance, start, stop);
|
||||
ImGui.GetWindowDrawList().PathStroke(ImGui.GetColorU32(color), ImDrawFlags.None, 3.0f);
|
||||
}
|
||||
|
||||
private static void DrawFilledSemiCircle(Vector2 center, float distance, float rotation)
|
||||
{
|
||||
var halfConeAngle = DegreesToRadians(90.0f) / 2.0f;
|
||||
|
||||
var coneColor = ImGui.GetColorU32(System.SystemConfig.PlayerConeColor);
|
||||
var startAngle = rotation - halfConeAngle;
|
||||
var stopAngle = rotation + halfConeAngle;
|
||||
|
||||
var startPosition = new Vector2(distance * MathF.Cos(rotation - halfConeAngle), distance * MathF.Sin(rotation - halfConeAngle));
|
||||
|
||||
ImGui.GetWindowDrawList().PathArcTo(center, distance, startAngle, stopAngle);
|
||||
ImGui.GetWindowDrawList().PathLineTo(center);
|
||||
ImGui.GetWindowDrawList().PathLineTo(center + startPosition);
|
||||
ImGui.GetWindowDrawList().PathFillConvex(coneColor);
|
||||
}
|
||||
|
||||
private static unsafe float GetCameraRotation() => -DegreesToRadians(AreaMapNumberArray.Instance()->ConeRotation) - 0.5f * MathF.PI;
|
||||
|
||||
private static float DegreesToRadians(float degrees) => MathF.PI / 180.0f * degrees;
|
||||
|
||||
private void DrawPlayerIcon(Vector2 position)
|
||||
{
|
||||
if (!System.SystemConfig.ShowPlayerIcon) return;
|
||||
if (Service.ObjectTable is not { LocalPlayer: { } player }) return;
|
||||
|
||||
var texture = Service.TextureProvider.GetFromGameIcon(60443).GetWrapOrEmpty();
|
||||
var angle = -player.Rotation + MathF.PI / 2.0f;
|
||||
|
||||
var scale = System.SystemConfig.ScaleWithZoom ? Scale : 1.0f;
|
||||
scale *= System.SystemConfig.PlayerIconScale;
|
||||
|
||||
var vectors = GetRotationVectors(angle, position, texture.Size / 2.0f * scale);
|
||||
|
||||
ImGui.GetWindowDrawList().AddImageQuad(texture.Handle, vectors[0], vectors[1], vectors[2], vectors[3]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draw only the minimap player cone (direction indicator). Call before DrawMinimapMarkers so markers draw on top of the cone.
|
||||
/// </summary>
|
||||
private void DrawMinimapConeAtCenter(Vector2 centerPos, float mapScale)
|
||||
{
|
||||
if (!System.SystemConfig.MinimapShowPlayerCone) return;
|
||||
var angle = GetCameraRotation();
|
||||
var lineLength = System.SystemConfig.ConeSize * 0.5f;
|
||||
var halfConeAngle = DegreesToRadians(90.0f) / 2.0f;
|
||||
DrawMinimapConeGradient(centerPos, lineLength, angle - halfConeAngle, angle + halfConeAngle);
|
||||
var softWhite = new Vector4(1f, 1f, 1f, 0.2f);
|
||||
DrawAngledLineFromCenter(centerPos, lineLength, angle - halfConeAngle, softWhite);
|
||||
DrawAngledLineFromCenter(centerPos, lineLength, angle + halfConeAngle, softWhite);
|
||||
DrawLineArcFromCenter(centerPos, lineLength, angle, softWhite);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draw player icon at center (for minimap). Cone is drawn earlier so markers can be drawn on top of it.
|
||||
/// </summary>
|
||||
private void DrawPlayerAtCenter(Vector2 centerPos, float mapScale)
|
||||
{
|
||||
if (Service.ObjectTable.LocalPlayer is not { } localPlayer) return;
|
||||
if (!System.SystemConfig.ShowPlayerIcon) return;
|
||||
|
||||
var texture = Service.TextureProvider.GetFromGameIcon(60443).GetWrapOrEmpty();
|
||||
var angle = -localPlayer.Rotation + MathF.PI / 2.0f;
|
||||
var iconScale = System.SystemConfig.PlayerIconScale * 1.5f; // 1.5x for minimap visibility
|
||||
var vectors = GetRotationVectors(angle, centerPos, texture.Size / 2.0f * iconScale);
|
||||
ImGui.GetWindowDrawList().AddImageQuad(texture.Handle, vectors[0], vectors[1], vectors[2], vectors[3]);
|
||||
}
|
||||
|
||||
/// <summary>Draw minimap cone as white light with radial gradient (bright at center, fading at edge). Kept quite transparent so markers underneath remain visible.</summary>
|
||||
private static void DrawMinimapConeGradient(Vector2 center, float radius, float startAngle, float endAngle)
|
||||
{
|
||||
const int segments = 24;
|
||||
const float maxAlpha = 0.18f;
|
||||
var drawList = ImGui.GetWindowDrawList();
|
||||
for (var j = segments - 1; j >= 0; j--) {
|
||||
var rInner = radius * j / segments;
|
||||
var rOuter = radius * (j + 1) / segments;
|
||||
var t = (j + 0.5f) / segments;
|
||||
var alpha = maxAlpha * (1f - t);
|
||||
if (alpha <= 0f) continue;
|
||||
var color = ImGui.GetColorU32(new Vector4(1f, 1f, 1f, alpha));
|
||||
var outerStart = center + new Vector2(rOuter * MathF.Cos(startAngle), rOuter * MathF.Sin(startAngle));
|
||||
var innerEnd = center + new Vector2(rInner * MathF.Cos(endAngle), rInner * MathF.Sin(endAngle));
|
||||
drawList.PathClear();
|
||||
drawList.PathLineTo(center);
|
||||
drawList.PathLineTo(outerStart);
|
||||
drawList.PathArcTo(center, rOuter, startAngle, endAngle);
|
||||
drawList.PathLineTo(innerEnd);
|
||||
drawList.PathArcTo(center, rInner, endAngle, startAngle);
|
||||
drawList.PathFillConvex(color);
|
||||
}
|
||||
}
|
||||
|
||||
private static Vector2[] GetRotationVectors(float angle, Vector2 center, Vector2 size)
|
||||
{
|
||||
var cosA = MathF.Cos(angle + 0.5f * MathF.PI);
|
||||
var sinA = MathF.Sin(angle + 0.5f * MathF.PI);
|
||||
|
||||
Vector2[] vectors =
|
||||
[
|
||||
center + ImRotate(new Vector2(-size.X * 0.5f, -size.Y * 0.5f), cosA, sinA),
|
||||
center + ImRotate(new Vector2(+size.X * 0.5f, -size.Y * 0.5f), cosA, sinA),
|
||||
center + ImRotate(new Vector2(+size.X * 0.5f, +size.Y * 0.5f), cosA, sinA),
|
||||
center + ImRotate(new Vector2(-size.X * 0.5f, +size.Y * 0.5f), cosA, sinA),
|
||||
];
|
||||
return vectors;
|
||||
}
|
||||
|
||||
private static Vector2 ImRotate(Vector2 v, float cosA, float sinA) => new(v.X * cosA - v.Y * sinA, v.X * sinA + v.Y * cosA);
|
||||
}
|
||||
Reference in New Issue
Block a user