Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Material editor adjustments #329

Merged
merged 4 commits into from
Sep 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 11 additions & 26 deletions Penumbra/Interop/MaterialPreview/LiveColorSetPreviewer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using FFXIVClientStructs.FFXIV.Client.Graphics.Kernel;
using FFXIVClientStructs.FFXIV.Client.Graphics.Render;
using Penumbra.GameData.Files;
using Penumbra.Interop.SafeHandles;

namespace Penumbra.Interop.MaterialPreview;

Expand All @@ -16,8 +17,8 @@ public sealed unsafe class LiveColorSetPreviewer : LiveMaterialPreviewerBase

private readonly Framework _framework;

private readonly Texture** _colorSetTexture;
private readonly Texture* _originalColorSetTexture;
private readonly Texture** _colorSetTexture;
private readonly SafeTextureHandle _originalColorSetTexture;

private Half[] _colorSet;
private bool _updatePending;
Expand All @@ -40,12 +41,10 @@ public LiveColorSetPreviewer(IObjectTable objects, Framework framework, Material

_colorSetTexture = colorSetTextures + (MaterialInfo.ModelSlot * 4 + MaterialInfo.MaterialSlot);

_originalColorSetTexture = *_colorSetTexture;
_originalColorSetTexture = new SafeTextureHandle(*_colorSetTexture, true);
if (_originalColorSetTexture == null)
throw new InvalidOperationException("Material doesn't have a color set");

Structs.TextureUtility.IncRef(_originalColorSetTexture);

_colorSet = new Half[TextureLength];
_updatePending = true;

Expand All @@ -59,15 +58,9 @@ protected override void Clear(bool disposing, bool reset)
base.Clear(disposing, reset);

if (reset)
{
var oldTexture = (Texture*)Interlocked.Exchange(ref *(nint*)_colorSetTexture, (nint)_originalColorSetTexture);
if (oldTexture != null)
Structs.TextureUtility.DecRef(oldTexture);
}
else
{
Structs.TextureUtility.DecRef(_originalColorSetTexture);
}
_originalColorSetTexture.Exchange(ref *(nint*)_colorSetTexture);

_originalColorSetTexture.Dispose();
}

public void ScheduleUpdate()
Expand All @@ -89,29 +82,21 @@ private void OnFrameworkUpdate(Framework _)
textureSize[0] = TextureWidth;
textureSize[1] = TextureHeight;

var newTexture = Structs.TextureUtility.Create2D(Device.Instance(), textureSize, 1, 0x2460, 0x80000804, 7);
if (newTexture == null)
using var texture = new SafeTextureHandle(Structs.TextureUtility.Create2D(Device.Instance(), textureSize, 1, 0x2460, 0x80000804, 7), false);
if (texture.IsInvalid)
return;

bool success;
lock (_colorSet)
{
fixed (Half* colorSet = _colorSet)
{
success = Structs.TextureUtility.InitializeContents(newTexture, colorSet);
success = Structs.TextureUtility.InitializeContents(texture.Texture, colorSet);
}
}

if (success)
{
var oldTexture = (Texture*)Interlocked.Exchange(ref *(nint*)_colorSetTexture, (nint)newTexture);
if (oldTexture != null)
Structs.TextureUtility.DecRef(oldTexture);
}
else
{
Structs.TextureUtility.DecRef(newTexture);
}
texture.Exchange(ref *(nint*)_colorSetTexture);
}

protected override bool IsStillValid()
Expand Down
48 changes: 48 additions & 0 deletions Penumbra/Interop/SafeHandles/SafeTextureHandle.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
using System;
using System.Runtime.InteropServices;
using System.Threading;
using FFXIVClientStructs.FFXIV.Client.Graphics.Render;
using Penumbra.Interop.Structs;

namespace Penumbra.Interop.SafeHandles;

