Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add map trail glow #101

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 12 additions & 6 deletions Entity/StandardTrail.MiniMap.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,7 @@ public partial class StandardTrail {
bool inBounds = false;

if (lastPointInBounds | (inBounds = bounds.Contains(nextPoint))) {
float drawOpacity = opacity;

if (_packState.UserConfiguration.MapFadeVerticallyDistantTrailSegments.Value) {
float averageVert = (trailSection[i].Z + trailSection[i + 1].Z) / 2f;
drawOpacity *= MathHelper.Clamp(1f - Math.Abs(averageVert - GameService.Gw2Mumble.PlayerCharacter.Position.Z) * 0.005f, 0.15f, 1f);
}
float drawOpacity = HeightCorrectOpacity(trailSection[i], trailSection[i + 1], opacity);

float distance = Vector2.Distance(thisPoint, nextPoint);
float angle = (float)Math.Atan2(nextPoint.Y - thisPoint.Y, nextPoint.X - thisPoint.X);
Expand All @@ -46,10 +41,21 @@ public partial class StandardTrail {
lastPointInBounds = inBounds;
}
}

if (_packState.UserConfiguration.MapTrailGlowBeadSpacing.Value > 5) {
RenderGlow(spriteBatch, bounds, offsetX, offsetY, scale, isMapOpen);
}

return null;
}

private float HeightCorrectOpacity(Vector3 current, Vector3 next, float opacity) {
if (!_packState.UserConfiguration.MapFadeVerticallyDistantTrailSegments.Value) return opacity;

float averageVert = (current.Z + next.Z) / 2f;
return opacity * MathHelper.Clamp(1f - Math.Abs(averageVert - GameService.Gw2Mumble.PlayerCharacter.Position.Z) * 0.005f, 0.15f, 1f);
}

