diff --git a/Penumbra/UI/Classes/ModEditWindow.Textures.cs b/Penumbra/UI/Classes/ModEditWindow.Textures.cs index 2762179c..9b07b8a1 100644 --- a/Penumbra/UI/Classes/ModEditWindow.Textures.cs +++ b/Penumbra/UI/Classes/ModEditWindow.Textures.cs @@ -22,7 +22,7 @@ using Image = SixLabors.ImageSharp.Image; namespace Penumbra.UI.Classes; -public struct Texture : IDisposable +public class Texture : IDisposable { // Path to the file we tried to load. public string Path = string.Empty; @@ -44,6 +44,28 @@ public struct Texture : IDisposable public Texture() { } + public void Draw( Vector2 size ) + { + if( TextureWrap != null ) + { + ImGui.TextUnformatted( $"Image Dimensions: {TextureWrap.Width} x {TextureWrap.Height}" ); + size = size.X < TextureWrap.Width + ? size with { Y = TextureWrap.Height * size.X / TextureWrap.Width } + : new Vector2( TextureWrap.Width, TextureWrap.Height ); + + ImGui.Image( TextureWrap.ImGuiHandle, size ); + } + else if( LoadError != null ) + { + ImGui.TextUnformatted( "Could not load file:" ); + ImGuiUtil.TextColored( Colors.RegexWarningBorder, LoadError.ToString() ); + } + else + { + ImGui.Dummy( size ); + } + } + private void Clean() { RGBAPixels = Array.Empty< byte >(); @@ -51,47 +73,88 @@ public struct Texture : IDisposable TextureWrap = null; ( BaseImage as IDisposable )?.Dispose(); BaseImage = null; + Loaded?.Invoke( false ); } public void Dispose() => Clean(); - public bool Load( string path ) + public event Action< bool >? Loaded; + + private void Load( string path ) { + _tmpPath = null; if( path == Path ) { - return false; + return; } Path = path; Clean(); - return System.IO.Path.GetExtension( Path ) switch + try { - ".dds" => LoadDds(), - ".png" => LoadPng(), - ".tex" => LoadTex(), - _ => true, - }; + var _ = System.IO.Path.GetExtension( Path ) switch + { + ".dds" => LoadDds(), + ".png" => LoadPng(), + ".tex" => LoadTex(), + _ => true, + }; + Loaded?.Invoke( true ); + } + catch( Exception e ) + { + LoadError = e; + Clean(); + } } private bool LoadDds() - => true; + { + var scratch = ScratchImage.LoadDDS( Path ); + BaseImage = scratch; + var rgba = scratch.GetRGBA( out var f ).ThrowIfError( f ); + RGBAPixels = rgba.Pixels[ ..( f.Meta.Width * f.Meta.Height * f.Meta.Format.BitsPerPixel() / 8 ) ].ToArray(); + CreateTextureWrap( f.Meta.Width, f.Meta.Height ); + return true; + } private bool LoadPng() - => true; + { + BaseImage = null; + using var stream = File.OpenRead( Path ); + using var png = Image.Load< Rgba32 >( stream ); + RGBAPixels = new byte[png.Height * png.Width * 4]; + png.CopyPixelDataTo( RGBAPixels ); + CreateTextureWrap( png.Width, png.Height ); + return true; + } private bool LoadTex() - => true; + { + var tex = System.IO.Path.IsPathRooted( Path ) + ? Dalamud.GameData.GameData.GetFileFromDisk< TexFile >( Path ) + : Dalamud.GameData.GetFile< TexFile >( Path ); + BaseImage = tex ?? throw new Exception( "Could not read .tex file." ); + RGBAPixels = tex.GetRgbaImageData(); + CreateTextureWrap( tex.Header.Width, tex.Header.Height ); + return true; + } + + private void CreateTextureWrap( int width, int height ) + => TextureWrap = Dalamud.PluginInterface.UiBuilder.LoadImageRaw( RGBAPixels, width, height, 4 ); + + private string? _tmpPath; public void PathInputBox( string label, string hint, string tooltip, string startPath, FileDialogManager manager ) { - var tmp = Path; + _tmpPath ??= Path; using var spacing = ImRaii.PushStyle( ImGuiStyleVar.ItemSpacing, new Vector2( 3 * ImGuiHelpers.GlobalScale, 0 ) ); ImGui.SetNextItemWidth( -ImGui.GetFrameHeight() - 3 * ImGuiHelpers.GlobalScale ); - ImGui.InputTextWithHint( label, hint, ref tmp, Utf8GamePath.MaxGamePathLength ); + ImGui.InputTextWithHint( label, hint, ref _tmpPath, Utf8GamePath.MaxGamePathLength ); if( ImGui.IsItemDeactivatedAfterEdit() ) { - Load( tmp ); + Load( _tmpPath ); } ImGuiUtil.HoverTooltip( tooltip ); @@ -119,7 +182,7 @@ public struct Texture : IDisposable } public static Texture Combined( Texture left, Texture right, InputManipulations leftManips, InputManipulations rightManips ) - => new Texture(); + => new(); } public struct InputManipulations @@ -352,13 +415,17 @@ public partial class ModEditWindow { try { - if (!ScratchImage.LoadDDS( path, out var f )) + if( !ScratchImage.LoadDDS( path, out var f ) ) + { return ( null, 0, 0 ); + } - if(!f.GetRGBA( out f )) + if( !f.GetRGBA( out f ) ) + { return ( null, 0, 0 ); + } - return ( f.Pixels[ ..(f.Meta.Width * f.Meta.Height * 4) ].ToArray(), f.Meta.Width, f.Meta.Height ); + return ( f.Pixels[ ..( f.Meta.Width * f.Meta.Height * 4 ) ].ToArray(), f.Meta.Width, f.Meta.Height ); } catch( Exception e ) { @@ -715,4 +782,4 @@ public partial class ModEditWindow } } } -} +} \ No newline at end of file