Add state editing and tracking.

This commit is contained in:
Ottermandias 2024-02-01 13:52:20 +01:00
parent 5cdcb9288e
commit fb7aac5228
10 changed files with 383 additions and 235 deletions

View file

@ -2,6 +2,7 @@
using Glamourer.Designs;
using Glamourer.Events;
using Glamourer.GameData;
using Glamourer.Interop.Material;
using Glamourer.Services;
using Penumbra.GameData.DataContainers;
using Penumbra.GameData.Enums;
@ -220,6 +221,39 @@ public class InternalStateEditor(
return true;
}
/// <summary> Change the value of a single material color table entry. </summary>
public bool ChangeMaterialValue(ActorState state, MaterialValueIndex index, Vector3 value, Vector3 gameValue, StateSource source, out Vector3 oldValue,
uint key = 0)
{
// We already have an existing value.
if (state.Materials.TryGetValue(index, out var old))
{
oldValue = old.Model;
if (!state.CanUnlock(key))
return false;
// Remove if overwritten by a game value.
if (source is StateSource.Game)
{
state.Materials.RemoveValue(index);
return true;
}
// Update if edited.
state.Materials.UpdateValue(index, new MaterialValueState(gameValue, value, source), out _);
return true;
}
// We do not have an existing value.
oldValue = gameValue;
// Do not do anything if locked or if the game value updates, because then we do not need to add an entry.
if (!state.CanUnlock(key) || source is StateSource.Game)
return false;
// Only add an entry if it is sufficiently different from the game value.
return !value.NearEqual(gameValue) && state.Materials.TryAddValue(index, new MaterialValueState(gameValue, value, source));
}
public bool ChangeMetaState(ActorState state, MetaIndex index, bool value, StateSource source, out bool oldValue,
uint key = 0)
{

View file

@ -1,6 +1,7 @@
using Glamourer.Designs;
using Glamourer.GameData;
using Glamourer.Interop;
using Glamourer.Interop.Material;
using Glamourer.Interop.Penumbra;
using Glamourer.Interop.Structs;
using Glamourer.Services;
@ -275,6 +276,41 @@ public class StateApplier(
return data;
}
public unsafe void ChangeMaterialValue(ActorData data, MaterialValueIndex index, Vector3? value, bool force)
{
if (!force && !_config.UseAdvancedParameters)
return;
foreach (var actor in data.Objects.Where(a => a is { IsCharacter: true, Model.IsHuman: true }))
{
if (!index.TryGetTexture(actor, out var texture))
continue;
if (!index.TryGetColorTable(texture, out var table))
continue;
Vector3 actualValue;
if (value.HasValue)
actualValue = value.Value;
else if (!PrepareColorSet.TryGetColorTable(actor, index, out var baseTable)
|| !index.DataIndex.TryGetValue(baseTable[index.RowIndex], out actualValue))
continue;
if (!index.DataIndex.SetValue(ref table[index.RowIndex], actualValue))
continue;
MaterialService.ReplaceColorTable(texture, table);
}
}
public ActorData ChangeMaterialValue(ActorState state, MaterialValueIndex index, bool apply)
{
var data = GetData(state);
if (apply)
ChangeMaterialValue(data, index, state.Materials.TryGetValue(index, out var v) ? v.Model : null, state.IsLocked);
return data;
}
/// <summary> Apply the entire state of an actor to all relevant actors, either via immediate redraw or piecewise. </summary>
/// <param name="state"> The state to apply. </param>
/// <param name="redraw"> Whether a redraw should be forced. </param>

View file

@ -2,6 +2,7 @@ using Glamourer.Designs;
using Glamourer.Designs.Links;
using Glamourer.Events;
using Glamourer.GameData;
using Glamourer.Interop.Material;
using Glamourer.Interop.Penumbra;
using Glamourer.Interop.Structs;
using Glamourer.Services;
@ -149,9 +150,7 @@ public class StateEditor(
/// <inheritdoc/>
public void ChangeCustomizeParameter(object data, CustomizeParameterFlag flag, CustomizeParameterValue value, ApplySettings settings)
{
if (data is not ActorState state)
return;
var state = (ActorState)data;
// Also apply main color to highlights when highlights is off.
if (!state.ModelData.Customize.Highlights && flag is CustomizeParameterFlag.HairDiffuse)
ChangeCustomizeParameter(state, CustomizeParameterFlag.HairHighlight, value, settings);
@ -166,6 +165,17 @@ public class StateEditor(
StateChanged.Invoke(StateChanged.Type.Parameter, settings.Source, state, actors, (old, @new, flag));
}
public void ChangeMaterialValue(object data, MaterialValueIndex index, Vector3 value, Vector3 gameValue, ApplySettings settings)
{
var state = (ActorState)data;
if (!Editor.ChangeMaterialValue(state, index, value, gameValue, settings.Source, out var oldValue, settings.Key))
return;
var actors = Applier.ChangeMaterialValue(state, index, settings.Source.RequiresChange());
Glamourer.Log.Verbose($"Set material value in state {state.Identifier.Incognito(null)} from {oldValue} to {value}. [Affecting {actors.ToLazyString("nothing")}.]");
StateChanged.Invoke(StateChanged.Type.MaterialValue, settings.Source, state, actors, (oldValue, value, index));
}
/// <inheritdoc/>
public void ChangeMetaState(object data, MetaIndex index, bool value, ApplySettings settings)
{