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.Png => textureManager.SavePng(inputFile, outputFile),
TextureType.Targa => textureManager.SaveTga(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.RgbaTex => textureManager.SaveAs(CombinedTexture.TextureSaveType.Bitmap, mipMaps, true, inputFile, outputFile),
@ -26,6 +27,7 @@ public class EditingApi(TextureManager textureManager) : IPenumbraApiEditing, IA
=> textureType switch
{
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.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),

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);
}
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)
{
if (!IsLoaded || _current == null)
@ -72,6 +80,7 @@ public partial class CombinedTexture : IDisposable
".tex" => TextureType.Tex,
".dds" => TextureType.Dds,
".png" => TextureType.Png,
".tga" => TextureType.Targa,
_ => TextureType.Unknown,
};
@ -85,6 +94,9 @@ public partial class CombinedTexture : IDisposable
break;
case TextureType.Png:
SaveAsPng(textures, path);
break;
case TextureType.Targa:
SaveAsTarga(textures, path);
break;
default:
throw new ArgumentException(

View file

@ -8,6 +8,7 @@ using OtterGui.Tasks;
using OtterTex;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.Formats.Tga;
using SixLabors.ImageSharp.PixelFormats;
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)
=> 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)
=> 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)
=> Enqueue(new SaveAsAction(this, type, mipMaps, asTex, input, output));
@ -66,44 +74,65 @@ public sealed class TextureManager(IDataManager gameData, Logger logger, ITextur
return t;
}
private class SavePngAction : IAction
private class SaveImageSharpAction : IAction
{
private readonly TextureManager _textures;
private readonly string _outputPath;
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;
_input = new ImageInputData(input);
_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;
_input = new ImageInputData(image, rgba, width, height);
_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)
{
_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);
cancel.ThrowIfCancellationRequested();
Image<Rgba32>? png = null;
Image<Rgba32>? data = null;
if (image.Type is TextureType.Unknown)
{
if (rgba != null && width > 0 && height > 0)
png = ConvertToPng(rgba, width, height).AsPng!;
data = ConvertToPng(rgba, width, height).AsPng!;
}
else
{
png = ConvertToPng(image, cancel, rgba).AsPng!;
data = ConvertToPng(image, cancel, rgba).AsPng!;
}
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()
@ -111,7 +140,7 @@ public sealed class TextureManager(IDataManager gameData, Logger logger, ITextur
public bool Equals(IAction? other)
{
if (other is not SavePngAction rhs)
if (other is not SaveImageSharpAction rhs)
return false;
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 dds = _type switch
{
CombinedTexture.TextureSaveType.AsIs when imageTypeBehaviour is TextureType.Png => ConvertToRgbaDds(image, _mipMaps,
cancel, rgba,
width, height),
CombinedTexture.TextureSaveType.AsIs when imageTypeBehaviour is TextureType.Png => ConvertToRgbaDds(image, _mipMaps, cancel,
rgba, width, height),
CombinedTexture.TextureSaveType.AsIs when imageTypeBehaviour is TextureType.Dds => AddMipMaps(image.AsDds!, _mipMaps),
CombinedTexture.TextureSaveType.Bitmap => ConvertToRgbaDds(image, _mipMaps, 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);
}
}
}
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. 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,
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))
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");
ImGui.SameLine();
if (ImGui.Button("Export as DDS", buttonSize2))
if (ImGui.Button("Export as DDS", buttonSize3))
OpenSaveAsDialog(".dds");
ImGui.NewLine();
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,
"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))
@ -226,7 +228,8 @@ public partial class ModEditWindow
private void OpenSaveAsDialog(string defaultExtension)
{
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) =>
{
if (a)