private void DrawLine(SpriteBatch spriteBatch, Vector2 position, float angle, float distance, Color color, float thickness) {
spriteBatch.Draw(ContentService.Textures.Pixel,
position,
Expand Down
7 changes: 6 additions & 1 deletion Entity/StandardTrail.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ private void Populate(AttributeCollection collection, TextureResourceManager res
// Editor Specific
Populate_EditTag(collection, resourceManager);
}

private void Initialize(ITrail trail) {
var trailSections = new List<Vector3[]>(trail.TrailSections.Count());
foreach (var trailSection in trail.TrailSections) {
Expand All @@ -51,6 +51,11 @@ private void Initialize(ITrail trail) {
Populate(trail.GetAggregatedAttributes(), TextureResourceManager.GetTextureResourceManager(trail.ResourceManager));

BuildBuffers(trail);

UpdateMapGlowOpacity(_packState.UserConfiguration.MapDrawOpacity.Value);
UpdateMiniMapGlowOpacity(_packState.UserConfiguration.MiniMapDrawOpacity.Value);
_packState.UserConfiguration.MapDrawOpacity.SettingChanged += (_, args) => UpdateMapGlowOpacity(args.NewValue);
_packState.UserConfiguration.MiniMapDrawOpacity.SettingChanged += (_, args) => UpdateMiniMapGlowOpacity(args.NewValue);

this.FadeIn();
}
Expand Down
119 changes: 119 additions & 0 deletions Entity/StandardTrail[glow].cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
using System;
using System.Collections.Generic;
using Blish_HUD;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace BhModule.Community.Pathing.Entity;

#nullable enable
public partial class StandardTrail {
public const float MaxGlowLength = 1.5f;


private float? _distance = null;
public float Distance {
get {
if (_distance is not null) return _distance.Value;

float distance = 0;
foreach (Vector3[] section in _sectionPoints) {
for (int i = 0; i < section.Length - 1; i++) {
distance += Vector3.Distance(section[i], section[i + 1]);
}
}
_distance = distance;
return distance;
}
}

private Vector3[] GenerateGlowPoints(float resolution) {
var points = new List<Vector3>();
points.Add(_sectionPoints[0][0]);
foreach (Vector3[] section in _sectionPoints) {
for (int i = 0; i < section.Length - 1; i++) {
var current = section[i];
var next = section[i + 1];
float distance = Vector3.Distance(current, next);
if (distance <= resolution) {
points.Add(next);
continue;
}
// Split segment
var segment = (current - next) / distance;
int splits = (int) Math.Floor(distance / resolution);
segment *= resolution;
for (int j = 0; j < splits; j++) {
points.Add(current -= segment);
}
points.Add(next);
}
}

return points.ToArray();
}

private float? _lastGlowResolution = null;
private int? _lastGlowBeadSpacing = null;
private int _glowBeadCount = 0;
private Vector3[]? _glowPoints = null;

private float _glowSpeed => _packState.UserConfiguration.MapTrailGlowSpeed.Value;
private int _glowBeadSpacing => _packState.UserConfiguration.MapTrailGlowBeadSpacing.Value;

private void RenderGlow(SpriteBatch spriteBatch, Rectangle bounds, double offsetX, double offsetY, double scale, bool mapOpen) {

if (_glowPoints is null || _lastGlowResolution != MaxGlowLength) {
this._lastGlowResolution = MaxGlowLength;
this._glowPoints = GenerateGlowPoints(MaxGlowLength);
this._lastGlowBeadSpacing = null; // regenerate bead spacing
}
if (_lastGlowBeadSpacing == null || _lastGlowBeadSpacing != this._glowBeadSpacing) {
this._lastGlowBeadSpacing = this._glowBeadSpacing;
this._glowBeadCount = this._glowPoints.Length / this._glowBeadSpacing;
}

int globalFrame = (int) Math.Floor((GameService.Overlay.CurrentGameTime.TotalGameTime.TotalSeconds * _glowSpeed) % this._glowBeadSpacing);

for (int i = 0; i < _glowBeadCount; i++) {
int relativeFrame = (i * this._glowBeadSpacing) + globalFrame;
try {
RenderGlowBead(spriteBatch, bounds, offsetX, offsetY, scale, relativeFrame, mapOpen);
} catch (IndexOutOfRangeException) {
break; // since relativeFrame will increase with each iteration, if it goes over we know all future iterations will go over too.
}
}
}

private float _glowBeadMapOpacity = 1f;
private float _glowBeadMinimapOpacity = 1f;

private void RenderGlowBead(SpriteBatch spriteBatch, Rectangle bounds, double offsetX, double offsetY, double scale, int frame, bool mapOpen) {
var current = _glowPoints![frame];
var next = _glowPoints![frame + 1];
var currentScaled = GetScaledLocation(current.X, current.Y, scale, offsetX, offsetY);
var nextScaled = GetScaledLocation(next.X, next.Y, scale, offsetX, offsetY);

if (!bounds.Contains(currentScaled) && !bounds.Contains(nextScaled)) {
return;
}
if (Vector3.Distance(current, next) > MaxGlowLength + 1) {
return;
}

float distance = Vector2.Distance(currentScaled, nextScaled);
float angle = (float) Math.Atan2(nextScaled.Y - currentScaled.Y, nextScaled.X - currentScaled.X);
float opacity = HeightCorrectOpacity(current, next, mapOpen ? _glowBeadMapOpacity : _glowBeadMinimapOpacity);

DrawLine(spriteBatch, currentScaled, angle, distance, _glowBeadColor * opacity, _packState.UserConfiguration.MapTrailWidth.Value);
}

private void UpdateMapGlowOpacity(float newMapOpacity) {
_glowBeadMapOpacity = MathHelper.Clamp(newMapOpacity * _packState.UserResourceStates.Advanced.GlowTrailOpacityPercent, 0f, 1f);
}

private void UpdateMiniMapGlowOpacity(float newMiniMapOpacity) {
_glowBeadMinimapOpacity = MathHelper.Clamp(newMiniMapOpacity * _packState.UserResourceStates.Advanced.GlowTrailOpacityPercent, 0f, 1f);
}

}
16 changes: 15 additions & 1 deletion Entity/StandardTrail[texture].cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,21 @@ public AsyncTexture2D Texture {
}
}

public Color TrailSampleColor { get; set; } = Color.White;
private Color _trailSampleColor = Color.White;
private Color _glowBeadColor = Color.Black;
public Color TrailSampleColor {
get => _trailSampleColor;
set {
_trailSampleColor = value;
// A way to theoretically change it to white or black based off of color brightness. Didn't get it to work well so I switched to color inversion.
// Leaving this here in case someone wants to fix it up since color inversion isn't the best.
// Note you'll also have to uncomment GlowTrailColorBiasPercentage in AdvancedDefaults too
//float luma = 0.2126f * value.R + 0.7152f * value.G + 0.0722f * value.B; // result is 0-255
//var bias = luma > 128 ? Color.Black : Color.White;
//_glowBeadColor = Color.Lerp(value, bias, _packState.UserResourceStates.Advanced.GlowTrailColorBiasPercent);
_glowBeadColor = new Color(255 - value.R, 255 - value.G, 255 - value.B);
}
}

/// <summary>
/// texture
Expand Down
31 changes: 19 additions & 12 deletions ModuleSettings.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Runtime.CompilerServices;
using BhModule.Community.Pathing.Entity;
using Blish_HUD.Input;
using Blish_HUD.Settings;
using Microsoft.Xna.Framework.Input;
Expand Down Expand Up @@ -134,27 +135,33 @@ private void InitPackSettings(SettingCollection settings) {
public SettingEntry<bool> MapFadeVerticallyDistantTrailSegments { get; private set; }
public SettingEntry<float> MapTrailWidth { get; private set; }
public SettingEntry<bool> MapShowTooltip { get; private set; }
public SettingEntry<int> MapTrailGlowBeadSpacing { get; private set; }
public SettingEntry<int> MapTrailGlowSpeed { get; private set; }

private void InitMapSettings(SettingCollection settings) {
this.MapSettings = settings.AddSubCollection(MAP_SETTINGS);

// TODO: Add string to strings.resx for localization.
// TODO: Add description to settings.
this.MapPathablesEnabled = this.MapSettings.DefineSetting(nameof(this.MapPathablesEnabled), true, () => "Show Markers on Maps");
this.MapMarkerVisibilityLevel = this.MapSettings.DefineSetting(nameof(this.MapMarkerVisibilityLevel), MapVisibilityLevel.Default, () => Strings.Setting_MapShowMarkersOnFullscreen, () => "");
this.MapTrailVisibilityLevel = this.MapSettings.DefineSetting(nameof(this.MapTrailVisibilityLevel), MapVisibilityLevel.Default, () => Strings.Setting_MapShowTrailsOnFullscreen, () => "");
this.MapDrawOpacity = this.MapSettings.DefineSetting(nameof(this.MapDrawOpacity), 1f, () => "Opacity on Fullscreen Map", () => "");
this.MiniMapMarkerVisibilityLevel = this.MapSettings.DefineSetting(nameof(this.MiniMapMarkerVisibilityLevel), MapVisibilityLevel.Default, () => Strings.Setting_MapShowMarkersOnCompass, () => "");
this.MiniMapTrailVisibilityLevel = this.MapSettings.DefineSetting(nameof(this.MiniMapTrailVisibilityLevel), MapVisibilityLevel.Default, () => Strings.Setting_MapShowTrailsOnCompass, () => "");
this.MiniMapDrawOpacity = this.MapSettings.DefineSetting(nameof(this.MiniMapDrawOpacity), 1f, () => "Opacity on the Minimap", () => "");
this.MapShowAboveBelowIndicators = this.MapSettings.DefineSetting(nameof(this.MapShowAboveBelowIndicators), true, () => Strings.Setting_MapShowAboveBelowIndicators, () => "");
this.MapFadeVerticallyDistantTrailSegments = this.MapSettings.DefineSetting(nameof(this.MapFadeVerticallyDistantTrailSegments), true, () => "Fade Trail Segments Which Are High Above or Below", () => "");
this.MapShowTooltip = this.MapSettings.DefineSetting(nameof(this.MapShowTooltip), true, () => "Show Tooltips on Map", () => "If enabled, tooltips will be shown on the map when the cursor is over a marker.");
this.MapTrailWidth = this.MapSettings.DefineSetting(nameof(this.MapTrailWidth), 2f, () => "Trail Width on Maps", () => "The thickness of trails shown on the map.");

this.MapPathablesEnabled = this.MapSettings.DefineSetting(nameof(this.MapPathablesEnabled), true, () => "Show Markers on Maps");
this.MapMarkerVisibilityLevel = this.MapSettings.DefineSetting(nameof(this.MapMarkerVisibilityLevel), MapVisibilityLevel.Default, () => Strings.Setting_MapShowMarkersOnFullscreen, () => "");
this.MapTrailVisibilityLevel = this.MapSettings.DefineSetting(nameof(this.MapTrailVisibilityLevel), MapVisibilityLevel.Default, () => Strings.Setting_MapShowTrailsOnFullscreen, () => "");
this.MapDrawOpacity = this.MapSettings.DefineSetting(nameof(this.MapDrawOpacity), 1f, () => "Opacity on Fullscreen Map", () => "");
this.MiniMapMarkerVisibilityLevel = this.MapSettings.DefineSetting(nameof(this.MiniMapMarkerVisibilityLevel), MapVisibilityLevel.Default, () => Strings.Setting_MapShowMarkersOnCompass, () => "");
this.MiniMapTrailVisibilityLevel = this.MapSettings.DefineSetting(nameof(this.MiniMapTrailVisibilityLevel), MapVisibilityLevel.Default, () => Strings.Setting_MapShowTrailsOnCompass, () => "");
this.MiniMapDrawOpacity = this.MapSettings.DefineSetting(nameof(this.MiniMapDrawOpacity), 1f, () => "Opacity on the Minimap", () => "");
this.MapShowAboveBelowIndicators = this.MapSettings.DefineSetting(nameof(this.MapShowAboveBelowIndicators), true, () => Strings.Setting_MapShowAboveBelowIndicators, () => "");
this.MapFadeVerticallyDistantTrailSegments = this.MapSettings.DefineSetting(nameof(this.MapFadeVerticallyDistantTrailSegments), true, () => "Fade Trail Segments Which Are High Above or Below", () => "");
this.MapShowTooltip = this.MapSettings.DefineSetting(nameof(this.MapShowTooltip), true, () => "Show Tooltips on Map", () => "If enabled, tooltips will be shown on the map when the cursor is over a marker.");
this.MapTrailWidth = this.MapSettings.DefineSetting(nameof(this.MapTrailWidth), 2f, () => "Trail Width on Maps", () => "The thickness of trails shown on the map.");
this.MapTrailGlowBeadSpacing = this.MapSettings.DefineSetting(nameof(this.MapTrailGlowBeadSpacing), 0, () => "Trail Glow Bead Distance", () => "How far apart glow beads should be");
this.MapTrailGlowSpeed = this.MapSettings.DefineSetting(nameof(this.MapTrailGlowSpeed), 20, () => "Trail Glow Speed", () => "The speed at which the glow moves along the trail");

this.MapDrawOpacity.SetRange(0f, 1f);
this.MiniMapDrawOpacity.SetRange(0f, 1f);
this.MapTrailWidth.SetRange(0.5f, 4.5f);
this.MapTrailGlowBeadSpacing.SetRange(5, 80);
this.MapTrailGlowSpeed.SetRange(3, 50);
}

#endregion
Expand Down
4 changes: 4 additions & 0 deletions Pathing.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<GenerateResourceUsePreserializedResources>true</GenerateResourceUsePreserializedResources>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{B5DE694A-0648-4A39-8349-8C0BB0DD538C}</ProjectGuid>
Expand Down Expand Up @@ -180,6 +181,9 @@
<Compile Include="Entity\StandardTrail[fadenear,fadefar].cs">
<DependentUpon>StandardTrail.cs</DependentUpon>
</Compile>
<Compile Include="Entity\StandardTrail[glow].cs">
<DependentUpon>StandardTrail.cs</DependentUpon>
</Compile>
<Compile Include="Entity\StandardTrail[guid].cs" />
<Compile Include="Entity\StandardTrail[minimapvisibility,mapvisibility,ingamevisibility].cs">
<DependentUpon>StandardTrail.cs</DependentUpon>
Expand Down
1 change: 1 addition & 0 deletions Pathing.sln.DotSettings
Original file line number Diff line number Diff line change
Expand Up @@ -1231,6 +1231,7 @@ System.Threading.Tasks.Task.ConfigureAwait</s:String>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpKeepExistingMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpPlaceEmbeddedOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpUseContinuousIndentInsideBracesMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002EMemberReordering_002EMigrations_002ECSharpFileLayoutPatternRemoveIsAttributeUpgrade/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EAlwaysTreatStructAsNotReorderableMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EPredefinedNamingRulesToUserRulesUpgrade/@EntryIndexedValue">True</s:Boolean>
Expand Down
6 changes: 6 additions & 0 deletions State/UserResources/AdvancedDefaults.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,12 @@ public class AdvancedDefaults {
// Trails
[YamlMember(Description = "A multiplier which changes the fade radius around the character.")]
public float CharacterTrailFadeMultiplier { get; set; } = 1f;

// Glow
[YamlMember(Description = "The percentage of normal opacity that a glow bead is")]
public float GlowTrailOpacityPercent { get; set; } = 2f;

//[YamlMember(Description = "The percentage of color bias to apply to a glow bead")]
//public float GlowTrailColorBiasPercent { get; set; } = 0.5f;
}
}