From 600f5987cda4f9e345fdb17830d500acffd52f93 Mon Sep 17 00:00:00 2001 From: Ottermandias Date: Wed, 30 Aug 2023 17:25:26 +0200 Subject: [PATCH] Slight restructuring. --- .../Textures/CombinedTexture.Manipulation.cs | 230 ++---------------- .../Textures/CombinedTexture.Operations.cs | 150 ++++++++++++ Penumbra/Import/Textures/RgbaPixelData.cs | 43 ++++ 3 files changed, 219 insertions(+), 204 deletions(-) create mode 100644 Penumbra/Import/Textures/CombinedTexture.Operations.cs create mode 100644 Penumbra/Import/Textures/RgbaPixelData.cs diff --git a/Penumbra/Import/Textures/CombinedTexture.Manipulation.cs b/Penumbra/Import/Textures/CombinedTexture.Manipulation.cs index 1633de62..9bc4a2a5 100644 --- a/Penumbra/Import/Textures/CombinedTexture.Manipulation.cs +++ b/Penumbra/Import/Textures/CombinedTexture.Manipulation.cs @@ -8,81 +8,12 @@ using SixLabors.ImageSharp.PixelFormats; using Dalamud.Interface; using Penumbra.UI; -using SixLabors.ImageSharp; -using SixLabors.ImageSharp.Processing; using System.Linq; namespace Penumbra.Import.Textures; public partial class CombinedTexture { - private enum CombineOp - { - LeftMultiply = -4, - LeftCopy = -3, - RightCopy = -2, - Invalid = -1, - Over = 0, - Under = 1, - RightMultiply = 2, - CopyChannels = 3, - } - - private enum ResizeOp - { - LeftOnly = -2, - RightOnly = -1, - None = 0, - ToLeft = 1, - ToRight = 2, - } - - [Flags] - private enum Channels - { - Red = 1, - Green = 2, - Blue = 4, - Alpha = 8, - } - - private readonly record struct RgbaPixelData(int Width, int Height, byte[] PixelData) - { - public static readonly RgbaPixelData Empty = new(0, 0, Array.Empty()); - - public (int Width, int Height) Size - => (Width, Height); - - public RgbaPixelData((int Width, int Height) size, byte[] pixelData) - : this(size.Width, size.Height, pixelData) - { - } - - public Image ToImage() - => Image.LoadPixelData(PixelData, Width, Height); - - public RgbaPixelData Resize((int Width, int Height) size) - { - if (Width == size.Width && Height == size.Height) - return this; - - var result = new RgbaPixelData(size, NewPixelData(size)); - using (var image = ToImage()) - { - image.Mutate(ctx => ctx.Resize(size.Width, size.Height, KnownResamplers.Lanczos3)); - image.CopyPixelDataTo(result.PixelData); - } - - return result; - } - - public static byte[] NewPixelData((int Width, int Height) size) - => new byte[size.Width * size.Height * 4]; - - public static RgbaPixelData FromTexture(Texture texture) - => new(texture.TextureWrap!.Width, texture.TextureWrap!.Height, texture.RgbaPixels); - } - private Matrix4x4 _multiplierLeft = Matrix4x4.Identity; private Vector4 _constantLeft = Vector4.Zero; private Matrix4x4 _multiplierRight = Matrix4x4.Identity; @@ -96,42 +27,6 @@ public static RgbaPixelData FromTexture(Texture texture) private RgbaPixelData _leftPixels = RgbaPixelData.Empty; private RgbaPixelData _rightPixels = RgbaPixelData.Empty; - private static readonly IReadOnlyList CombineOpLabels = new string[] - { - "Overlay over Input", - "Input over Overlay", - "Replace Input", - "Copy Channels", - }; - - private static readonly IReadOnlyList CombineOpTooltips = new string[] - { - "Standard composition.\nApply the overlay over the input.", - "Standard composition, reversed.\nApply the input over the overlay ; can be used to fix some wrong imports.", - "Completely replace the input with the overlay.\nCan be used to select the destination file as input and the source file as overlay.", - "Replace some input channels with those from the overlay.\nUseful for Multi maps.", - }; - - private static ResizeOp GetActualResizeOp(ResizeOp resizeOp, CombineOp combineOp) - => combineOp switch - { - CombineOp.LeftCopy => ResizeOp.LeftOnly, - CombineOp.LeftMultiply => ResizeOp.LeftOnly, - CombineOp.RightCopy => ResizeOp.RightOnly, - CombineOp.RightMultiply => ResizeOp.RightOnly, - CombineOp.Over => resizeOp, - CombineOp.Under => resizeOp, - CombineOp.CopyChannels => resizeOp, - _ => throw new ArgumentException($"Invalid combine operation {combineOp}"), - }; - - private static readonly IReadOnlyList ResizeOpLabels = new string[] - { - "No Resizing", - "Adjust Overlay to Input", - "Adjust Input to Overlay", - }; - private const float OneThird = 1.0f / 3.0f; private const float RWeight = 0.2126f; private const float GWeight = 0.7152f; @@ -154,32 +49,6 @@ private static ResizeOp GetActualResizeOp(ResizeOp resizeOp, CombineOp combineOp }; // @formatter:on - private CombineOp GetActualCombineOp() - { - var combineOp = (_left.IsLoaded, _right.IsLoaded) switch - { - (true, true) => _combineOp, - (true, false) => CombineOp.LeftMultiply, - (false, true) => CombineOp.RightMultiply, - (false, false) => CombineOp.Invalid, - }; - - if (combineOp == CombineOp.CopyChannels) - { - if (_copyChannels == 0) - combineOp = CombineOp.LeftMultiply; - else if (_copyChannels == (Channels.Red | Channels.Green | Channels.Blue | Channels.Alpha)) - combineOp = CombineOp.RightMultiply; - } - - return combineOp switch - { - CombineOp.LeftMultiply when _multiplierLeft.IsIdentity && _constantLeft == Vector4.Zero => CombineOp.LeftCopy, - CombineOp.RightMultiply when _multiplierRight.IsIdentity && _constantRight == Vector4.Zero => CombineOp.RightCopy, - _ => combineOp, - }; - } - private Vector4 DataLeft(int offset) => CappedVector(_leftPixels.PixelData, offset, _multiplierLeft, _constantLeft); @@ -280,11 +149,10 @@ private void MultiplyPixelsRight(int y, ParallelLoopState _) } } - private (int Width, int Height) CombineImage() { var combineOp = GetActualCombineOp(); - var resizeOp = GetActualResizeOp(_resizeOp, combineOp); + var resizeOp = GetActualResizeOp(_resizeOp, combineOp); var left = resizeOp != ResizeOp.RightOnly ? RgbaPixelData.FromTexture(_left) : RgbaPixelData.Empty; var right = resizeOp != ResizeOp.LeftOnly ? RgbaPixelData.FromTexture(_right) : RgbaPixelData.Empty; @@ -325,8 +193,8 @@ private void MultiplyPixelsRight(int y, ParallelLoopState _) } finally { - _leftPixels = RgbaPixelData.Empty; - _rightPixels = RgbaPixelData.Empty; + _leftPixels = RgbaPixelData.Empty; + _rightPixels = RgbaPixelData.Empty; } return targetSize; @@ -488,99 +356,53 @@ private static bool DrawMatrixInput(ref Matrix4x4 multiplier, ref Vector4 consta private static bool DrawMatrixTools(ref Matrix4x4 multiplier, ref Vector4 constant) { - var changes = false; - - using (var combo = ImRaii.Combo("Presets", string.Empty, ImGuiComboFlags.NoPreview)) - { - if (combo) - foreach (var (label, preMultiplier, preConstant) in PredefinedColorTransforms) - { - if (ImGui.Selectable(label, multiplier == preMultiplier && constant == preConstant)) - { - multiplier = preMultiplier; - constant = preConstant; - changes = true; - } - } - } - + var changes = PresetCombo(ref multiplier, ref constant); ImGui.SameLine(); ImGui.Dummy(ImGuiHelpers.ScaledVector2(20, 0)); ImGui.SameLine(); ImGui.TextUnformatted("Invert"); ImGui.SameLine(); - if (ImGui.Button("Colors")) - { - InvertRed(ref multiplier, ref constant); - InvertGreen(ref multiplier, ref constant); - InvertBlue(ref multiplier, ref constant); - changes = true; - } + Channels channels = 0; + if (ImGui.Button("Colors")) + channels |= Channels.Red | Channels.Green | Channels.Blue; ImGui.SameLine(); if (ImGui.Button("R")) - { - InvertRed(ref multiplier, ref constant); - changes = true; - } + channels |= Channels.Red; ImGui.SameLine(); if (ImGui.Button("G")) - { - InvertGreen(ref multiplier, ref constant); - changes = true; - } + channels |= Channels.Green; ImGui.SameLine(); if (ImGui.Button("B")) - { - InvertBlue(ref multiplier, ref constant); - changes = true; - } + channels |= Channels.Blue; ImGui.SameLine(); if (ImGui.Button("A")) - { - InvertAlpha(ref multiplier, ref constant); - changes = true; - } + channels |= Channels.Alpha; + changes |= InvertChannels(channels, ref multiplier, ref constant); return changes; } - private static void InvertRed(ref Matrix4x4 multiplier, ref Vector4 constant) + private static bool PresetCombo(ref Matrix4x4 multiplier, ref Vector4 constant) { - multiplier.M11 = -multiplier.M11; - multiplier.M21 = -multiplier.M21; - multiplier.M31 = -multiplier.M31; - multiplier.M41 = -multiplier.M41; - constant.X = 1.0f - constant.X; - } + using var combo = ImRaii.Combo("Presets", string.Empty, ImGuiComboFlags.NoPreview); + if (!combo) + return false; - private static void InvertGreen(ref Matrix4x4 multiplier, ref Vector4 constant) - { - multiplier.M12 = -multiplier.M12; - multiplier.M22 = -multiplier.M22; - multiplier.M32 = -multiplier.M32; - multiplier.M42 = -multiplier.M42; - constant.Y = 1.0f - constant.Y; - } + var ret = false; + foreach (var (label, preMultiplier, preConstant) in PredefinedColorTransforms) + { + if (!ImGui.Selectable(label, multiplier == preMultiplier && constant == preConstant)) + continue; - private static void InvertBlue(ref Matrix4x4 multiplier, ref Vector4 constant) - { - multiplier.M13 = -multiplier.M13; - multiplier.M23 = -multiplier.M23; - multiplier.M33 = -multiplier.M33; - multiplier.M43 = -multiplier.M43; - constant.Z = 1.0f - constant.Z; - } + multiplier = preMultiplier; + constant = preConstant; + ret = true; + } - private static void InvertAlpha(ref Matrix4x4 multiplier, ref Vector4 constant) - { - multiplier.M14 = -multiplier.M14; - multiplier.M24 = -multiplier.M24; - multiplier.M34 = -multiplier.M34; - multiplier.M44 = -multiplier.M44; - constant.W = 1.0f - constant.W; + return ret; } } diff --git a/Penumbra/Import/Textures/CombinedTexture.Operations.cs b/Penumbra/Import/Textures/CombinedTexture.Operations.cs new file mode 100644 index 00000000..441cd3f0 --- /dev/null +++ b/Penumbra/Import/Textures/CombinedTexture.Operations.cs @@ -0,0 +1,150 @@ +using System; +using System.Collections.Generic; +using System.Numerics; + +namespace Penumbra.Import.Textures; + +public partial class CombinedTexture +{ + private enum CombineOp + { + LeftMultiply = -4, + LeftCopy = -3, + RightCopy = -2, + Invalid = -1, + Over = 0, + Under = 1, + RightMultiply = 2, + CopyChannels = 3, + } + + private enum ResizeOp + { + LeftOnly = -2, + RightOnly = -1, + None = 0, + ToLeft = 1, + ToRight = 2, + } + + [Flags] + private enum Channels : byte + { + Red = 1, + Green = 2, + Blue = 4, + Alpha = 8, + } + + private static readonly IReadOnlyList CombineOpLabels = new[] + { + "Overlay over Input", + "Input over Overlay", + "Replace Input", + "Copy Channels", + }; + + private static readonly IReadOnlyList CombineOpTooltips = new[] + { + "Standard composition.\nApply the overlay over the input.", + "Standard composition, reversed.\nApply the input over the overlay ; can be used to fix some wrong imports.", + "Completely replace the input with the overlay.\nCan be used to select the destination file as input and the source file as overlay.", + "Replace some input channels with those from the overlay.\nUseful for Multi maps.", + }; + + private static readonly IReadOnlyList ResizeOpLabels = new string[] + { + "No Resizing", + "Adjust Overlay to Input", + "Adjust Input to Overlay", + }; + + private static ResizeOp GetActualResizeOp(ResizeOp resizeOp, CombineOp combineOp) + => combineOp switch + { + CombineOp.LeftCopy => ResizeOp.LeftOnly, + CombineOp.LeftMultiply => ResizeOp.LeftOnly, + CombineOp.RightCopy => ResizeOp.RightOnly, + CombineOp.RightMultiply => ResizeOp.RightOnly, + CombineOp.Over => resizeOp, + CombineOp.Under => resizeOp, + CombineOp.CopyChannels => resizeOp, + _ => throw new ArgumentException($"Invalid combine operation {combineOp}"), + }; + + private CombineOp GetActualCombineOp() + { + var combineOp = (_left.IsLoaded, _right.IsLoaded) switch + { + (true, true) => _combineOp, + (true, false) => CombineOp.LeftMultiply, + (false, true) => CombineOp.RightMultiply, + (false, false) => CombineOp.Invalid, + }; + + if (combineOp == CombineOp.CopyChannels) + { + if (_copyChannels == 0) + combineOp = CombineOp.LeftMultiply; + else if (_copyChannels == (Channels.Red | Channels.Green | Channels.Blue | Channels.Alpha)) + combineOp = CombineOp.RightMultiply; + } + + return combineOp switch + { + CombineOp.LeftMultiply when _multiplierLeft.IsIdentity && _constantLeft == Vector4.Zero => CombineOp.LeftCopy, + CombineOp.RightMultiply when _multiplierRight.IsIdentity && _constantRight == Vector4.Zero => CombineOp.RightCopy, + _ => combineOp, + }; + } + + + private static bool InvertChannels(Channels channels, ref Matrix4x4 multiplier, ref Vector4 constant) + { + if (channels.HasFlag(Channels.Red)) + InvertRed(ref multiplier, ref constant); + if (channels.HasFlag(Channels.Green)) + InvertGreen(ref multiplier, ref constant); + if (channels.HasFlag(Channels.Blue)) + InvertBlue(ref multiplier, ref constant); + if (channels.HasFlag(Channels.Alpha)) + InvertAlpha(ref multiplier, ref constant); + return channels != 0; + } + + private static void InvertRed(ref Matrix4x4 multiplier, ref Vector4 constant) + { + multiplier.M11 = -multiplier.M11; + multiplier.M21 = -multiplier.M21; + multiplier.M31 = -multiplier.M31; + multiplier.M41 = -multiplier.M41; + constant.X = 1.0f - constant.X; + } + + private static void InvertGreen(ref Matrix4x4 multiplier, ref Vector4 constant) + { + multiplier.M12 = -multiplier.M12; + multiplier.M22 = -multiplier.M22; + multiplier.M32 = -multiplier.M32; + multiplier.M42 = -multiplier.M42; + constant.Y = 1.0f - constant.Y; + } + + private static void InvertBlue(ref Matrix4x4 multiplier, ref Vector4 constant) + { + multiplier.M13 = -multiplier.M13; + multiplier.M23 = -multiplier.M23; + multiplier.M33 = -multiplier.M33; + multiplier.M43 = -multiplier.M43; + constant.Z = 1.0f - constant.Z; + } + + private static void InvertAlpha(ref Matrix4x4 multiplier, ref Vector4 constant) + { + multiplier.M14 = -multiplier.M14; + multiplier.M24 = -multiplier.M24; + multiplier.M34 = -multiplier.M34; + multiplier.M44 = -multiplier.M44; + constant.W = 1.0f - constant.W; + } +} diff --git a/Penumbra/Import/Textures/RgbaPixelData.cs b/Penumbra/Import/Textures/RgbaPixelData.cs new file mode 100644 index 00000000..0314b104 --- /dev/null +++ b/Penumbra/Import/Textures/RgbaPixelData.cs @@ -0,0 +1,43 @@ +using System; +using SixLabors.ImageSharp; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing; + +namespace Penumbra.Import.Textures; + +public readonly record struct RgbaPixelData(int Width, int Height, byte[] PixelData) +{ + public static readonly RgbaPixelData Empty = new(0, 0, Array.Empty()); + + public (int Width, int Height) Size + => (Width, Height); + + public RgbaPixelData((int Width, int Height) size, byte[] pixelData) + : this(size.Width, size.Height, pixelData) + { + } + + public Image ToImage() + => Image.LoadPixelData(PixelData, Width, Height); + + public RgbaPixelData Resize((int Width, int Height) size) + { + if (Width == size.Width && Height == size.Height) + return this; + + var result = new RgbaPixelData(size, NewPixelData(size)); + using (var image = ToImage()) + { + image.Mutate(ctx => ctx.Resize(size.Width, size.Height, KnownResamplers.Lanczos3)); + image.CopyPixelDataTo(result.PixelData); + } + + return result; + } + + public static byte[] NewPixelData((int Width, int Height) size) + => new byte[size.Width * size.Height * 4]; + + public static RgbaPixelData FromTexture(Texture texture) + => new(texture.TextureWrap!.Width, texture.TextureWrap!.Height, texture.RgbaPixels); +}