using System; using System.Linq; using Robust.Client.AutoGenerated; using Robust.Client.Graphics; using Robust.Client.Graphics.Clyde; using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.XAML; using Robust.Shared.IoC; using Robust.Shared.Localization; using Robust.Shared.Utility; namespace Robust.Client.UserInterface; /// /// Shows all loaded textures in the game. /// [GenerateTypedNameReferences] internal sealed partial class DevWindowTabTextures : Control { [Dependency] private IClydeInternal _clyde = null!; [Dependency] private ILocalizationManager _loc = null!; public DevWindowTabTextures() { RobustXamlLoader.Load(this); IoCManager.InjectDependencies(this); ReloadButton.OnPressed += _ => Reload(); SearchBar.OnTextChanged += _ => Reload(); } protected override void VisibilityChanged(bool newVisible) { if (newVisible) { Reload(); } else { // Clear to release memory when tab not visible. Clear(); } } private void Clear() { TextureList.RemoveAllChildren(); } private void Reload() { Clear(); var total = 0L; foreach (var (clydeTexture, loadedTexture) in _clyde.GetLoadedTextures() .OrderByDescending(tup => tup.Item2.MemoryPressure)) { if (!string.IsNullOrWhiteSpace(SearchBar.Text)) { if (loadedTexture.Name is not { } name) continue; if (!name.Contains(SearchBar.Text, StringComparison.CurrentCultureIgnoreCase)) continue; } if (loadedTexture.MemoryPressure == 0) { // Bad hack to avoid showing render targets lol. continue; } var button = new ContainerButton { Children = { new TextureEntry(loadedTexture, clydeTexture) } }; button.OnPressed += _ => SelectTexture(loadedTexture, clydeTexture); TextureList.AddChild(button); total += loadedTexture.MemoryPressure; } SummaryLabel.Text = _loc.GetString("dev-window-tab-textures-summary", ("bytes", ByteHelpers.FormatBytes(total))); } private void SelectTexture(Clyde.LoadedTexture loaded, Clyde.ClydeTexture texture) { SelectedTextureDisplay.Texture = texture; SelectedTextureInfo.Text = _loc.GetString("dev-window-tab-textures-info", ("width", loaded.Width), ("height", loaded.Height), ("pixelType", loaded.TexturePixelType), ("srgb", loaded.IsSrgb), ("name", loaded.Name ?? ""), ("bytes", ByteHelpers.FormatBytes(loaded.MemoryPressure))); } private sealed class TextureEntry : Control { public TextureEntry(Clyde.LoadedTexture loaded, Clyde.ClydeTexture texture) { SetHeight = 64; var bytes = ByteHelpers.FormatBytes(loaded.MemoryPressure); var label = loaded.Name == null ? $"{texture.TextureId} ({bytes})" : $"{loaded.Name}\n{texture.TextureId} ({bytes})"; AddChild(new BoxContainer { Orientation = BoxContainer.LayoutOrientation.Horizontal, Children = { new TextureRect { SetWidth = 64, Texture = texture, CanShrink = true, RectClipContent = true, Stretch = TextureRect.StretchMode.Scale }, new Label { Text = label, ClipText = true, HorizontalExpand = true } } }); } } }