mirror of
https://github.com/Ottermandias/Glamourer.git
synced 2026-01-03 06:13:45 +01:00
Add CustomizeParameter data.
This commit is contained in:
parent
bbf460f5e0
commit
9361560350
4 changed files with 406 additions and 0 deletions
220
Glamourer/GameData/CustomizeParameterData.cs
Normal file
220
Glamourer/GameData/CustomizeParameterData.cs
Normal file
|
|
@ -0,0 +1,220 @@
|
|||
using System;
|
||||
using System.Numerics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using FFXIVClientStructs.FFXIV.Shader;
|
||||
|
||||
namespace Glamourer.GameData;
|
||||
|
||||
public struct CustomizeParameterData
|
||||
{
|
||||
public Vector3 SkinDiffuse;
|
||||
public Vector3 SkinSpecular;
|
||||
public Vector3 LipDiffuse;
|
||||
public Vector3 HairDiffuse;
|
||||
public Vector3 HairSpecular;
|
||||
public Vector3 HairHighlight;
|
||||
public Vector3 LeftEye;
|
||||
public Vector3 RightEye;
|
||||
public Vector3 FeatureColor;
|
||||
public float FacePaintUvMultiplier;
|
||||
public float FacePaintUvOffset;
|
||||
public float MuscleTone;
|
||||
public float LipOpacity;
|
||||
|
||||
public Vector3 this[CustomizeParameterFlag flag]
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
readonly get
|
||||
{
|
||||
return flag switch
|
||||
{
|
||||
CustomizeParameterFlag.SkinDiffuse => SkinDiffuse,
|
||||
CustomizeParameterFlag.MuscleTone => new Vector3(MuscleTone, 0, 0),
|
||||
CustomizeParameterFlag.SkinSpecular => SkinSpecular,
|
||||
CustomizeParameterFlag.LipDiffuse => LipDiffuse,
|
||||
CustomizeParameterFlag.LipOpacity => new Vector3(LipOpacity, 0, 0),
|
||||
CustomizeParameterFlag.HairDiffuse => HairDiffuse,
|
||||
CustomizeParameterFlag.HairSpecular => HairSpecular,
|
||||
CustomizeParameterFlag.HairHighlight => HairHighlight,
|
||||
CustomizeParameterFlag.LeftEye => LeftEye,
|
||||
CustomizeParameterFlag.RightEye => RightEye,
|
||||
CustomizeParameterFlag.FeatureColor => FeatureColor,
|
||||
CustomizeParameterFlag.FacePaintUvMultiplier => new Vector3(FacePaintUvMultiplier, 0, 0),
|
||||
CustomizeParameterFlag.FacePaintUvOffset => new Vector3(FacePaintUvOffset, 0, 0),
|
||||
_ => Vector3.Zero,
|
||||
};
|
||||
}
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
set => Set(flag, value);
|
||||
}
|
||||
|
||||
public bool Set(CustomizeParameterFlag flag, Vector3 value)
|
||||
{
|
||||
return flag switch
|
||||
{
|
||||
CustomizeParameterFlag.SkinDiffuse => SetIfDifferent(ref SkinDiffuse, value),
|
||||
CustomizeParameterFlag.MuscleTone => SetIfDifferent(ref MuscleTone, Math.Clamp(value[0], -100, 100)),
|
||||
CustomizeParameterFlag.SkinSpecular => SetIfDifferent(ref SkinSpecular, value),
|
||||
CustomizeParameterFlag.LipDiffuse => SetIfDifferent(ref LipDiffuse, value),
|
||||
CustomizeParameterFlag.LipOpacity => SetIfDifferent(ref LipOpacity, Math.Clamp(value[0], -100, 100)),
|
||||
CustomizeParameterFlag.HairDiffuse => SetIfDifferent(ref HairDiffuse, value),
|
||||
CustomizeParameterFlag.HairSpecular => SetIfDifferent(ref HairSpecular, value),
|
||||
CustomizeParameterFlag.HairHighlight => SetIfDifferent(ref HairHighlight, value),
|
||||
CustomizeParameterFlag.LeftEye => SetIfDifferent(ref LeftEye, value),
|
||||
CustomizeParameterFlag.RightEye => SetIfDifferent(ref RightEye, value),
|
||||
CustomizeParameterFlag.FeatureColor => SetIfDifferent(ref FeatureColor, value),
|
||||
CustomizeParameterFlag.FacePaintUvMultiplier => SetIfDifferent(ref FacePaintUvMultiplier, value[0]),
|
||||
CustomizeParameterFlag.FacePaintUvOffset => SetIfDifferent(ref FacePaintUvOffset, value[0]),
|
||||
_ => false,
|
||||
};
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
public readonly void Apply(ref CustomizeParameter parameters, CustomizeParameterFlag flags = CustomizeParameterExtensions.All)
|
||||
{
|
||||
if (flags.HasFlag(CustomizeParameterFlag.SkinDiffuse))
|
||||
parameters.SkinColor = Convert(SkinDiffuse, parameters.SkinColor.W);
|
||||
if (flags.HasFlag(CustomizeParameterFlag.MuscleTone))
|
||||
parameters.SkinColor.W = MuscleTone;
|
||||
if (flags.HasFlag(CustomizeParameterFlag.SkinSpecular))
|
||||
parameters.SkinFresnelValue0 = Convert(SkinSpecular, 0);
|
||||
if (flags.HasFlag(CustomizeParameterFlag.LipDiffuse))
|
||||
parameters.LipColor = Convert(LipDiffuse, parameters.LipColor.W);
|
||||
if (flags.HasFlag(CustomizeParameterFlag.LipOpacity))
|
||||
parameters.LipColor.W = LipOpacity;
|
||||
if (flags.HasFlag(CustomizeParameterFlag.HairDiffuse))
|
||||
parameters.MainColor = Convert(HairDiffuse);
|
||||
if (flags.HasFlag(CustomizeParameterFlag.HairSpecular))
|
||||
parameters.HairFresnelValue0 = Convert(HairSpecular);
|
||||
if (flags.HasFlag(CustomizeParameterFlag.HairHighlight))
|
||||
parameters.MeshColor = Convert(HairHighlight);
|
||||
if (flags.HasFlag(CustomizeParameterFlag.LeftEye))
|
||||
parameters.LeftColor = Convert(LeftEye, parameters.LeftColor.W);
|
||||
if (flags.HasFlag(CustomizeParameterFlag.RightEye))
|
||||
parameters.RightColor = Convert(RightEye, parameters.RightColor.W);
|
||||
if (flags.HasFlag(CustomizeParameterFlag.FeatureColor))
|
||||
parameters.OptionColor = Convert(FeatureColor);
|
||||
if (flags.HasFlag(CustomizeParameterFlag.FacePaintUvMultiplier))
|
||||
parameters.LeftColor.W = FacePaintUvMultiplier;
|
||||
if (flags.HasFlag(CustomizeParameterFlag.FacePaintUvOffset))
|
||||
parameters.RightColor.W = FacePaintUvOffset;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
public readonly void ApplySingle(ref CustomizeParameter parameters, CustomizeParameterFlag flag)
|
||||
{
|
||||
switch (flag)
|
||||
{
|
||||
case CustomizeParameterFlag.SkinDiffuse:
|
||||
parameters.SkinColor = Convert(SkinDiffuse, parameters.SkinColor.W);
|
||||
break;
|
||||
case CustomizeParameterFlag.MuscleTone:
|
||||
parameters.SkinColor.W = MuscleTone;
|
||||
break;
|
||||
case CustomizeParameterFlag.SkinSpecular:
|
||||
parameters.SkinFresnelValue0 = Convert(SkinSpecular, 0);
|
||||
break;
|
||||
case CustomizeParameterFlag.LipDiffuse:
|
||||
parameters.LipColor = Convert(LipDiffuse, parameters.LipColor.W);
|
||||
break;
|
||||
case CustomizeParameterFlag.LipOpacity:
|
||||
parameters.LipColor.W = LipOpacity;
|
||||
break;
|
||||
case CustomizeParameterFlag.HairDiffuse:
|
||||
parameters.MainColor = Convert(HairDiffuse);
|
||||
break;
|
||||
case CustomizeParameterFlag.HairSpecular:
|
||||
parameters.HairFresnelValue0 = Convert(HairSpecular);
|
||||
break;
|
||||
case CustomizeParameterFlag.HairHighlight:
|
||||
parameters.MeshColor = Convert(HairHighlight);
|
||||
break;
|
||||
case CustomizeParameterFlag.LeftEye:
|
||||
parameters.LeftColor = Convert(LeftEye, parameters.LeftColor.W);
|
||||
break;
|
||||
case CustomizeParameterFlag.RightEye:
|
||||
parameters.RightColor = Convert(RightEye, parameters.RightColor.W);
|
||||
break;
|
||||
case CustomizeParameterFlag.FeatureColor:
|
||||
parameters.OptionColor = Convert(FeatureColor);
|
||||
break;
|
||||
case CustomizeParameterFlag.FacePaintUvMultiplier:
|
||||
parameters.LeftColor.W = FacePaintUvMultiplier;
|
||||
break;
|
||||
case CustomizeParameterFlag.FacePaintUvOffset:
|
||||
parameters.RightColor.W = FacePaintUvOffset;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public static CustomizeParameterData FromParameters(in CustomizeParameter parameter)
|
||||
=> new()
|
||||
{
|
||||
FacePaintUvOffset = parameter.RightColor.W,
|
||||
FacePaintUvMultiplier = parameter.LeftColor.W,
|
||||
MuscleTone = parameter.SkinColor.W,
|
||||
LipOpacity = parameter.LipColor.W,
|
||||
SkinDiffuse = Convert(parameter.SkinColor),
|
||||
SkinSpecular = Convert(parameter.SkinFresnelValue0),
|
||||
LipDiffuse = Convert(parameter.LipColor),
|
||||
HairDiffuse = Convert(parameter.MainColor),
|
||||
HairSpecular = Convert(parameter.HairFresnelValue0),
|
||||
HairHighlight = Convert(parameter.MeshColor),
|
||||
LeftEye = Convert(parameter.LeftColor),
|
||||
RightEye = Convert(parameter.RightColor),
|
||||
FeatureColor = Convert(parameter.OptionColor),
|
||||
};
|
||||
|
||||
public static Vector3 FromParameter(in CustomizeParameter parameter, CustomizeParameterFlag flag)
|
||||
=> flag switch
|
||||
{
|
||||
CustomizeParameterFlag.SkinDiffuse => Convert(parameter.SkinColor),
|
||||
CustomizeParameterFlag.MuscleTone => new Vector3(parameter.SkinColor.W),
|
||||
CustomizeParameterFlag.SkinSpecular => Convert(parameter.SkinFresnelValue0),
|
||||
CustomizeParameterFlag.LipDiffuse => Convert(parameter.LipColor),
|
||||
CustomizeParameterFlag.LipOpacity => new Vector3(parameter.LipColor.W),
|
||||
CustomizeParameterFlag.HairDiffuse => Convert(parameter.MainColor),
|
||||
CustomizeParameterFlag.HairSpecular => Convert(parameter.HairFresnelValue0),
|
||||
CustomizeParameterFlag.HairHighlight => Convert(parameter.MeshColor),
|
||||
CustomizeParameterFlag.LeftEye => Convert(parameter.LeftColor),
|
||||
CustomizeParameterFlag.RightEye => Convert(parameter.RightColor),
|
||||
CustomizeParameterFlag.FeatureColor => Convert(parameter.OptionColor),
|
||||
CustomizeParameterFlag.FacePaintUvMultiplier => new Vector3(parameter.LeftColor.W),
|
||||
CustomizeParameterFlag.FacePaintUvOffset => new Vector3(parameter.RightColor.W),
|
||||
_ => Vector3.Zero,
|
||||
};
|
||||
|
||||
private static FFXIVClientStructs.FFXIV.Common.Math.Vector4 Convert(Vector3 value, float w)
|
||||
=> new(value.X * value.X, value.Y * value.Y, value.Z * value.Z, w);
|
||||
|
||||
private static Vector3 Convert(FFXIVClientStructs.FFXIV.Common.Math.Vector3 value)
|
||||
=> new((float)Math.Sqrt(value.X), (float)Math.Sqrt(value.Y), (float)Math.Sqrt(value.Z));
|
||||
|
||||
private static Vector3 Convert(FFXIVClientStructs.FFXIV.Common.Math.Vector4 value)
|
||||
=> new((float)Math.Sqrt(value.X), (float)Math.Sqrt(value.Y), (float)Math.Sqrt(value.Z));
|
||||
|
||||
private static FFXIVClientStructs.FFXIV.Common.Math.Vector3 Convert(Vector3 value)
|
||||
=> new(value.X * value.X, value.Y * value.Y, value.Z * value.Z);
|
||||
|
||||
private static bool SetIfDifferent(ref Vector3 val, Vector3 @new)
|
||||
{
|
||||
@new.X = Math.Clamp(@new.X, 0, 1);
|
||||
@new.Y = Math.Clamp(@new.Y, 0, 1);
|
||||
@new.Z = Math.Clamp(@new.Z, 0, 1);
|
||||
|
||||
if (@new == val)
|
||||
return false;
|
||||
|
||||
val = @new;
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool SetIfDifferent<T>(ref T val, T @new) where T : IEqualityOperators<T, T, bool>
|
||||
{
|
||||
if (@new == val)
|
||||
return false;
|
||||
|
||||
val = @new;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
52
Glamourer/GameData/CustomizeParameterFlag.cs
Normal file
52
Glamourer/GameData/CustomizeParameterFlag.cs
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
|
||||
namespace Glamourer.GameData;
|
||||
|
||||
[Flags]
|
||||
public enum CustomizeParameterFlag : ushort
|
||||
{
|
||||
SkinDiffuse = 0x0001,
|
||||
MuscleTone = 0x0002,
|
||||
SkinSpecular = 0x0004,
|
||||
LipDiffuse = 0x0008,
|
||||
LipOpacity = 0x0010,
|
||||
HairDiffuse = 0x0020,
|
||||
HairSpecular = 0x0040,
|
||||
HairHighlight = 0x0080,
|
||||
LeftEye = 0x0100,
|
||||
RightEye = 0x0200,
|
||||
FeatureColor = 0x0400,
|
||||
FacePaintUvMultiplier = 0x0800,
|
||||
FacePaintUvOffset = 0x1000,
|
||||
}
|
||||
|
||||
public static class CustomizeParameterExtensions
|
||||
{
|
||||
public const CustomizeParameterFlag All = (CustomizeParameterFlag)0x1FFF;
|
||||
|
||||
public const CustomizeParameterFlag Triples = All
|
||||
& ~(CustomizeParameterFlag.MuscleTone
|
||||
| CustomizeParameterFlag.LipOpacity
|
||||
| CustomizeParameterFlag.FacePaintUvOffset
|
||||
| CustomizeParameterFlag.FacePaintUvMultiplier);
|
||||
|
||||
public const CustomizeParameterFlag Percentages = CustomizeParameterFlag.MuscleTone | CustomizeParameterFlag.LipOpacity;
|
||||
public const CustomizeParameterFlag Values = CustomizeParameterFlag.FacePaintUvOffset | CustomizeParameterFlag.FacePaintUvMultiplier;
|
||||
|
||||
public static readonly IReadOnlyList<CustomizeParameterFlag> AllFlags = [.. Enum.GetValues<CustomizeParameterFlag>()];
|
||||
public static readonly IReadOnlyList<CustomizeParameterFlag> TripleFlags = AllFlags.Where(f => Triples.HasFlag(f)).ToArray();
|
||||
public static readonly IReadOnlyList<CustomizeParameterFlag> PercentageFlags = AllFlags.Where(f => Percentages.HasFlag(f)).ToArray();
|
||||
public static readonly IReadOnlyList<CustomizeParameterFlag> ValueFlags = AllFlags.Where(f => Values.HasFlag(f)).ToArray();
|
||||
|
||||
public static int Count(this CustomizeParameterFlag flag)
|
||||
=> Triples.HasFlag(flag) ? 3 : 1;
|
||||
|
||||
public static IEnumerable<CustomizeParameterFlag> Iterate(this CustomizeParameterFlag flags)
|
||||
=> AllFlags.Where(f => flags.HasFlag(f));
|
||||
|
||||
public static int ToInternalIndex(this CustomizeParameterFlag flag)
|
||||
=> BitOperations.TrailingZeroCount((uint)flag);
|
||||
}
|
||||
38
Glamourer/Gui/Customization/CustomizeParameterDrawData.cs
Normal file
38
Glamourer/Gui/Customization/CustomizeParameterDrawData.cs
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
using System;
|
||||
using System.Numerics;
|
||||
using Glamourer.Designs;
|
||||
using Glamourer.Events;
|
||||
using Glamourer.GameData;
|
||||
using Glamourer.State;
|
||||
|
||||
namespace Glamourer.Gui.Customization;
|
||||
|
||||
public ref struct CustomizeParameterDrawData(CustomizeParameterFlag flag, in DesignData data)
|
||||
{
|
||||
public readonly CustomizeParameterFlag Flag = flag;
|
||||
public bool Locked;
|
||||
public bool DisplayApplication;
|
||||
|
||||
public Action<Vector3> ValueSetter = null!;
|
||||
public Action<bool> ApplySetter = null!;
|
||||
public Vector3 CurrentValue = data.Parameters[flag];
|
||||
public bool CurrentApply;
|
||||
|
||||
public static CustomizeParameterDrawData FromDesign(DesignManager manager, Design design, CustomizeParameterFlag flag)
|
||||
=> new(flag, design.DesignData)
|
||||
{
|
||||
Locked = design.WriteProtected(),
|
||||
DisplayApplication = true,
|
||||
CurrentApply = design.DoApplyParameter(flag),
|
||||
ValueSetter = v => manager.ChangeCustomizeParameter(design, flag, v),
|
||||
ApplySetter = v => manager.ChangeApplyParameter(design, flag, v),
|
||||
};
|
||||
|
||||
public static CustomizeParameterDrawData FromState(StateManager manager, ActorState state, CustomizeParameterFlag flag)
|
||||
=> new(flag, state.ModelData)
|
||||
{
|
||||
Locked = state.IsLocked,
|
||||
DisplayApplication = false,
|
||||
ValueSetter = v => manager.ChangeCustomizeParameter(state, flag, v, StateChanged.Source.Manual),
|
||||
};
|
||||
}
|
||||
96
Glamourer/Gui/Customization/CustomizeParameterDrawer.cs
Normal file
96
Glamourer/Gui/Customization/CustomizeParameterDrawer.cs
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
using Glamourer.Designs;
|
||||
using Glamourer.GameData;
|
||||
using Glamourer.State;
|
||||
using System.Numerics;
|
||||
using Dalamud.Interface.Utility.Raii;
|
||||
using ImGuiNET;
|
||||
using OtterGui.Services;
|
||||
|
||||
namespace Glamourer.Gui.Customization;
|
||||
|
||||
public class CustomizeParameterDrawer(Configuration config) : IService
|
||||
{
|
||||
public void Draw(DesignManager designManager, Design design)
|
||||
{
|
||||
foreach (var flag in CustomizeParameterExtensions.TripleFlags)
|
||||
DrawColorInput(CustomizeParameterDrawData.FromDesign(designManager, design, flag));
|
||||
|
||||
foreach (var flag in CustomizeParameterExtensions.PercentageFlags)
|
||||
DrawPercentageInput(CustomizeParameterDrawData.FromDesign(designManager, design, flag));
|
||||
|
||||
foreach (var flag in CustomizeParameterExtensions.ValueFlags)
|
||||
DrawValueInput(CustomizeParameterDrawData.FromDesign(designManager, design, flag));
|
||||
}
|
||||
|
||||
public void Draw(StateManager stateManager, ActorState state)
|
||||
{
|
||||
foreach (var flag in CustomizeParameterExtensions.TripleFlags)
|
||||
DrawColorInput(CustomizeParameterDrawData.FromState(stateManager, state, flag));
|
||||
|
||||
foreach (var flag in CustomizeParameterExtensions.PercentageFlags)
|
||||
DrawPercentageInput(CustomizeParameterDrawData.FromState(stateManager, state, flag));
|
||||
|
||||
foreach (var flag in CustomizeParameterExtensions.ValueFlags)
|
||||
DrawValueInput(CustomizeParameterDrawData.FromState(stateManager, state, flag));
|
||||
}
|
||||
|
||||
private void DrawColorInput(in CustomizeParameterDrawData data)
|
||||
{
|
||||
using var id = ImRaii.PushId((int)data.Flag);
|
||||
var value = data.CurrentValue;
|
||||
using (_ = ImRaii.Disabled(data.Locked))
|
||||
{
|
||||
if (ImGui.ColorEdit3("##value", ref value, ImGuiColorEditFlags.Float))
|
||||
data.ValueSetter(value);
|
||||
}
|
||||
|
||||
DrawApplyAndLabel(data);
|
||||
}
|
||||
|
||||
private void DrawValueInput(in CustomizeParameterDrawData data)
|
||||
{
|
||||
using var id = ImRaii.PushId((int)data.Flag);
|
||||
var value = data.CurrentValue[0];
|
||||
|
||||
using (_ = ImRaii.Disabled(data.Locked))
|
||||
{
|
||||
if (ImGui.InputFloat("##value", ref value, 0.1f, 0.5f))
|
||||
data.ValueSetter(new Vector3(value));
|
||||
}
|
||||
|
||||
DrawApplyAndLabel(data);
|
||||
}
|
||||
|
||||
private void DrawPercentageInput(in CustomizeParameterDrawData data)
|
||||
{
|
||||
using var id = ImRaii.PushId((int)data.Flag);
|
||||
var value = data.CurrentValue[0] * 100f;
|
||||
|
||||
using (_ = ImRaii.Disabled(data.Locked))
|
||||
{
|
||||
if (ImGui.SliderFloat("##value", ref value, 0, 100, "%.2f", ImGuiSliderFlags.AlwaysClamp))
|
||||
data.ValueSetter(new Vector3(value / 100f));
|
||||
}
|
||||
|
||||
DrawApplyAndLabel(data);
|
||||
}
|
||||
|
||||
private static void DrawApply(in CustomizeParameterDrawData data)
|
||||
{
|
||||
if (UiHelpers.DrawCheckbox("##apply", "Apply this custom parameter when applying the Design.", data.CurrentApply, out var enabled,
|
||||
data.Locked))
|
||||
data.ApplySetter(enabled);
|
||||
}
|
||||
|
||||
private void DrawApplyAndLabel(in CustomizeParameterDrawData data)
|
||||
{
|
||||
if (data.DisplayApplication && !config.HideApplyCheckmarks)
|
||||
{
|
||||
ImGui.SameLine(0, ImGui.GetStyle().ItemInnerSpacing.X);
|
||||
DrawApply(data);
|
||||
}
|
||||
|
||||
ImGui.SameLine(0, ImGui.GetStyle().ItemInnerSpacing.X);
|
||||
ImGui.TextUnformatted(data.Flag.ToString());
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue