492 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			492 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| using Dalamud.Interface;
 | |
| using Dalamud.Interface.Colors;
 | |
| using Dalamud.Interface.Utility.Raii;
 | |
| using ImGuiNET;
 | |
| using MareSynchronos.API.Data.Enum;
 | |
| using MareSynchronos.Interop.Ipc;
 | |
| using MareSynchronos.Services;
 | |
| using MareSynchronos.Services.Mediator;
 | |
| using MareSynchronos.Utils;
 | |
| using Microsoft.Extensions.Logging;
 | |
| using System.Numerics;
 | |
| 
 | |
| namespace MareSynchronos.UI;
 | |
| 
 | |
| public class DataAnalysisUi : WindowMediatorSubscriberBase
 | |
| {
 | |
|     private readonly CharacterAnalyzer _characterAnalyzer;
 | |
|     private readonly Progress<(string, int)> _conversionProgress = new();
 | |
|     private readonly IpcManager _ipcManager;
 | |
|     private readonly UiSharedService _uiSharedService;
 | |
|     private readonly Dictionary<string, string[]> _texturesToConvert = new(StringComparer.Ordinal);
 | |
|     private Dictionary<ObjectKind, Dictionary<string, CharacterAnalyzer.FileDataEntry>>? _cachedAnalysis;
 | |
|     private CancellationTokenSource _conversionCancellationTokenSource = new();
 | |
|     private string _conversionCurrentFileName = string.Empty;
 | |
|     private int _conversionCurrentFileProgress = 0;
 | |
|     private Task? _conversionTask;
 | |
|     private bool _enableBc7ConversionMode = false;
 | |
|     private bool _hasUpdate = false;
 | |
|     private bool _sortDirty = true;
 | |
|     private bool _modalOpen = false;
 | |
|     private string _selectedFileTypeTab = string.Empty;
 | |
|     private string _selectedHash = string.Empty;
 | |
|     private ObjectKind _selectedObjectTab;
 | |
|     private bool _showModal = false;
 | |
| 
 | |
|     public DataAnalysisUi(ILogger<DataAnalysisUi> logger, MareMediator mediator,
 | |
|         CharacterAnalyzer characterAnalyzer, IpcManager ipcManager,
 | |
|         PerformanceCollectorService performanceCollectorService,
 | |
|         UiSharedService uiSharedService)
 | |
|         : base(logger, mediator, "Character Data Analysis", performanceCollectorService)
 | |
|     {
 | |
|         _characterAnalyzer = characterAnalyzer;
 | |
|         _ipcManager = ipcManager;
 | |
|         _uiSharedService = uiSharedService;
 | |
|         Mediator.Subscribe<CharacterDataAnalyzedMessage>(this, (_) =>
 | |
|         {
 | |
|             _hasUpdate = true;
 | |
|         });
 | |
|         SizeConstraints = new()
 | |
|         {
 | |
|             MinimumSize = new()
 | |
|             {
 | |
|                 X = 800,
 | |
|                 Y = 600
 | |
|             },
 | |
|             MaximumSize = new()
 | |
|             {
 | |
|                 X = 3840,
 | |
|                 Y = 2160
 | |
|             }
 | |
|         };
 | |
| 
 | |
|         _conversionProgress.ProgressChanged += ConversionProgress_ProgressChanged;
 | |
|     }
 | |
| 
 | |
|     protected override void DrawInternal()
 | |
|     {
 | |
|         if (_conversionTask != null && !_conversionTask.IsCompleted)
 | |
|         {
 | |
|             _showModal = true;
 | |
|             if (ImGui.BeginPopupModal("BC7 Conversion in Progress"))
 | |
|             {
 | |
|                 ImGui.TextUnformatted("BC7 Conversion in progress: " + _conversionCurrentFileProgress + "/" + _texturesToConvert.Count);
 | |
|                 UiSharedService.TextWrapped("Current file: " + _conversionCurrentFileName);
 | |
|                 if (_uiSharedService.IconTextButton(FontAwesomeIcon.StopCircle, "Cancel conversion"))
 | |
|                 {
 | |
|                     _conversionCancellationTokenSource.Cancel();
 | |
|                 }
 | |
|                 UiSharedService.SetScaledWindowSize(500);
 | |
|                 ImGui.EndPopup();
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 _modalOpen = false;
 | |
|             }
 | |
|         }
 | |
|         else if (_conversionTask != null && _conversionTask.IsCompleted && _texturesToConvert.Count > 0)
 | |
|         {
 | |
|             _conversionTask = null;
 | |
|             _texturesToConvert.Clear();
 | |
|             _showModal = false;
 | |
|             _modalOpen = false;
 | |
|             _enableBc7ConversionMode = false;
 | |
|         }
 | |
| 
 | |
|         if (_showModal && !_modalOpen)
 | |
|         {
 | |
|             ImGui.OpenPopup("BC7 Conversion in Progress");
 | |
|             _modalOpen = true;
 | |
|         }
 | |
| 
 | |
|         if (_hasUpdate)
 | |
|         {
 | |
|             _cachedAnalysis = _characterAnalyzer.LastAnalysis.DeepClone();
 | |
|             _hasUpdate = false;
 | |
|             _sortDirty = true;
 | |
|         }
 | |
| 
 | |
|         UiSharedService.TextWrapped("This window shows you all files and their sizes that are currently in use through your character and associated entities");
 | |
| 
 | |
|         if (_cachedAnalysis == null || _cachedAnalysis.Count == 0) return;
 | |
| 
 | |
|         bool isAnalyzing = _characterAnalyzer.IsAnalysisRunning;
 | |
|         bool needAnalysis = _cachedAnalysis!.Any(c => c.Value.Any(f => !f.Value.IsComputed));
 | |
|         if (isAnalyzing)
 | |
|         {
 | |
|             UiSharedService.ColorTextWrapped($"Analyzing {_characterAnalyzer.CurrentFile}/{_characterAnalyzer.TotalFiles}",
 | |
|                 ImGuiColors.DalamudYellow);
 | |
|             if (_uiSharedService.IconTextButton(FontAwesomeIcon.StopCircle, "Cancel analysis"))
 | |
|             {
 | |
|                 _characterAnalyzer.CancelAnalyze();
 | |
|             }
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             if (needAnalysis)
 | |
|             {
 | |
|                 UiSharedService.ColorTextWrapped("Some entries in the analysis have file size not determined yet, press the button below to analyze your current data",
 | |
|                     ImGuiColors.DalamudYellow);
 | |
|                 if (_uiSharedService.IconTextButton(FontAwesomeIcon.PlayCircle, "Start analysis (missing entries)"))
 | |
|                 {
 | |
|                     _ = _characterAnalyzer.ComputeAnalysis(print: false);
 | |
|                 }
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 if (_uiSharedService.IconTextButton(FontAwesomeIcon.PlayCircle, "Start analysis (recalculate all entries)"))
 | |
|                 {
 | |
|                     _ = _characterAnalyzer.ComputeAnalysis(print: false, recalculate: true);
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         ImGui.Separator();
 | |
| 
 | |
|         ImGui.TextUnformatted("Total files:");
 | |
|         ImGui.SameLine();
 | |
|         ImGui.TextUnformatted(_cachedAnalysis!.Values.Sum(c => c.Values.Count).ToString());
 | |
|         ImGui.SameLine();
 | |
|         using (var font = ImRaii.PushFont(UiBuilder.IconFont))
 | |
|         {
 | |
|             ImGui.TextUnformatted(FontAwesomeIcon.InfoCircle.ToIconString());
 | |
|         }
 | |
|         if (ImGui.IsItemHovered())
 | |
|         {
 | |
|             string text = "";
 | |
|             var groupedfiles = _cachedAnalysis.Values.SelectMany(f => f.Values).GroupBy(f => f.FileType, StringComparer.Ordinal);
 | |
|             text = string.Join(Environment.NewLine, groupedfiles.OrderBy(f => f.Key, StringComparer.Ordinal)
 | |
|                 .Select(f => f.Key + ": " + f.Count() + " files, size: " + UiSharedService.ByteToString(f.Sum(v => v.OriginalSize))
 | |
|                 + ", compressed: " + UiSharedService.ByteToString(f.Sum(v => v.CompressedSize))));
 | |
|             ImGui.SetTooltip(text);
 | |
|         }
 | |
|         ImGui.TextUnformatted("Total size (actual):");
 | |
|         ImGui.SameLine();
 | |
|         ImGui.TextUnformatted(UiSharedService.ByteToString(_cachedAnalysis!.Sum(c => c.Value.Sum(c => c.Value.OriginalSize))));
 | |
|         ImGui.TextUnformatted("Total size (download size):");
 | |
|         ImGui.SameLine();
 | |
|         using (ImRaii.PushColor(ImGuiCol.Text, ImGuiColors.DalamudYellow, needAnalysis))
 | |
|         {
 | |
|             ImGui.TextUnformatted(UiSharedService.ByteToString(_cachedAnalysis!.Sum(c => c.Value.Sum(c => c.Value.CompressedSize))));
 | |
|             if (needAnalysis && !isAnalyzing)
 | |
|             {
 | |
|                 ImGui.SameLine();
 | |
|                 using (ImRaii.PushFont(UiBuilder.IconFont))
 | |
|                     ImGui.TextUnformatted(FontAwesomeIcon.ExclamationCircle.ToIconString());
 | |
|                 UiSharedService.AttachToolTip("Click \"Start analysis\" to calculate download size");
 | |
|             }
 | |
|         }
 | |
|         ImGui.TextUnformatted($"Total modded model triangles: {UiSharedService.TrisToString(_cachedAnalysis.Sum(c => c.Value.Sum(f => f.Value.Triangles)))}");
 | |
|         ImGui.Separator();
 | |
| 
 | |
|         using var tabbar = ImRaii.TabBar("objectSelection");
 | |
|         foreach (var kvp in _cachedAnalysis)
 | |
|         {
 | |
|             using var id = ImRaii.PushId(kvp.Key.ToString());
 | |
|             string tabText = kvp.Key.ToString();
 | |
|             using var tab = ImRaii.TabItem(tabText + "###" + kvp.Key.ToString());
 | |
|             if (tab.Success)
 | |
|             {
 | |
|                 var groupedfiles = kvp.Value.Select(v => v.Value).GroupBy(f => f.FileType, StringComparer.Ordinal)
 | |
|                     .OrderBy(k => k.Key, StringComparer.Ordinal).ToList();
 | |
| 
 | |
|                 ImGui.TextUnformatted("Files for " + kvp.Key);
 | |
|                 ImGui.SameLine();
 | |
|                 ImGui.TextUnformatted(kvp.Value.Count.ToString());
 | |
|                 ImGui.SameLine();
 | |
| 
 | |
|                 using (var font = ImRaii.PushFont(UiBuilder.IconFont))
 | |
|                 {
 | |
|                     ImGui.TextUnformatted(FontAwesomeIcon.InfoCircle.ToIconString());
 | |
|                 }
 | |
|                 if (ImGui.IsItemHovered())
 | |
|                 {
 | |
|                     string text = "";
 | |
|                     text = string.Join(Environment.NewLine, groupedfiles
 | |
|                         .Select(f => f.Key + ": " + f.Count() + " files, size: " + UiSharedService.ByteToString(f.Sum(v => v.OriginalSize))
 | |
|                         + ", compressed: " + UiSharedService.ByteToString(f.Sum(v => v.CompressedSize))));
 | |
|                     ImGui.SetTooltip(text);
 | |
|                 }
 | |
|                 ImGui.TextUnformatted($"{kvp.Key} size (actual):");
 | |
|                 ImGui.SameLine();
 | |
|                 ImGui.TextUnformatted(UiSharedService.ByteToString(kvp.Value.Sum(c => c.Value.OriginalSize)));
 | |
|                 ImGui.TextUnformatted($"{kvp.Key} size (download size):");
 | |
|                 ImGui.SameLine();
 | |
|                 using (ImRaii.PushColor(ImGuiCol.Text, ImGuiColors.DalamudYellow, needAnalysis))
 | |
|                 {
 | |
|                     ImGui.TextUnformatted(UiSharedService.ByteToString(kvp.Value.Sum(c => c.Value.CompressedSize)));
 | |
|                     if (needAnalysis && !isAnalyzing)
 | |
|                     {
 | |
|                         ImGui.SameLine();
 | |
|                         using (ImRaii.PushFont(UiBuilder.IconFont))
 | |
|                             ImGui.TextUnformatted(FontAwesomeIcon.ExclamationCircle.ToIconString());
 | |
|                         UiSharedService.AttachToolTip("Click \"Start analysis\" to calculate download size");
 | |
|                     }
 | |
|                 }
 | |
|                 ImGui.TextUnformatted($"{kvp.Key} VRAM usage:");
 | |
|                 ImGui.SameLine();
 | |
|                 var vramUsage = groupedfiles.SingleOrDefault(v => string.Equals(v.Key, "tex", StringComparison.Ordinal));
 | |
|                 if (vramUsage != null)
 | |
|                 {
 | |
|                     ImGui.TextUnformatted(UiSharedService.ByteToString(vramUsage.Sum(f => f.OriginalSize)));
 | |
|                 }
 | |
|                 ImGui.TextUnformatted($"{kvp.Key} modded model triangles: {UiSharedService.TrisToString(kvp.Value.Sum(f => f.Value.Triangles))}");
 | |
| 
 | |
|                 ImGui.Separator();
 | |
|                 if (_selectedObjectTab != kvp.Key)
 | |
|                 {
 | |
|                     _selectedHash = string.Empty;
 | |
|                     _selectedObjectTab = kvp.Key;
 | |
|                     _selectedFileTypeTab = string.Empty;
 | |
|                     _enableBc7ConversionMode = false;
 | |
|                     _texturesToConvert.Clear();
 | |
|                 }
 | |
| 
 | |
|                 using var fileTabBar = ImRaii.TabBar("fileTabs");
 | |
| 
 | |
|                 foreach (IGrouping<string, CharacterAnalyzer.FileDataEntry>? fileGroup in groupedfiles)
 | |
|                 {
 | |
|                     string fileGroupText = fileGroup.Key + " [" + fileGroup.Count() + "]";
 | |
|                     var requiresCompute = fileGroup.Any(k => !k.IsComputed);
 | |
|                     using var tabcol = ImRaii.PushColor(ImGuiCol.Tab, UiSharedService.Color(ImGuiColors.DalamudYellow), requiresCompute);
 | |
|                     ImRaii.IEndObject fileTab;
 | |
|                     using (var textcol = ImRaii.PushColor(ImGuiCol.Text, UiSharedService.Color(new(0, 0, 0, 1)),
 | |
|                         requiresCompute && !string.Equals(_selectedFileTypeTab, fileGroup.Key, StringComparison.Ordinal)))
 | |
|                     {
 | |
|                         fileTab = ImRaii.TabItem(fileGroupText + "###" + fileGroup.Key);
 | |
|                     }
 | |
| 
 | |
|                     if (!fileTab) { fileTab.Dispose(); continue; }
 | |
| 
 | |
|                     if (!string.Equals(fileGroup.Key, _selectedFileTypeTab, StringComparison.Ordinal))
 | |
|                     {
 | |
|                         _selectedFileTypeTab = fileGroup.Key;
 | |
|                         _selectedHash = string.Empty;
 | |
|                         _enableBc7ConversionMode = false;
 | |
|                         _texturesToConvert.Clear();
 | |
|                     }
 | |
| 
 | |
|                     ImGui.TextUnformatted($"{fileGroup.Key} files");
 | |
|                     ImGui.SameLine();
 | |
|                     ImGui.TextUnformatted(fileGroup.Count().ToString());
 | |
| 
 | |
|                     ImGui.TextUnformatted($"{fileGroup.Key} files size (actual):");
 | |
|                     ImGui.SameLine();
 | |
|                     ImGui.TextUnformatted(UiSharedService.ByteToString(fileGroup.Sum(c => c.OriginalSize)));
 | |
| 
 | |
|                     ImGui.TextUnformatted($"{fileGroup.Key} files size (download size):");
 | |
|                     ImGui.SameLine();
 | |
|                     ImGui.TextUnformatted(UiSharedService.ByteToString(fileGroup.Sum(c => c.CompressedSize)));
 | |
| 
 | |
|                     if (string.Equals(_selectedFileTypeTab, "tex", StringComparison.Ordinal))
 | |
|                     {
 | |
|                         ImGui.Checkbox("Enable BC7 Conversion Mode", ref _enableBc7ConversionMode);
 | |
|                         if (_enableBc7ConversionMode)
 | |
|                         {
 | |
|                             UiSharedService.ColorText("WARNING BC7 CONVERSION:", ImGuiColors.DalamudYellow);
 | |
|                             ImGui.SameLine();
 | |
|                             UiSharedService.ColorText("Converting textures to BC7 is irreversible!", ImGuiColors.DalamudRed);
 | |
|                             UiSharedService.ColorTextWrapped("- Converting textures to BC7 will reduce their size (compressed and uncompressed) drastically. It is recommended to be used for large (4k+) textures." +
 | |
|                             Environment.NewLine + "- Some textures, especially ones utilizing colorsets, might not be suited for BC7 conversion and might produce visual artifacts." +
 | |
|                             Environment.NewLine + "- Before converting textures, make sure to have the original files of the mod you are converting so you can reimport it in case of issues." +
 | |
|                             Environment.NewLine + "- Conversion will convert all found texture duplicates (entries with more than 1 file path) automatically." +
 | |
|                             Environment.NewLine + "- Converting textures to BC7 is a very expensive operation and, depending on the amount of textures to convert, will take a while to complete."
 | |
|                                 , ImGuiColors.DalamudYellow);
 | |
|                             if (_texturesToConvert.Count > 0 && _uiSharedService.IconTextButton(FontAwesomeIcon.PlayCircle, "Start conversion of " + _texturesToConvert.Count + " texture(s)"))
 | |
|                             {
 | |
|                                 _conversionCancellationTokenSource = _conversionCancellationTokenSource.CancelRecreate();
 | |
|                                 _conversionTask = _ipcManager.Penumbra.ConvertTextureFiles(_logger, _texturesToConvert, _conversionProgress, _conversionCancellationTokenSource.Token);
 | |
|                             }
 | |
|                         }
 | |
|                     }
 | |
| 
 | |
|                     ImGui.Separator();
 | |
|                     DrawTable(fileGroup);
 | |
| 
 | |
|                     fileTab.Dispose();
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         ImGui.Separator();
 | |
| 
 | |
|         ImGui.TextUnformatted("Selected file:");
 | |
|         ImGui.SameLine();
 | |
|         UiSharedService.ColorText(_selectedHash, ImGuiColors.DalamudYellow);
 | |
| 
 | |
|         if (_cachedAnalysis[_selectedObjectTab].TryGetValue(_selectedHash, out CharacterAnalyzer.FileDataEntry? item))
 | |
|         {
 | |
|             var filePaths = item.FilePaths;
 | |
|             ImGui.TextUnformatted("Local file path:");
 | |
|             ImGui.SameLine();
 | |
|             UiSharedService.TextWrapped(filePaths[0]);
 | |
|             if (filePaths.Count > 1)
 | |
|             {
 | |
|                 ImGui.SameLine();
 | |
|                 ImGui.TextUnformatted($"(and {filePaths.Count - 1} more)");
 | |
|                 ImGui.SameLine();
 | |
|                 _uiSharedService.IconText(FontAwesomeIcon.InfoCircle);
 | |
|                 UiSharedService.AttachToolTip(string.Join(Environment.NewLine, filePaths.Skip(1)));
 | |
|             }
 | |
| 
 | |
|             var gamepaths = item.GamePaths;
 | |
|             ImGui.TextUnformatted("Used by game path:");
 | |
|             ImGui.SameLine();
 | |
|             UiSharedService.TextWrapped(gamepaths[0]);
 | |
|             if (gamepaths.Count > 1)
 | |
|             {
 | |
|                 ImGui.SameLine();
 | |
|                 ImGui.TextUnformatted($"(and {gamepaths.Count - 1} more)");
 | |
|                 ImGui.SameLine();
 | |
|                 _uiSharedService.IconText(FontAwesomeIcon.InfoCircle);
 | |
|                 UiSharedService.AttachToolTip(string.Join(Environment.NewLine, gamepaths.Skip(1)));
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     public override void OnOpen()
 | |
|     {
 | |
|         _hasUpdate = true;
 | |
|         _selectedHash = string.Empty;
 | |
|         _enableBc7ConversionMode = false;
 | |
|         _texturesToConvert.Clear();
 | |
|     }
 | |
| 
 | |
|     protected override void Dispose(bool disposing)
 | |
|     {
 | |
|         base.Dispose(disposing);
 | |
|         _conversionProgress.ProgressChanged -= ConversionProgress_ProgressChanged;
 | |
|     }
 | |
| 
 | |
|     private void ConversionProgress_ProgressChanged(object? sender, (string, int) e)
 | |
|     {
 | |
|         _conversionCurrentFileName = e.Item1;
 | |
|         _conversionCurrentFileProgress = e.Item2;
 | |
|     }
 | |
| 
 | |
|     private void DrawTable(IGrouping<string, CharacterAnalyzer.FileDataEntry> fileGroup)
 | |
|     {
 | |
|         var tableColumns = string.Equals(fileGroup.Key, "tex", StringComparison.Ordinal)
 | |
|             ? (_enableBc7ConversionMode ? 7 : 6)
 | |
|             : (string.Equals(fileGroup.Key, "mdl", StringComparison.Ordinal) ? 6 : 5);
 | |
|         using var table = ImRaii.Table("Analysis", tableColumns, ImGuiTableFlags.Sortable | ImGuiTableFlags.RowBg | ImGuiTableFlags.ScrollY | ImGuiTableFlags.SizingFixedFit,
 | |
|             new Vector2(0, 300));
 | |
|         if (!table.Success) return;
 | |
|         ImGui.TableSetupColumn("Hash");
 | |
|         ImGui.TableSetupColumn("Filepaths", ImGuiTableColumnFlags.PreferSortDescending);
 | |
|         ImGui.TableSetupColumn("Gamepaths", ImGuiTableColumnFlags.PreferSortDescending);
 | |
|         ImGui.TableSetupColumn("File Size", ImGuiTableColumnFlags.DefaultSort | ImGuiTableColumnFlags.PreferSortDescending);
 | |
|         ImGui.TableSetupColumn("Download Size", ImGuiTableColumnFlags.PreferSortDescending);
 | |
|         if (string.Equals(fileGroup.Key, "tex", StringComparison.Ordinal))
 | |
|         {
 | |
|             ImGui.TableSetupColumn("Format");
 | |
|             if (_enableBc7ConversionMode) ImGui.TableSetupColumn("Convert to BC7");
 | |
|         }
 | |
|         if (string.Equals(fileGroup.Key, "mdl", StringComparison.Ordinal))
 | |
|         {
 | |
|             ImGui.TableSetupColumn("Triangles", ImGuiTableColumnFlags.PreferSortDescending);
 | |
|         }
 | |
|         ImGui.TableSetupScrollFreeze(0, 1);
 | |
|         ImGui.TableHeadersRow();
 | |
| 
 | |
|         var sortSpecs = ImGui.TableGetSortSpecs();
 | |
|         if (sortSpecs.SpecsDirty || _sortDirty)
 | |
|         {
 | |
|             var idx = sortSpecs.Specs.ColumnIndex;
 | |
| 
 | |
|             if (idx == 0 && sortSpecs.Specs.SortDirection == ImGuiSortDirection.Ascending)
 | |
|                 _cachedAnalysis![_selectedObjectTab] = _cachedAnalysis[_selectedObjectTab].OrderBy(k => k.Key, StringComparer.Ordinal).ToDictionary(d => d.Key, d => d.Value, StringComparer.Ordinal);
 | |
|             if (idx == 0 && sortSpecs.Specs.SortDirection == ImGuiSortDirection.Descending)
 | |
|                 _cachedAnalysis![_selectedObjectTab] = _cachedAnalysis[_selectedObjectTab].OrderByDescending(k => k.Key, StringComparer.Ordinal).ToDictionary(d => d.Key, d => d.Value, StringComparer.Ordinal);
 | |
|             if (idx == 1 && sortSpecs.Specs.SortDirection == ImGuiSortDirection.Ascending)
 | |
|                 _cachedAnalysis![_selectedObjectTab] = _cachedAnalysis[_selectedObjectTab].OrderBy(k => k.Value.FilePaths.Count).ToDictionary(d => d.Key, d => d.Value, StringComparer.Ordinal);
 | |
|             if (idx == 1 && sortSpecs.Specs.SortDirection == ImGuiSortDirection.Descending)
 | |
|                 _cachedAnalysis![_selectedObjectTab] = _cachedAnalysis[_selectedObjectTab].OrderByDescending(k => k.Value.FilePaths.Count).ToDictionary(d => d.Key, d => d.Value, StringComparer.Ordinal);
 | |
|             if (idx == 2 && sortSpecs.Specs.SortDirection == ImGuiSortDirection.Ascending)
 | |
|                 _cachedAnalysis![_selectedObjectTab] = _cachedAnalysis[_selectedObjectTab].OrderBy(k => k.Value.GamePaths.Count).ToDictionary(d => d.Key, d => d.Value, StringComparer.Ordinal);
 | |
|             if (idx == 2 && sortSpecs.Specs.SortDirection == ImGuiSortDirection.Descending)
 | |
|                 _cachedAnalysis![_selectedObjectTab] = _cachedAnalysis[_selectedObjectTab].OrderByDescending(k => k.Value.GamePaths.Count).ToDictionary(d => d.Key, d => d.Value, StringComparer.Ordinal);
 | |
|             if (idx == 3 && sortSpecs.Specs.SortDirection == ImGuiSortDirection.Ascending)
 | |
|                 _cachedAnalysis![_selectedObjectTab] = _cachedAnalysis[_selectedObjectTab].OrderBy(k => k.Value.OriginalSize).ToDictionary(d => d.Key, d => d.Value, StringComparer.Ordinal);
 | |
|             if (idx == 3 && sortSpecs.Specs.SortDirection == ImGuiSortDirection.Descending)
 | |
|                 _cachedAnalysis![_selectedObjectTab] = _cachedAnalysis[_selectedObjectTab].OrderByDescending(k => k.Value.OriginalSize).ToDictionary(d => d.Key, d => d.Value, StringComparer.Ordinal);
 | |
|             if (idx == 4 && sortSpecs.Specs.SortDirection == ImGuiSortDirection.Ascending)
 | |
|                 _cachedAnalysis![_selectedObjectTab] = _cachedAnalysis[_selectedObjectTab].OrderBy(k => k.Value.CompressedSize).ToDictionary(d => d.Key, d => d.Value, StringComparer.Ordinal);
 | |
|             if (idx == 4 && sortSpecs.Specs.SortDirection == ImGuiSortDirection.Descending)
 | |
|                 _cachedAnalysis![_selectedObjectTab] = _cachedAnalysis[_selectedObjectTab].OrderByDescending(k => k.Value.CompressedSize).ToDictionary(d => d.Key, d => d.Value, StringComparer.Ordinal);
 | |
|             if (string.Equals(fileGroup.Key, "mdl", StringComparison.Ordinal) && idx == 5 && sortSpecs.Specs.SortDirection == ImGuiSortDirection.Ascending)
 | |
|                 _cachedAnalysis![_selectedObjectTab] = _cachedAnalysis[_selectedObjectTab].OrderBy(k => k.Value.Triangles).ToDictionary(d => d.Key, d => d.Value, StringComparer.Ordinal);
 | |
|             if (string.Equals(fileGroup.Key, "mdl", StringComparison.Ordinal) && idx == 5 && sortSpecs.Specs.SortDirection == ImGuiSortDirection.Descending)
 | |
|                 _cachedAnalysis![_selectedObjectTab] = _cachedAnalysis[_selectedObjectTab].OrderByDescending(k => k.Value.Triangles).ToDictionary(d => d.Key, d => d.Value, StringComparer.Ordinal);
 | |
|             if (string.Equals(fileGroup.Key, "tex", StringComparison.Ordinal) && idx == 5 && sortSpecs.Specs.SortDirection == ImGuiSortDirection.Ascending)
 | |
|                 _cachedAnalysis![_selectedObjectTab] = _cachedAnalysis[_selectedObjectTab].OrderBy(k => k.Value.Format.Value, StringComparer.Ordinal).ToDictionary(d => d.Key, d => d.Value, StringComparer.Ordinal);
 | |
|             if (string.Equals(fileGroup.Key, "tex", StringComparison.Ordinal) && idx == 5 && sortSpecs.Specs.SortDirection == ImGuiSortDirection.Descending)
 | |
|                 _cachedAnalysis![_selectedObjectTab] = _cachedAnalysis[_selectedObjectTab].OrderByDescending(k => k.Value.Format.Value, StringComparer.Ordinal).ToDictionary(d => d.Key, d => d.Value, StringComparer.Ordinal);
 | |
| 
 | |
|             sortSpecs.SpecsDirty = false;
 | |
|             _sortDirty = false;
 | |
|         }
 | |
| 
 | |
|         foreach (var item in fileGroup)
 | |
|         {
 | |
|             using var text = ImRaii.PushColor(ImGuiCol.Text, new Vector4(0, 0, 0, 1), string.Equals(item.Hash, _selectedHash, StringComparison.Ordinal));
 | |
|             using var text2 = ImRaii.PushColor(ImGuiCol.Text, new Vector4(1, 1, 1, 1), !item.IsComputed);
 | |
|             ImGui.TableNextColumn();
 | |
|             if (string.Equals(_selectedHash, item.Hash, StringComparison.Ordinal))
 | |
|             {
 | |
|                 ImGui.TableSetBgColor(ImGuiTableBgTarget.RowBg1, UiSharedService.Color(ImGuiColors.DalamudYellow));
 | |
|                 ImGui.TableSetBgColor(ImGuiTableBgTarget.RowBg0, UiSharedService.Color(ImGuiColors.DalamudYellow));
 | |
|             }
 | |
|             ImGui.TextUnformatted(item.Hash);
 | |
|             if (ImGui.IsItemClicked()) _selectedHash = item.Hash;
 | |
|             ImGui.TableNextColumn();
 | |
|             ImGui.TextUnformatted(item.FilePaths.Count.ToString());
 | |
|             if (ImGui.IsItemClicked()) _selectedHash = item.Hash;
 | |
|             ImGui.TableNextColumn();
 | |
|             ImGui.TextUnformatted(item.GamePaths.Count.ToString());
 | |
|             if (ImGui.IsItemClicked()) _selectedHash = item.Hash;
 | |
|             ImGui.TableNextColumn();
 | |
|             ImGui.TextUnformatted(UiSharedService.ByteToString(item.OriginalSize));
 | |
|             if (ImGui.IsItemClicked()) _selectedHash = item.Hash;
 | |
|             ImGui.TableNextColumn();
 | |
|             using (ImRaii.PushColor(ImGuiCol.Text, ImGuiColors.DalamudYellow, !item.IsComputed))
 | |
|                 ImGui.TextUnformatted(UiSharedService.ByteToString(item.CompressedSize));
 | |
|             if (ImGui.IsItemClicked()) _selectedHash = item.Hash;
 | |
|             if (string.Equals(fileGroup.Key, "tex", StringComparison.Ordinal))
 | |
|             {
 | |
|                 ImGui.TableNextColumn();
 | |
|                 ImGui.TextUnformatted(item.Format.Value);
 | |
|                 if (ImGui.IsItemClicked()) _selectedHash = item.Hash;
 | |
|                 if (_enableBc7ConversionMode)
 | |
|                 {
 | |
|                     ImGui.TableNextColumn();
 | |
|                     if (item.Format.Value.StartsWith("BC") || item.Format.Value.StartsWith("DXT")
 | |
|                         || item.Format.Value.StartsWith("24864")) // BC4
 | |
|                     {
 | |
|                         ImGui.TextUnformatted("");
 | |
|                         continue;
 | |
|                     }
 | |
|                     var filePath = item.FilePaths[0];
 | |
|                     bool toConvert = _texturesToConvert.ContainsKey(filePath);
 | |
|                     if (ImGui.Checkbox("###convert" + item.Hash, ref toConvert))
 | |
|                     {
 | |
|                         if (toConvert && !_texturesToConvert.ContainsKey(filePath))
 | |
|                         {
 | |
|                             _texturesToConvert[filePath] = item.FilePaths.Skip(1).ToArray();
 | |
|                         }
 | |
|                         else if (!toConvert && _texturesToConvert.ContainsKey(filePath))
 | |
|                         {
 | |
|                             _texturesToConvert.Remove(filePath);
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|             if (string.Equals(fileGroup.Key, "mdl", StringComparison.Ordinal))
 | |
|             {
 | |
|                 ImGui.TableNextColumn();
 | |
|                 ImGui.TextUnformatted(UiSharedService.TrisToString(item.Triangles));
 | |
|                 if (ImGui.IsItemClicked()) _selectedHash = item.Hash;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| } | 
