Add Targa export.

This commit is contained in:
Ottermandias 2024-08-26 21:21:38 +02:00
parent c4853434c8
commit ded910d8a1
5 changed files with 67 additions and 22 deletions

@ -1 +1 @@
Subproject commit 552246e595ffab2aaba2c75f578d564f8938fc9a Subproject commit a38e9bcfb80c456102945bbb4c59f5621cae0442

View file

@ -10,6 +10,7 @@ public class EditingApi(TextureManager textureManager) : IPenumbraApiEditing, IA
=> textureType switch => textureType switch
{ {
TextureType.Png => textureManager.SavePng(inputFile, outputFile), TextureType.Png => textureManager.SavePng(inputFile, outputFile),
TextureType.Targa => textureManager.SaveTga(inputFile, outputFile),
TextureType.AsIsTex => textureManager.SaveAs(CombinedTexture.TextureSaveType.AsIs, mipMaps, true, inputFile, outputFile), TextureType.AsIsTex => textureManager.SaveAs(CombinedTexture.TextureSaveType.AsIs, mipMaps, true, inputFile, outputFile),
TextureType.AsIsDds => textureManager.SaveAs(CombinedTexture.TextureSaveType.AsIs, mipMaps, false, inputFile, outputFile), TextureType.AsIsDds => textureManager.SaveAs(CombinedTexture.TextureSaveType.AsIs, mipMaps, false, inputFile, outputFile),
TextureType.RgbaTex => textureManager.SaveAs(CombinedTexture.TextureSaveType.Bitmap, mipMaps, true, inputFile, outputFile), TextureType.RgbaTex => textureManager.SaveAs(CombinedTexture.TextureSaveType.Bitmap, mipMaps, true, inputFile, outputFile),
@ -26,6 +27,7 @@ public class EditingApi(TextureManager textureManager) : IPenumbraApiEditing, IA
=> textureType switch => textureType switch
{ {
TextureType.Png => textureManager.SavePng(new BaseImage(), outputFile, rgbaData, width, rgbaData.Length / 4 / width), TextureType.Png => textureManager.SavePng(new BaseImage(), outputFile, rgbaData, width, rgbaData.Length / 4 / width),
TextureType.Targa => textureManager.SaveTga(new BaseImage(), outputFile, rgbaData, width, rgbaData.Length / 4 / width),
TextureType.AsIsTex => textureManager.SaveAs(CombinedTexture.TextureSaveType.AsIs, mipMaps, true, new BaseImage(), outputFile, rgbaData, width, rgbaData.Length / 4 / width), TextureType.AsIsTex => textureManager.SaveAs(CombinedTexture.TextureSaveType.AsIs, mipMaps, true, new BaseImage(), outputFile, rgbaData, width, rgbaData.Length / 4 / width),
TextureType.AsIsDds => textureManager.SaveAs(CombinedTexture.TextureSaveType.AsIs, mipMaps, false, new BaseImage(), outputFile, rgbaData, width, rgbaData.Length / 4 / width), TextureType.AsIsDds => textureManager.SaveAs(CombinedTexture.TextureSaveType.AsIs, mipMaps, false, new BaseImage(), outputFile, rgbaData, width, rgbaData.Length / 4 / width),
TextureType.RgbaTex => textureManager.SaveAs(CombinedTexture.TextureSaveType.Bitmap, mipMaps, true, new BaseImage(), outputFile, rgbaData, width, rgbaData.Length / 4 / width), TextureType.RgbaTex => textureManager.SaveAs(CombinedTexture.TextureSaveType.Bitmap, mipMaps, true, new BaseImage(), outputFile, rgbaData, width, rgbaData.Length / 4 / width),

View file

@ -55,6 +55,14 @@ public partial class CombinedTexture : IDisposable
SaveTask = textures.SavePng(_current.BaseImage, path, _current.RgbaPixels, _current.TextureWrap!.Width, _current.TextureWrap!.Height); SaveTask = textures.SavePng(_current.BaseImage, path, _current.RgbaPixels, _current.TextureWrap!.Width, _current.TextureWrap!.Height);
} }
public void SaveAsTarga(TextureManager textures, string path)
{
if (!IsLoaded || _current == null)
return;
SaveTask = textures.SaveTga(_current.BaseImage, path, _current.RgbaPixels, _current.TextureWrap!.Width, _current.TextureWrap!.Height);
}
private void SaveAs(TextureManager textures, string path, TextureSaveType type, bool mipMaps, bool writeTex) private void SaveAs(TextureManager textures, string path, TextureSaveType type, bool mipMaps, bool writeTex)
{ {
if (!IsLoaded || _current == null) if (!IsLoaded || _current == null)
@ -72,6 +80,7 @@ public partial class CombinedTexture : IDisposable
".tex" => TextureType.Tex, ".tex" => TextureType.Tex,
".dds" => TextureType.Dds, ".dds" => TextureType.Dds,
".png" => TextureType.Png, ".png" => TextureType.Png,
".tga" => TextureType.Targa,
_ => TextureType.Unknown, _ => TextureType.Unknown,
}; };
@ -85,6 +94,9 @@ public partial class CombinedTexture : IDisposable
break; break;
case TextureType.Png: case TextureType.Png:
SaveAsPng(textures, path); SaveAsPng(textures, path);
break;
case TextureType.Targa:
SaveAsTarga(textures, path);
break; break;
default: default:
throw new ArgumentException( throw new ArgumentException(

View file

@ -8,6 +8,7 @@ using OtterGui.Tasks;
using OtterTex; using OtterTex;
using SixLabors.ImageSharp; using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Formats.Png; using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.Formats.Tga;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using Image = SixLabors.ImageSharp.Image; using Image = SixLabors.ImageSharp.Image;
@ -33,10 +34,17 @@ public sealed class TextureManager(IDataManager gameData, Logger logger, ITextur
} }
public Task SavePng(string input, string output) public Task SavePng(string input, string output)
=> Enqueue(new SavePngAction(this, input, output)); => Enqueue(new SaveImageSharpAction(this, input, output, TextureType.Png));
public Task SavePng(BaseImage image, string path, byte[]? rgba = null, int width = 0, int height = 0) public Task SavePng(BaseImage image, string path, byte[]? rgba = null, int width = 0, int height = 0)
=> Enqueue(new SavePngAction(this, image, path, rgba, width, height)); => Enqueue(new SaveImageSharpAction(this, image, path, TextureType.Png, rgba, width, height));
public Task SaveTga(string input, string output)
=> Enqueue(new SaveImageSharpAction(this, input, output, TextureType.Targa));
public Task SaveTga(BaseImage image, string path, byte[]? rgba = null, int width = 0, int height = 0)
=> Enqueue(new SaveImageSharpAction(this, image, path, TextureType.Targa, rgba, width, height));
public Task SaveAs(CombinedTexture.TextureSaveType type, bool mipMaps, bool asTex, string input, string output) public Task SaveAs(CombinedTexture.TextureSaveType type, bool mipMaps, bool asTex, string input, string output)
=> Enqueue(new SaveAsAction(this, type, mipMaps, asTex, input, output)); => Enqueue(new SaveAsAction(this, type, mipMaps, asTex, input, output));
@ -66,44 +74,65 @@ public sealed class TextureManager(IDataManager gameData, Logger logger, ITextur
return t; return t;
} }
private class SavePngAction : IAction private class SaveImageSharpAction : IAction
{ {
private readonly TextureManager _textures; private readonly TextureManager _textures;
private readonly string _outputPath; private readonly string _outputPath;
private readonly ImageInputData _input; private readonly ImageInputData _input;
private readonly TextureType _type;
public SavePngAction(TextureManager textures, string input, string output) public SaveImageSharpAction(TextureManager textures, string input, string output, TextureType type)
{ {
_textures = textures; _textures = textures;
_input = new ImageInputData(input); _input = new ImageInputData(input);
_outputPath = output; _outputPath = output;
_type = type;
if (_type.ReduceToBehaviour() is not TextureType.Png)
throw new ArgumentOutOfRangeException(nameof(type), type, $"Can not save as {type} with ImageSharp.");
} }
public SavePngAction(TextureManager textures, BaseImage image, string path, byte[]? rgba = null, int width = 0, int height = 0) public SaveImageSharpAction(TextureManager textures, BaseImage image, string path, TextureType type, byte[]? rgba = null, int width = 0,
int height = 0)
{ {
_textures = textures; _textures = textures;
_input = new ImageInputData(image, rgba, width, height); _input = new ImageInputData(image, rgba, width, height);
_outputPath = path; _outputPath = path;
_type = type;
if (_type.ReduceToBehaviour() is not TextureType.Png)
throw new ArgumentOutOfRangeException(nameof(type), type, $"Can not save as {type} with ImageSharp.");
} }
public void Execute(CancellationToken cancel) public void Execute(CancellationToken cancel)
{ {
_textures._logger.Information($"[{nameof(TextureManager)}] Saving {_input} as .png to {_outputPath}..."); _textures._logger.Information($"[{nameof(TextureManager)}] Saving {_input} as {_type} to {_outputPath}...");
var (image, rgba, width, height) = _input.GetData(_textures); var (image, rgba, width, height) = _input.GetData(_textures);
cancel.ThrowIfCancellationRequested(); cancel.ThrowIfCancellationRequested();
Image<Rgba32>? png = null; Image<Rgba32>? data = null;
if (image.Type is TextureType.Unknown) if (image.Type is TextureType.Unknown)
{ {
if (rgba != null && width > 0 && height > 0) if (rgba != null && width > 0 && height > 0)
png = ConvertToPng(rgba, width, height).AsPng!; data = ConvertToPng(rgba, width, height).AsPng!;
} }
else else
{ {
png = ConvertToPng(image, cancel, rgba).AsPng!; data = ConvertToPng(image, cancel, rgba).AsPng!;
} }
cancel.ThrowIfCancellationRequested(); cancel.ThrowIfCancellationRequested();
png?.SaveAsync(_outputPath, new PngEncoder() { CompressionLevel = PngCompressionLevel.NoCompression }, cancel).Wait(cancel); switch (_type)
{
case TextureType.Png:
data?.SaveAsync(_outputPath, new PngEncoder() { CompressionLevel = PngCompressionLevel.NoCompression }, cancel)
.Wait(cancel);
return;
case TextureType.Targa:
data?.SaveAsync(_outputPath, new TgaEncoder()
{
Compression = TgaCompression.None,
BitsPerPixel = TgaBitsPerPixel.Pixel32,
}, cancel).Wait(cancel);
return;
}
} }
public override string ToString() public override string ToString()
@ -111,7 +140,7 @@ public sealed class TextureManager(IDataManager gameData, Logger logger, ITextur
public bool Equals(IAction? other) public bool Equals(IAction? other)
{ {
if (other is not SavePngAction rhs) if (other is not SaveImageSharpAction rhs)
return false; return false;
return string.Equals(_outputPath, rhs._outputPath, StringComparison.OrdinalIgnoreCase) && _input.Equals(rhs._input); return string.Equals(_outputPath, rhs._outputPath, StringComparison.OrdinalIgnoreCase) && _input.Equals(rhs._input);
@ -168,9 +197,8 @@ public sealed class TextureManager(IDataManager gameData, Logger logger, ITextur
var imageTypeBehaviour = image.Type.ReduceToBehaviour(); var imageTypeBehaviour = image.Type.ReduceToBehaviour();
var dds = _type switch var dds = _type switch
{ {
CombinedTexture.TextureSaveType.AsIs when imageTypeBehaviour is TextureType.Png => ConvertToRgbaDds(image, _mipMaps, CombinedTexture.TextureSaveType.AsIs when imageTypeBehaviour is TextureType.Png => ConvertToRgbaDds(image, _mipMaps, cancel,
cancel, rgba, rgba, width, height),
width, height),
CombinedTexture.TextureSaveType.AsIs when imageTypeBehaviour is TextureType.Dds => AddMipMaps(image.AsDds!, _mipMaps), CombinedTexture.TextureSaveType.AsIs when imageTypeBehaviour is TextureType.Dds => AddMipMaps(image.AsDds!, _mipMaps),
CombinedTexture.TextureSaveType.Bitmap => ConvertToRgbaDds(image, _mipMaps, cancel, rgba, width, height), CombinedTexture.TextureSaveType.Bitmap => ConvertToRgbaDds(image, _mipMaps, cancel, rgba, width, height),
CombinedTexture.TextureSaveType.BC3 => ConvertToCompressedDds(image, _mipMaps, false, cancel, rgba, width, height), CombinedTexture.TextureSaveType.BC3 => ConvertToCompressedDds(image, _mipMaps, false, cancel, rgba, width, height),

View file

@ -85,7 +85,7 @@ public partial class ModEditWindow
ImGuiUtil.SelectableHelpMarker(newDesc); ImGuiUtil.SelectableHelpMarker(newDesc);
} }
} }
private void RedrawOnSaveBox() private void RedrawOnSaveBox()
{ {
@ -128,7 +128,8 @@ public partial class ModEditWindow
? "This saves the texture in place. This is not revertible." ? "This saves the texture in place. This is not revertible."
: $"This saves the texture in place. This is not revertible. Hold {_config.DeleteModModifier} to save."; : $"This saves the texture in place. This is not revertible. Hold {_config.DeleteModModifier} to save.";
var buttonSize2 = new Vector2((ImGui.GetContentRegionAvail().X - ImGui.GetStyle().ItemSpacing.X) / 2, 0); var buttonSize2 = new Vector2((ImGui.GetContentRegionAvail().X - ImGui.GetStyle().ItemSpacing.X) / 2, 0);
var buttonSize3 = new Vector2((ImGui.GetContentRegionAvail().X - ImGui.GetStyle().ItemSpacing.X * 2) / 3, 0);
if (ImGuiUtil.DrawDisabledButton("Save in place", buttonSize2, if (ImGuiUtil.DrawDisabledButton("Save in place", buttonSize2,
tt, !isActive || !canSaveInPlace || _center.IsLeftCopy && _currentSaveAs == (int)CombinedTexture.TextureSaveType.AsIs)) tt, !isActive || !canSaveInPlace || _center.IsLeftCopy && _currentSaveAs == (int)CombinedTexture.TextureSaveType.AsIs))
{ {
@ -141,17 +142,18 @@ public partial class ModEditWindow
if (ImGui.Button("Save as TEX", buttonSize2)) if (ImGui.Button("Save as TEX", buttonSize2))
OpenSaveAsDialog(".tex"); OpenSaveAsDialog(".tex");
if (ImGui.Button("Export as PNG", buttonSize2)) if (ImGui.Button("Export as TGA", buttonSize3))
OpenSaveAsDialog(".tga");
ImGui.SameLine();
if (ImGui.Button("Export as PNG", buttonSize3))
OpenSaveAsDialog(".png"); OpenSaveAsDialog(".png");
ImGui.SameLine(); ImGui.SameLine();
if (ImGui.Button("Export as DDS", buttonSize2)) if (ImGui.Button("Export as DDS", buttonSize3))
OpenSaveAsDialog(".dds"); OpenSaveAsDialog(".dds");
ImGui.NewLine(); ImGui.NewLine();
var canConvertInPlace = canSaveInPlace && _left.Type is TextureType.Tex && _center.IsLeftCopy; var canConvertInPlace = canSaveInPlace && _left.Type is TextureType.Tex && _center.IsLeftCopy;
var buttonSize3 = new Vector2((ImGui.GetContentRegionAvail().X - ImGui.GetStyle().ItemSpacing.X * 2) / 3, 0);
if (ImGuiUtil.DrawDisabledButton("Convert to BC7", buttonSize3, if (ImGuiUtil.DrawDisabledButton("Convert to BC7", buttonSize3,
"This converts the texture to BC7 format in place. This is not revertible.", "This converts the texture to BC7 format in place. This is not revertible.",
!canConvertInPlace || _left.Format is DXGIFormat.BC7Typeless or DXGIFormat.BC7UNorm or DXGIFormat.BC7UNormSRGB)) !canConvertInPlace || _left.Format is DXGIFormat.BC7Typeless or DXGIFormat.BC7UNorm or DXGIFormat.BC7UNormSRGB))
@ -226,7 +228,8 @@ public partial class ModEditWindow
private void OpenSaveAsDialog(string defaultExtension) private void OpenSaveAsDialog(string defaultExtension)
{ {
var fileName = Path.GetFileNameWithoutExtension(_left.Path.Length > 0 ? _left.Path : _right.Path); var fileName = Path.GetFileNameWithoutExtension(_left.Path.Length > 0 ? _left.Path : _right.Path);
_fileDialog.OpenSavePicker("Save Texture as TEX, DDS or PNG...", "Textures{.png,.dds,.tex},.tex,.dds,.png", fileName, defaultExtension, _fileDialog.OpenSavePicker("Save Texture as TEX, DDS, PNG or TGA...", "Textures{.png,.dds,.tex,.tga},.tex,.dds,.png,.tga", fileName,
defaultExtension,
(a, b) => (a, b) =>
{ {
if (a) if (a)