public unsafe class SafeTextureHandle : SafeHandle
{
public Texture* Texture => (Texture*)handle;

public override bool IsInvalid => handle == 0;

public SafeTextureHandle(Texture* handle, bool incRef, bool ownsHandle = true) : base(0, ownsHandle)
{
if (incRef && !ownsHandle)
throw new ArgumentException("Non-owning SafeTextureHandle with IncRef is unsupported");
if (incRef && handle != null)
TextureUtility.IncRef(handle);
SetHandle((nint)handle);
}

public void Exchange(ref nint ppTexture)
{
lock (this)
{
handle = Interlocked.Exchange(ref ppTexture, handle);
}
}

public static SafeTextureHandle CreateInvalid()
=> new(null, incRef: false);

protected override bool ReleaseHandle()
{
nint handle;
lock (this)
{
handle = this.handle;
this.handle = 0;
}
if (handle != 0)
TextureUtility.DecRef((Texture*)handle);

return true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public partial class ModEditWindow
{
private interface IConstantEditor
{
bool Draw(Span<float> values, bool disabled, float editorWidth);
bool Draw(Span<float> values, bool disabled);
}

private sealed class FloatConstantEditor : IConstantEditor
Expand Down Expand Up @@ -42,16 +42,18 @@ public FloatConstantEditor(float? minimum, float? maximum, float speed, float re
_format = $"{_format} {unit.Replace("%", "%%")}";
}

public bool Draw(Span<float> values, bool disabled, float editorWidth)
public bool Draw(Span<float> values, bool disabled)
{
var fieldWidth = (editorWidth - (values.Length - 1) * ImGui.GetStyle().ItemSpacing.X) / values.Length;
var spacing = ImGui.GetStyle().ItemInnerSpacing.X;
var fieldWidth = (ImGui.CalcItemWidth() - (values.Length - 1) * spacing) / values.Length;

var ret = false;

// Not using DragScalarN because of _relativeSpeed and other points of lost flexibility.
for (var valueIdx = 0; valueIdx < values.Length; ++valueIdx)
{
if (valueIdx > 0)
ImGui.SameLine();
ImGui.SameLine(0.0f, spacing);

ImGui.SetNextItemWidth(MathF.Round(fieldWidth * (valueIdx + 1)) - MathF.Round(fieldWidth * valueIdx));

Expand Down Expand Up @@ -101,16 +103,18 @@ public IntConstantEditor(int? minimum, int? maximum, float speed, float relative
_format = $"{_format} {unit.Replace("%", "%%")}";
}

public bool Draw(Span<float> values, bool disabled, float editorWidth)
public bool Draw(Span<float> values, bool disabled)
{
var fieldWidth = (editorWidth - (values.Length - 1) * ImGui.GetStyle().ItemSpacing.X) / values.Length;
var spacing = ImGui.GetStyle().ItemInnerSpacing.X;
var fieldWidth = (ImGui.CalcItemWidth() - (values.Length - 1) * spacing) / values.Length;

var ret = false;

// Not using DragScalarN because of _relativeSpeed and other points of lost flexibility.
for (var valueIdx = 0; valueIdx < values.Length; ++valueIdx)
{
if (valueIdx > 0)
ImGui.SameLine();
ImGui.SameLine(0.0f, spacing);

ImGui.SetNextItemWidth(MathF.Round(fieldWidth * (valueIdx + 1)) - MathF.Round(fieldWidth * valueIdx));

Expand Down Expand Up @@ -148,13 +152,12 @@ public ColorConstantEditor(bool squaredRgb, bool clamped)
_clamped = clamped;
}

public bool Draw(Span<float> values, bool disabled, float editorWidth)
public bool Draw(Span<float> values, bool disabled)
{
switch (values.Length)
{
case 3:
{
ImGui.SetNextItemWidth(editorWidth);
var value = new Vector3(values);
if (_squaredRgb)
value = PseudoSqrtRgb(value);
Expand All @@ -170,7 +173,6 @@ public bool Draw(Span<float> values, bool disabled, float editorWidth)
}
case 4:
{
ImGui.SetNextItemWidth(editorWidth);
var value = new Vector4(values);
if (_squaredRgb)
value = PseudoSqrtRgb(value);
Expand All @@ -186,7 +188,7 @@ public bool Draw(Span<float> values, bool disabled, float editorWidth)
value.CopyTo(values);
return true;
}
default: return FloatConstantEditor.Default.Draw(values, disabled, editorWidth);
default: return FloatConstantEditor.Default.Draw(values, disabled);
}
}
}
Expand All @@ -198,17 +200,18 @@ private sealed class EnumConstantEditor : IConstantEditor
public EnumConstantEditor(IReadOnlyList<(string Label, float Value, string Description)> values)
=> _values = values;

public bool Draw(Span<float> values, bool disabled, float editorWidth)
public bool Draw(Span<float> values, bool disabled)
{
var fieldWidth = (editorWidth - (values.Length - 1) * ImGui.GetStyle().ItemSpacing.X) / values.Length;
var spacing = ImGui.GetStyle().ItemInnerSpacing.X;
var fieldWidth = (ImGui.CalcItemWidth() - (values.Length - 1) * spacing) / values.Length;

var ret = false;

for (var valueIdx = 0; valueIdx < values.Length; ++valueIdx)
{
using var id = ImRaii.PushId(valueIdx);
if (valueIdx > 0)
ImGui.SameLine();
ImGui.SameLine(0.0f, spacing);

ImGui.SetNextItemWidth(MathF.Round(fieldWidth * (valueIdx + 1)) - MathF.Round(fieldWidth * valueIdx));

Expand Down
10 changes: 6 additions & 4 deletions Penumbra/UI/AdvancedWindow/ModEditWindow.Materials.MtrlTab.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
using Penumbra.Interop.MaterialPreview;
using Penumbra.String;
using Penumbra.String.Classes;
using Penumbra.UI.Classes;
using static Penumbra.GameData.Files.ShpkFile;

namespace Penumbra.UI.AdvancedWindow;
Expand Down Expand Up @@ -177,7 +178,7 @@ public void LoadShpk(FullPath path)

if (mayVary && (data as JObject)?["Vary"] != null)
{
var selector = BuildSelector(data["Vary"]!
var selector = BuildSelector(data!["Vary"]!
.Select(key => (uint)key)
.Select(key => Mtrl.GetShaderKey(key)?.Value ?? AssociatedShpk!.GetMaterialKeyById(key)!.Value.DefaultValue));
var index = (int)data["Selectors"]![selector.ToString()]!;
Expand Down Expand Up @@ -668,12 +669,13 @@ public void UpdateColorSetPreview()

private static void ApplyHighlight(ref MtrlFile.ColorSet.Row row, float time)
{
var level = Math.Sin(time * 2.0 * Math.PI) * 0.25 + 0.5;
var levelSq = (float)(level * level);
var level = (MathF.Sin(time * 2.0f * MathF.PI) + 2.0f) / 3.0f / 255.0f;
var baseColor = ColorId.InGameHighlight.Value();
var color = level * new Vector3(baseColor & 0xFF, (baseColor >> 8) & 0xFF, (baseColor >> 16) & 0xFF);

row.Diffuse = Vector3.Zero;
row.Specular = Vector3.Zero;
row.Emissive = new Vector3(levelSq);
row.Emissive = color * color;
}

public void Update()
Expand Down
3 changes: 2 additions & 1 deletion Penumbra/UI/AdvancedWindow/ModEditWindow.Materials.Shpk.cs
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,8 @@ private static bool DrawMaterialConstants(MtrlTab tab, bool disabled)
if (buffer.Length > 0)
{
using var id = ImRaii.PushId($"##{constant.Id:X8}:{slice.Start}");
if (editor.Draw(buffer[slice], disabled, 250.0f))
ImGui.SetNextItemWidth(250.0f);
if (editor.Draw(buffer[slice], disabled))
{
ret = true;
tab.SetMaterialParameter(constant.Id, slice.Start, buffer[slice]);
Expand Down
4 changes: 3 additions & 1 deletion Penumbra/UI/Classes/Colors.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ public enum ColorId
RedundantAssignment,
NoModsAssignment,
NoAssignment,
SelectorPriority,
SelectorPriority,
InGameHighlight,
}

public static class Colors
Expand Down Expand Up @@ -64,6 +65,7 @@ public static (uint DefaultColor, string Name, string Description) Data(this Col
ColorId.NoModsAssignment => ( 0x50000080, "'Use No Mods' Collection Assignment", "A collection assignment set to not use any mods at all."),
ColorId.NoAssignment => ( 0x00000000, "Unassigned Collection Assignment", "A collection assignment that is not configured to any collection and thus just has no specific treatment."),
ColorId.SelectorPriority => ( 0xFF808080, "Mod Selector Priority", "The priority displayed for non-zero priority mods in the mod selector."),
ColorId.InGameHighlight => ( 0xFFEBCF89, "In-Game Highlight", "An in-game element that has been highlighted for ease of editing."),
_ => throw new ArgumentOutOfRangeException( nameof( color ), color, null ),
// @formatter:on
};
Expand Down