mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-12 18:27:24 +01:00
Slight restructuring.
This commit is contained in:
parent
38a22c5298
commit
600f5987cd
3 changed files with 219 additions and 204 deletions
|
|
@ -8,81 +8,12 @@ using OtterGui;
|
||||||
using SixLabors.ImageSharp.PixelFormats;
|
using SixLabors.ImageSharp.PixelFormats;
|
||||||
using Dalamud.Interface;
|
using Dalamud.Interface;
|
||||||
using Penumbra.UI;
|
using Penumbra.UI;
|
||||||
using SixLabors.ImageSharp;
|
|
||||||
using SixLabors.ImageSharp.Processing;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
namespace Penumbra.Import.Textures;
|
namespace Penumbra.Import.Textures;
|
||||||
|
|
||||||
public partial class CombinedTexture
|
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<byte>());
|
|
||||||
|
|
||||||
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<Rgba32> ToImage()
|
|
||||||
=> Image.LoadPixelData<Rgba32>(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 Matrix4x4 _multiplierLeft = Matrix4x4.Identity;
|
||||||
private Vector4 _constantLeft = Vector4.Zero;
|
private Vector4 _constantLeft = Vector4.Zero;
|
||||||
private Matrix4x4 _multiplierRight = Matrix4x4.Identity;
|
private Matrix4x4 _multiplierRight = Matrix4x4.Identity;
|
||||||
|
|
@ -96,42 +27,6 @@ public partial class CombinedTexture
|
||||||
private RgbaPixelData _leftPixels = RgbaPixelData.Empty;
|
private RgbaPixelData _leftPixels = RgbaPixelData.Empty;
|
||||||
private RgbaPixelData _rightPixels = RgbaPixelData.Empty;
|
private RgbaPixelData _rightPixels = RgbaPixelData.Empty;
|
||||||
|
|
||||||
private static readonly IReadOnlyList<string> CombineOpLabels = new string[]
|
|
||||||
{
|
|
||||||
"Overlay over Input",
|
|
||||||
"Input over Overlay",
|
|
||||||
"Replace Input",
|
|
||||||
"Copy Channels",
|
|
||||||
};
|
|
||||||
|
|
||||||
private static readonly IReadOnlyList<string> 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<string> ResizeOpLabels = new string[]
|
|
||||||
{
|
|
||||||
"No Resizing",
|
|
||||||
"Adjust Overlay to Input",
|
|
||||||
"Adjust Input to Overlay",
|
|
||||||
};
|
|
||||||
|
|
||||||
private const float OneThird = 1.0f / 3.0f;
|
private const float OneThird = 1.0f / 3.0f;
|
||||||
private const float RWeight = 0.2126f;
|
private const float RWeight = 0.2126f;
|
||||||
private const float GWeight = 0.7152f;
|
private const float GWeight = 0.7152f;
|
||||||
|
|
@ -154,32 +49,6 @@ public partial class CombinedTexture
|
||||||
};
|
};
|
||||||
// @formatter:on
|
// @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)
|
private Vector4 DataLeft(int offset)
|
||||||
=> CappedVector(_leftPixels.PixelData, offset, _multiplierLeft, _constantLeft);
|
=> CappedVector(_leftPixels.PixelData, offset, _multiplierLeft, _constantLeft);
|
||||||
|
|
||||||
|
|
@ -280,11 +149,10 @@ public partial class CombinedTexture
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private (int Width, int Height) CombineImage()
|
private (int Width, int Height) CombineImage()
|
||||||
{
|
{
|
||||||
var combineOp = GetActualCombineOp();
|
var combineOp = GetActualCombineOp();
|
||||||
var resizeOp = GetActualResizeOp(_resizeOp, combineOp);
|
var resizeOp = GetActualResizeOp(_resizeOp, combineOp);
|
||||||
|
|
||||||
var left = resizeOp != ResizeOp.RightOnly ? RgbaPixelData.FromTexture(_left) : RgbaPixelData.Empty;
|
var left = resizeOp != ResizeOp.RightOnly ? RgbaPixelData.FromTexture(_left) : RgbaPixelData.Empty;
|
||||||
var right = resizeOp != ResizeOp.LeftOnly ? RgbaPixelData.FromTexture(_right) : RgbaPixelData.Empty;
|
var right = resizeOp != ResizeOp.LeftOnly ? RgbaPixelData.FromTexture(_right) : RgbaPixelData.Empty;
|
||||||
|
|
@ -325,8 +193,8 @@ public partial class CombinedTexture
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
_leftPixels = RgbaPixelData.Empty;
|
_leftPixels = RgbaPixelData.Empty;
|
||||||
_rightPixels = RgbaPixelData.Empty;
|
_rightPixels = RgbaPixelData.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
return targetSize;
|
return targetSize;
|
||||||
|
|
@ -488,99 +356,53 @@ public partial class CombinedTexture
|
||||||
|
|
||||||
private static bool DrawMatrixTools(ref Matrix4x4 multiplier, ref Vector4 constant)
|
private static bool DrawMatrixTools(ref Matrix4x4 multiplier, ref Vector4 constant)
|
||||||
{
|
{
|
||||||
var changes = false;
|
var changes = PresetCombo(ref multiplier, ref constant);
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui.SameLine();
|
ImGui.SameLine();
|
||||||
ImGui.Dummy(ImGuiHelpers.ScaledVector2(20, 0));
|
ImGui.Dummy(ImGuiHelpers.ScaledVector2(20, 0));
|
||||||
ImGui.SameLine();
|
ImGui.SameLine();
|
||||||
ImGui.TextUnformatted("Invert");
|
ImGui.TextUnformatted("Invert");
|
||||||
ImGui.SameLine();
|
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();
|
ImGui.SameLine();
|
||||||
if (ImGui.Button("R"))
|
if (ImGui.Button("R"))
|
||||||
{
|
channels |= Channels.Red;
|
||||||
InvertRed(ref multiplier, ref constant);
|
|
||||||
changes = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui.SameLine();
|
ImGui.SameLine();
|
||||||
if (ImGui.Button("G"))
|
if (ImGui.Button("G"))
|
||||||
{
|
channels |= Channels.Green;
|
||||||
InvertGreen(ref multiplier, ref constant);
|
|
||||||
changes = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui.SameLine();
|
ImGui.SameLine();
|
||||||
if (ImGui.Button("B"))
|
if (ImGui.Button("B"))
|
||||||
{
|
channels |= Channels.Blue;
|
||||||
InvertBlue(ref multiplier, ref constant);
|
|
||||||
changes = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui.SameLine();
|
ImGui.SameLine();
|
||||||
if (ImGui.Button("A"))
|
if (ImGui.Button("A"))
|
||||||
{
|
channels |= Channels.Alpha;
|
||||||
InvertAlpha(ref multiplier, ref constant);
|
|
||||||
changes = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
changes |= InvertChannels(channels, ref multiplier, ref constant);
|
||||||
return changes;
|
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;
|
using var combo = ImRaii.Combo("Presets", string.Empty, ImGuiComboFlags.NoPreview);
|
||||||
multiplier.M21 = -multiplier.M21;
|
if (!combo)
|
||||||
multiplier.M31 = -multiplier.M31;
|
return false;
|
||||||
multiplier.M41 = -multiplier.M41;
|
|
||||||
constant.X = 1.0f - constant.X;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void InvertGreen(ref Matrix4x4 multiplier, ref Vector4 constant)
|
var ret = false;
|
||||||
{
|
foreach (var (label, preMultiplier, preConstant) in PredefinedColorTransforms)
|
||||||
multiplier.M12 = -multiplier.M12;
|
{
|
||||||
multiplier.M22 = -multiplier.M22;
|
if (!ImGui.Selectable(label, multiplier == preMultiplier && constant == preConstant))
|
||||||
multiplier.M32 = -multiplier.M32;
|
continue;
|
||||||
multiplier.M42 = -multiplier.M42;
|
|
||||||
constant.Y = 1.0f - constant.Y;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void InvertBlue(ref Matrix4x4 multiplier, ref Vector4 constant)
|
multiplier = preMultiplier;
|
||||||
{
|
constant = preConstant;
|
||||||
multiplier.M13 = -multiplier.M13;
|
ret = true;
|
||||||
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)
|
return ret;
|
||||||
{
|
|
||||||
multiplier.M14 = -multiplier.M14;
|
|
||||||
multiplier.M24 = -multiplier.M24;
|
|
||||||
multiplier.M34 = -multiplier.M34;
|
|
||||||
multiplier.M44 = -multiplier.M44;
|
|
||||||
constant.W = 1.0f - constant.W;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
150
Penumbra/Import/Textures/CombinedTexture.Operations.cs
Normal file
150
Penumbra/Import/Textures/CombinedTexture.Operations.cs
Normal file
|
|
@ -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<string> CombineOpLabels = new[]
|
||||||
|
{
|
||||||
|
"Overlay over Input",
|
||||||
|
"Input over Overlay",
|
||||||
|
"Replace Input",
|
||||||
|
"Copy Channels",
|
||||||
|
};
|
||||||
|
|
||||||
|
private static readonly IReadOnlyList<string> 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<string> 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
43
Penumbra/Import/Textures/RgbaPixelData.cs
Normal file
43
Penumbra/Import/Textures/RgbaPixelData.cs
Normal file
|
|
@ -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<byte>());
|
||||||
|
|
||||||
|
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<Rgba32> ToImage()
|
||||||
|
=> Image.LoadPixelData<Rgba32>(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);
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue