mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-12 18:27:24 +01:00
Rework Material Constants
This commit is contained in:
parent
397362caa5
commit
d175802bec
3 changed files with 279 additions and 185 deletions
|
|
@ -12,6 +12,7 @@ using Penumbra.GameData.Data;
|
|||
using Penumbra.GameData.Files;
|
||||
using Penumbra.String.Classes;
|
||||
using Penumbra.Util;
|
||||
using static Penumbra.GameData.Files.ShpkFile;
|
||||
|
||||
namespace Penumbra.UI.Classes;
|
||||
|
||||
|
|
@ -22,10 +23,11 @@ public partial class ModEditWindow
|
|||
private readonly ModEditWindow _edit;
|
||||
public readonly MtrlFile Mtrl;
|
||||
|
||||
public uint MaterialNewKeyId = 0;
|
||||
public uint MaterialNewKeyDefault = 0;
|
||||
public uint MaterialNewConstantId = 0;
|
||||
public uint MaterialNewSamplerId = 0;
|
||||
public uint MaterialNewKeyId = 0;
|
||||
public uint MaterialNewKeyDefault = 0;
|
||||
public uint MaterialNewConstantId = 0;
|
||||
public int MaterialNewConstantIdx = 0;
|
||||
public uint MaterialNewSamplerId = 0;
|
||||
|
||||
|
||||
public ShpkFile? AssociatedShpk;
|
||||
|
|
@ -42,6 +44,16 @@ public partial class ModEditWindow
|
|||
public string VertexShaders = "Vertex Shaders: ???";
|
||||
public string PixelShaders = "Pixel Shaders: ???";
|
||||
|
||||
// Material Constants
|
||||
public List< (string Name, bool ComponentOnly, int ParamValueOffset) > MaterialConstants = new(16);
|
||||
public List< (string Name, uint Id, ushort ByteSize) > MissingMaterialConstants = new(16);
|
||||
|
||||
public string MaterialConstantLabel = "Constants###Constants";
|
||||
public bool HasMalformedMaterialConstants = false;
|
||||
public IndexSet OrphanedMaterialValues = new(0, false);
|
||||
public HashSet< uint > DefinedMaterialConstants = new(16);
|
||||
public int AliasedMaterialValueCount = 0;
|
||||
|
||||
public FullPath FindAssociatedShpk( out string defaultPath, out Utf8GamePath defaultGamePath )
|
||||
{
|
||||
defaultPath = GamePaths.Shader.ShpkPath( Mtrl.ShaderPackage.Name );
|
||||
|
|
@ -137,10 +149,77 @@ public partial class ModEditWindow
|
|||
PixelShaders = $"Pixel Shaders: {( pixelShaders.Count > 0 ? string.Join( ", ", pixelShaders.Select( i => $"#{i}" ) ) : "???" )}";
|
||||
}
|
||||
|
||||
public void UpdateConstantLabels()
|
||||
{
|
||||
var prefix = AssociatedShpk?.GetConstantById( MaterialParamsConstantId )?.Name ?? string.Empty;
|
||||
MaterialConstantLabel = prefix.Length == 0 ? "Constants###Constants" : prefix + "###Constants";
|
||||
|
||||
DefinedMaterialConstants.Clear();
|
||||
MaterialConstants.Clear();
|
||||
HasMalformedMaterialConstants = false;
|
||||
AliasedMaterialValueCount = 0;
|
||||
OrphanedMaterialValues = new IndexSet( Mtrl.ShaderPackage.ShaderValues.Length, true );
|
||||
foreach( var (constant, idx) in Mtrl.ShaderPackage.Constants.WithIndex() )
|
||||
{
|
||||
DefinedMaterialConstants.Add( constant.Id );
|
||||
var values = Mtrl.GetConstantValues( constant );
|
||||
var paramValueOffset = -values.Length;
|
||||
if( values.Length > 0 )
|
||||
{
|
||||
var shpkParam = AssociatedShpk?.GetMaterialParamById( constant.Id );
|
||||
var paramByteOffset = shpkParam?.ByteOffset ?? -1;
|
||||
if( ( paramByteOffset & 0x3 ) == 0 )
|
||||
{
|
||||
paramValueOffset = paramByteOffset >> 2;
|
||||
}
|
||||
|
||||
var unique = OrphanedMaterialValues.RemoveRange( constant.ByteOffset >> 2, values.Length );
|
||||
AliasedMaterialValueCount += values.Length - unique;
|
||||
}
|
||||
else
|
||||
{
|
||||
HasMalformedMaterialConstants = true;
|
||||
}
|
||||
|
||||
var (name, componentOnly) = MaterialParamRangeName( prefix, paramValueOffset, values.Length );
|
||||
var label = name == null
|
||||
? $"#{idx:D2} (ID: 0x{constant.Id:X8})###{constant.Id}"
|
||||
: $"#{idx:D2}: {name} (ID: 0x{constant.Id:X8})###{constant.Id}";
|
||||
|
||||
MaterialConstants.Add( ( label, componentOnly, paramValueOffset ) );
|
||||
}
|
||||
|
||||
MissingMaterialConstants.Clear();
|
||||
if( AssociatedShpk != null )
|
||||
{
|
||||
var setIdx = false;
|
||||
foreach( var param in AssociatedShpk.MaterialParams.Where( m => !DefinedMaterialConstants.Contains(m.Id)) )
|
||||
{
|
||||
var (name, _) = MaterialParamRangeName( prefix, param.ByteOffset >> 2, param.ByteSize >> 2 );
|
||||
var label = name == null
|
||||
? $"(ID: 0x{param.Id:X8})"
|
||||
: $"{name} (ID: 0x{param.Id:X8})";
|
||||
if( MaterialNewConstantId == param.Id )
|
||||
{
|
||||
setIdx = true;
|
||||
MaterialNewConstantIdx = MissingMaterialConstants.Count;
|
||||
}
|
||||
MissingMaterialConstants.Add( ( label, param.Id, param.ByteSize ) );
|
||||
}
|
||||
|
||||
if (!setIdx && MissingMaterialConstants.Count > 0)
|
||||
{
|
||||
MaterialNewConstantIdx = 0;
|
||||
MaterialNewConstantId = MissingMaterialConstants[ 0 ].Id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
UpdateTextureLabels();
|
||||
UpdateShaderKeyLabels();
|
||||
UpdateConstantLabels();
|
||||
}
|
||||
|
||||
public MtrlTab( ModEditWindow edit, MtrlFile file )
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using System.Text;
|
||||
using Dalamud.Interface;
|
||||
using Dalamud.Interface.ImGuiFileDialog;
|
||||
using ImGuiNET;
|
||||
|
|
@ -106,7 +107,7 @@ public partial class ModEditWindow
|
|||
}
|
||||
|
||||
|
||||
private static bool DrawShaderKey( MtrlTab tab, bool disabled, ShaderKey key, int idx )
|
||||
private static bool DrawShaderKey( MtrlTab tab, bool disabled, ref int idx )
|
||||
{
|
||||
var ret = false;
|
||||
using var t2 = ImRaii.TreeNode( tab.ShaderKeyLabels[ idx ], disabled ? ImGuiTreeNodeFlags.Leaf : 0 );
|
||||
|
|
@ -115,6 +116,7 @@ public partial class ModEditWindow
|
|||
return ret;
|
||||
}
|
||||
|
||||
var key = tab.Mtrl.ShaderPackage.ShaderKeys[ idx ];
|
||||
var shpkKey = tab.AssociatedShpk?.GetMaterialKeyById( key.Category );
|
||||
if( shpkKey.HasValue )
|
||||
{
|
||||
|
|
@ -128,6 +130,7 @@ public partial class ModEditWindow
|
|||
{
|
||||
tab.Mtrl.ShaderPackage.ShaderKeys[ idx ].Value = value;
|
||||
ret = true;
|
||||
tab.UpdateShaderKeyLabels();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -135,8 +138,9 @@ public partial class ModEditWindow
|
|||
|
||||
if( ImGui.Button( "Remove Key" ) )
|
||||
{
|
||||
tab.Mtrl.ShaderPackage.ShaderKeys = tab.Mtrl.ShaderPackage.ShaderKeys.RemoveItems( idx );
|
||||
tab.Mtrl.ShaderPackage.ShaderKeys = tab.Mtrl.ShaderPackage.ShaderKeys.RemoveItems( idx-- );
|
||||
ret = true;
|
||||
tab.UpdateShaderKeyLabels();
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
|
@ -145,6 +149,7 @@ public partial class ModEditWindow
|
|||
private static bool DrawNewShaderKey( MtrlTab tab )
|
||||
{
|
||||
ImGui.SetNextItemWidth( ImGuiHelpers.GlobalScale * 150.0f );
|
||||
var ret = false;
|
||||
using( var c = ImRaii.Combo( "##NewConstantId", $"ID: 0x{tab.MaterialNewKeyId:X8}" ) )
|
||||
{
|
||||
if( c )
|
||||
|
|
@ -157,6 +162,8 @@ public partial class ModEditWindow
|
|||
{
|
||||
tab.MaterialNewKeyDefault = key.DefaultValue;
|
||||
tab.MaterialNewKeyId = key.Id;
|
||||
ret = true;
|
||||
tab.UpdateShaderKeyLabels();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -170,10 +177,11 @@ public partial class ModEditWindow
|
|||
Category = tab.MaterialNewKeyId,
|
||||
Value = tab.MaterialNewKeyDefault,
|
||||
} );
|
||||
return true;
|
||||
ret = true;
|
||||
tab.UpdateShaderKeyLabels();
|
||||
}
|
||||
|
||||
return false;
|
||||
return ret;
|
||||
}
|
||||
|
||||
private static bool DrawMaterialShaderKeys( MtrlTab tab, bool disabled )
|
||||
|
|
@ -190,9 +198,9 @@ public partial class ModEditWindow
|
|||
}
|
||||
|
||||
var ret = false;
|
||||
foreach( var (key, idx) in tab.Mtrl.ShaderPackage.ShaderKeys.WithIndex() )
|
||||
for( var idx = 0; idx < tab.Mtrl.ShaderPackage.ShaderKeys.Length; ++idx )
|
||||
{
|
||||
ret |= DrawShaderKey( tab, disabled, key, idx );
|
||||
ret |= DrawShaderKey( tab, disabled, ref idx );
|
||||
}
|
||||
|
||||
if( !disabled && tab.AssociatedShpk != null && tab.MissingShaderKeyIndices.Count != 0 )
|
||||
|
|
@ -200,15 +208,9 @@ public partial class ModEditWindow
|
|||
ret |= DrawNewShaderKey( tab );
|
||||
}
|
||||
|
||||
if( ret )
|
||||
{
|
||||
tab.UpdateShaderKeyLabels();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
private static void DrawMaterialShaders( MtrlTab tab )
|
||||
{
|
||||
if( tab.AssociatedShpk == null )
|
||||
|
|
@ -220,170 +222,164 @@ public partial class ModEditWindow
|
|||
ImRaii.TreeNode( tab.PixelShaders, ImGuiTreeNodeFlags.Leaf ).Dispose();
|
||||
}
|
||||
|
||||
private bool DrawMaterialConstants( MtrlTab tab, bool disabled )
|
||||
|
||||
private static bool DrawMaterialConstantValues( MtrlTab tab, bool disabled, ref int idx )
|
||||
{
|
||||
var ret = false;
|
||||
if( tab.Mtrl.ShaderPackage.Constants.Length <= 0
|
||||
&& tab.Mtrl.ShaderPackage.ShaderValues.Length <= 0
|
||||
&& ( disabled || tab.AssociatedShpk == null || tab.AssociatedShpk.Constants.Length <= 0 ) )
|
||||
var (name, componentOnly, paramValueOffset) = tab.MaterialConstants[ idx ];
|
||||
using var font = ImRaii.PushFont( UiBuilder.MonoFont );
|
||||
using var t2 = ImRaii.TreeNode( name );
|
||||
if( !t2 )
|
||||
{
|
||||
return ret;
|
||||
return false;
|
||||
}
|
||||
|
||||
var materialParams = tab.AssociatedShpk?.GetConstantById( ShpkFile.MaterialParamsConstantId );
|
||||
font.Dispose();
|
||||
|
||||
using var t = ImRaii.TreeNode( materialParams?.Name ?? "Constants" );
|
||||
if( t )
|
||||
var constant = tab.Mtrl.ShaderPackage.Constants[ idx ];
|
||||
var ret = false;
|
||||
var values = tab.Mtrl.GetConstantValues( constant );
|
||||
if( values.Length > 0 )
|
||||
{
|
||||
var orphanValues = new IndexSet( tab.Mtrl.ShaderPackage.ShaderValues.Length, true );
|
||||
var aliasedValueCount = 0;
|
||||
var definedConstants = new HashSet< uint >();
|
||||
var hasMalformedConstants = false;
|
||||
var valueOffset = constant.ByteOffset >> 2;
|
||||
|
||||
foreach( var constant in tab.Mtrl.ShaderPackage.Constants )
|
||||
for( var valueIdx = 0; valueIdx < values.Length; ++valueIdx )
|
||||
{
|
||||
definedConstants.Add( constant.Id );
|
||||
var values = tab.Mtrl.GetConstantValues( constant );
|
||||
if( tab.Mtrl.GetConstantValues( constant ).Length > 0 )
|
||||
var paramName = MaterialParamName( componentOnly, paramValueOffset + valueIdx ) ?? $"#{valueIdx}";
|
||||
ImGui.SetNextItemWidth( ImGuiHelpers.GlobalScale * 150.0f );
|
||||
if( ImGui.InputFloat( $"{paramName} (at 0x{( valueOffset + valueIdx ) << 2:X4})", ref values[ valueIdx ], 0.0f, 0.0f, "%.3f",
|
||||
disabled ? ImGuiInputTextFlags.ReadOnly : ImGuiInputTextFlags.None ) )
|
||||
{
|
||||
var unique = orphanValues.RemoveRange( constant.ByteOffset >> 2, values.Length );
|
||||
aliasedValueCount += values.Length - unique;
|
||||
ret = true;
|
||||
tab.UpdateConstantLabels();
|
||||
}
|
||||
else
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ImRaii.TreeNode( $"Offset: 0x{constant.ByteOffset:X4}", ImGuiTreeNodeFlags.Leaf ).Dispose();
|
||||
ImRaii.TreeNode( $"Size: 0x{constant.ByteSize:X4}", ImGuiTreeNodeFlags.Leaf ).Dispose();
|
||||
}
|
||||
|
||||
if( !disabled
|
||||
&& !tab.HasMalformedMaterialConstants
|
||||
&& tab.OrphanedMaterialValues.Count == 0
|
||||
&& tab.AliasedMaterialValueCount == 0
|
||||
&& ImGui.Button( "Remove Constant" ) )
|
||||
{
|
||||
tab.Mtrl.ShaderPackage.ShaderValues = tab.Mtrl.ShaderPackage.ShaderValues.RemoveItems( constant.ByteOffset >> 2, constant.ByteSize >> 2 );
|
||||
tab.Mtrl.ShaderPackage.Constants = tab.Mtrl.ShaderPackage.Constants.RemoveItems( idx-- );
|
||||
for( var i = 0; i < tab.Mtrl.ShaderPackage.Constants.Length; ++i )
|
||||
{
|
||||
if( tab.Mtrl.ShaderPackage.Constants[ i ].ByteOffset >= constant.ByteOffset )
|
||||
{
|
||||
hasMalformedConstants = true;
|
||||
tab.Mtrl.ShaderPackage.Constants[ i ].ByteOffset -= constant.ByteSize;
|
||||
}
|
||||
}
|
||||
|
||||
foreach( var (constant, idx) in tab.Mtrl.ShaderPackage.Constants.WithIndex() )
|
||||
ret = true;
|
||||
tab.UpdateConstantLabels();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
private static bool DrawMaterialOrphans( MtrlTab tab, bool disabled )
|
||||
{
|
||||
using var t2 = ImRaii.TreeNode( $"Orphan Values ({tab.OrphanedMaterialValues.Count})" );
|
||||
if( !t2 )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var ret = false;
|
||||
foreach( var idx in tab.OrphanedMaterialValues )
|
||||
{
|
||||
ImGui.SetNextItemWidth( ImGui.GetFontSize() * 10.0f );
|
||||
if( ImGui.InputFloat( $"#{idx} (at 0x{idx << 2:X4})",
|
||||
ref tab.Mtrl.ShaderPackage.ShaderValues[ idx ], 0.0f, 0.0f, "%.3f",
|
||||
disabled ? ImGuiInputTextFlags.ReadOnly : ImGuiInputTextFlags.None ) )
|
||||
{
|
||||
var values = tab.Mtrl.GetConstantValues( constant );
|
||||
var paramValueOffset = -values.Length;
|
||||
if( values.Length > 0 )
|
||||
{
|
||||
var shpkParam = tab.AssociatedShpk?.GetMaterialParamById( constant.Id );
|
||||
var paramByteOffset = shpkParam.HasValue ? shpkParam.Value.ByteOffset : -1;
|
||||
if( ( paramByteOffset & 0x3 ) == 0 )
|
||||
{
|
||||
paramValueOffset = paramByteOffset >> 2;
|
||||
}
|
||||
}
|
||||
|
||||
var (constantName, componentOnly) = MaterialParamRangeName( materialParams?.Name ?? "", paramValueOffset, values.Length );
|
||||
|
||||
using var t2 = ImRaii.TreeNode( $"#{idx}{( constantName != null ? ": " + constantName : "" )} (ID: 0x{constant.Id:X8})" );
|
||||
if( t2 )
|
||||
{
|
||||
if( values.Length > 0 )
|
||||
{
|
||||
var valueOffset = constant.ByteOffset >> 2;
|
||||
|
||||
for( var valueIdx = 0; valueIdx < values.Length; ++valueIdx )
|
||||
{
|
||||
ImGui.SetNextItemWidth( ImGuiHelpers.GlobalScale * 150.0f );
|
||||
if( ImGui.InputFloat(
|
||||
$"{MaterialParamName( componentOnly, paramValueOffset + valueIdx ) ?? $"#{valueIdx}"} (at 0x{( valueOffset + valueIdx ) << 2:X4})",
|
||||
ref values[ valueIdx ], 0.0f, 0.0f, "%.3f",
|
||||
disabled ? ImGuiInputTextFlags.ReadOnly : ImGuiInputTextFlags.None ) )
|
||||
{
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ImRaii.TreeNode( $"Offset: 0x{constant.ByteOffset:X4}", ImGuiTreeNodeFlags.Leaf ).Dispose();
|
||||
ImRaii.TreeNode( $"Size: 0x{constant.ByteSize:X4}", ImGuiTreeNodeFlags.Leaf ).Dispose();
|
||||
}
|
||||
|
||||
if( !disabled
|
||||
&& !hasMalformedConstants
|
||||
&& orphanValues.Count == 0
|
||||
&& aliasedValueCount == 0
|
||||
&& ImGui.Button( "Remove Constant" ) )
|
||||
{
|
||||
tab.Mtrl.ShaderPackage.ShaderValues = tab.Mtrl.ShaderPackage.ShaderValues.RemoveItems( constant.ByteOffset >> 2, constant.ByteSize >> 2 );
|
||||
tab.Mtrl.ShaderPackage.Constants = tab.Mtrl.ShaderPackage.Constants.RemoveItems( idx );
|
||||
for( var i = 0; i < tab.Mtrl.ShaderPackage.Constants.Length; ++i )
|
||||
{
|
||||
if( tab.Mtrl.ShaderPackage.Constants[ i ].ByteOffset >= constant.ByteOffset )
|
||||
{
|
||||
tab.Mtrl.ShaderPackage.Constants[ i ].ByteOffset -= constant.ByteSize;
|
||||
}
|
||||
}
|
||||
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( orphanValues.Count > 0 )
|
||||
{
|
||||
using var t2 = ImRaii.TreeNode( $"Orphan Values ({orphanValues.Count})" );
|
||||
if( t2 )
|
||||
{
|
||||
foreach( var idx in orphanValues )
|
||||
{
|
||||
ImGui.SetNextItemWidth( ImGui.GetFontSize() * 10.0f );
|
||||
if( ImGui.InputFloat( $"#{idx} (at 0x{idx << 2:X4})",
|
||||
ref tab.Mtrl.ShaderPackage.ShaderValues[ idx ], 0.0f, 0.0f, "%.3f",
|
||||
disabled ? ImGuiInputTextFlags.ReadOnly : ImGuiInputTextFlags.None ) )
|
||||
{
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if( !disabled && !hasMalformedConstants && tab.AssociatedShpk != null )
|
||||
{
|
||||
var missingConstants = tab.AssociatedShpk.MaterialParams.Where( constant
|
||||
=> ( constant.ByteOffset & 0x3 ) == 0 && ( constant.ByteSize & 0x3 ) == 0 && !definedConstants.Contains( constant.Id ) ).ToArray();
|
||||
if( missingConstants.Length > 0 )
|
||||
{
|
||||
var selectedConstant = Array.Find( missingConstants, constant => constant.Id == tab.MaterialNewConstantId );
|
||||
if( selectedConstant.ByteSize == 0 )
|
||||
{
|
||||
selectedConstant = missingConstants[ 0 ];
|
||||
tab.MaterialNewConstantId = selectedConstant.Id;
|
||||
}
|
||||
|
||||
ImGui.SetNextItemWidth( ImGuiHelpers.GlobalScale * 450.0f );
|
||||
var (selectedConstantName, _) = MaterialParamRangeName( materialParams?.Name ?? "", selectedConstant.ByteOffset >> 2, selectedConstant.ByteSize >> 2 );
|
||||
using( var c = ImRaii.Combo( "##NewConstantId", $"{selectedConstantName} (ID: 0x{selectedConstant.Id:X8})" ) )
|
||||
{
|
||||
if( c )
|
||||
{
|
||||
foreach( var constant in missingConstants )
|
||||
{
|
||||
var (constantName, _) = MaterialParamRangeName( materialParams?.Name ?? "", constant.ByteOffset >> 2, constant.ByteSize >> 2 );
|
||||
if( ImGui.Selectable( $"{constantName} (ID: 0x{constant.Id:X8})", constant.Id == tab.MaterialNewConstantId ) )
|
||||
{
|
||||
selectedConstant = constant;
|
||||
tab.MaterialNewConstantId = constant.Id;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
if( ImGui.Button( "Add Constant" ) )
|
||||
{
|
||||
tab.Mtrl.ShaderPackage.ShaderValues = tab.Mtrl.ShaderPackage.ShaderValues.AddItem( 0.0f, selectedConstant.ByteSize >> 2 );
|
||||
tab.Mtrl.ShaderPackage.Constants = tab.Mtrl.ShaderPackage.Constants.AddItem( new MtrlFile.Constant
|
||||
{
|
||||
Id = tab.MaterialNewConstantId,
|
||||
ByteOffset = ( ushort )( tab.Mtrl.ShaderPackage.ShaderValues.Length << 2 ),
|
||||
ByteSize = selectedConstant.ByteSize,
|
||||
} );
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
ret = true;
|
||||
tab.UpdateConstantLabels();
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
private static bool DrawNewMaterialParam( MtrlTab tab )
|
||||
{
|
||||
ImGui.SetNextItemWidth( ImGuiHelpers.GlobalScale * 450.0f );
|
||||
using( var font = ImRaii.PushFont( UiBuilder.MonoFont ) )
|
||||
{
|
||||
using var c = ImRaii.Combo( "##NewConstantId", tab.MissingMaterialConstants[ tab.MaterialNewConstantIdx ].Name );
|
||||
if( c )
|
||||
{
|
||||
foreach( var (constant, idx) in tab.MissingMaterialConstants.WithIndex() )
|
||||
{
|
||||
if( ImGui.Selectable( constant.Name, constant.Id == tab.MaterialNewConstantId ) )
|
||||
{
|
||||
tab.MaterialNewConstantIdx = idx;
|
||||
tab.MaterialNewConstantId = constant.Id;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
if( ImGui.Button( "Add Constant" ) )
|
||||
{
|
||||
var (_, _, byteSize) = tab.MissingMaterialConstants[ tab.MaterialNewConstantIdx ];
|
||||
tab.Mtrl.ShaderPackage.Constants = tab.Mtrl.ShaderPackage.Constants.AddItem( new MtrlFile.Constant
|
||||
{
|
||||
Id = tab.MaterialNewConstantId,
|
||||
ByteOffset = ( ushort )( tab.Mtrl.ShaderPackage.ShaderValues.Length << 2 ),
|
||||
ByteSize = byteSize,
|
||||
} );
|
||||
tab.Mtrl.ShaderPackage.ShaderValues = tab.Mtrl.ShaderPackage.ShaderValues.AddItem( 0.0f, byteSize >> 2 );
|
||||
tab.UpdateConstantLabels();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool DrawMaterialConstants( MtrlTab tab, bool disabled )
|
||||
{
|
||||
if( tab.Mtrl.ShaderPackage.Constants.Length == 0
|
||||
&& tab.Mtrl.ShaderPackage.ShaderValues.Length == 0
|
||||
&& ( disabled || tab.AssociatedShpk == null || tab.AssociatedShpk.MaterialParams.Length == 0 ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
using var font = ImRaii.PushFont( UiBuilder.MonoFont );
|
||||
using var t = ImRaii.TreeNode( tab.MaterialConstantLabel );
|
||||
if( !t )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
font.Dispose();
|
||||
var ret = false;
|
||||
for( var idx = 0; idx < tab.Mtrl.ShaderPackage.Constants.Length; ++idx )
|
||||
{
|
||||
ret |= DrawMaterialConstantValues( tab, disabled, ref idx );
|
||||
}
|
||||
|
||||
if( tab.OrphanedMaterialValues.Count > 0 )
|
||||
{
|
||||
ret |= DrawMaterialOrphans( tab, disabled );
|
||||
}
|
||||
else if( !disabled && !tab.HasMalformedMaterialConstants && tab.MissingMaterialConstants.Count > 0 )
|
||||
{
|
||||
ret |= DrawNewMaterialParam( tab );
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
private bool DrawMaterialSamplers( MtrlTab tab, bool disabled )
|
||||
{
|
||||
var ret = false;
|
||||
|
|
@ -544,9 +540,46 @@ public partial class ModEditWindow
|
|||
return ret;
|
||||
}
|
||||
|
||||
|
||||
private static (string?, bool) MaterialParamRangeName( string prefix, int valueOffset, int valueLength )
|
||||
private static string? MaterialParamName( bool componentOnly, int offset )
|
||||
{
|
||||
if( offset < 0 )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return ( componentOnly, offset & 0x3 ) switch
|
||||
{
|
||||
(true, 0) => "x",
|
||||
(true, 1) => "y",
|
||||
(true, 2) => "z",
|
||||
(true, 3) => "w",
|
||||
(false, 0) => $"[{offset >> 2:D2}].x",
|
||||
(false, 1) => $"[{offset >> 2:D2}].y",
|
||||
(false, 2) => $"[{offset >> 2:D2}].z",
|
||||
(false, 3) => $"[{offset >> 2:D2}].w",
|
||||
_ => null,
|
||||
};
|
||||
}
|
||||
|
||||
private static (string? Name, bool ComponentOnly) MaterialParamRangeName( string prefix, int valueOffset, int valueLength )
|
||||
{
|
||||
static string VectorSwizzle( int firstComponent, int lastComponent )
|
||||
=> ( firstComponent, lastComponent ) switch
|
||||
{
|
||||
(0, 4) => " ",
|
||||
(0, 0) => ".x ",
|
||||
(0, 1) => ".xy ",
|
||||
(0, 2) => ".xyz ",
|
||||
(0, 3) => " ",
|
||||
(1, 1) => ".y ",
|
||||
(1, 2) => ".yz ",
|
||||
(1, 3) => ".yzw ",
|
||||
(2, 2) => ".z ",
|
||||
(2, 3) => ".zw ",
|
||||
(3, 3) => ".w ",
|
||||
_ => string.Empty,
|
||||
};
|
||||
|
||||
if( valueLength == 0 || valueOffset < 0 )
|
||||
{
|
||||
return ( null, false );
|
||||
|
|
@ -556,35 +589,19 @@ public partial class ModEditWindow
|
|||
var lastVector = ( valueOffset + valueLength - 1 ) >> 2;
|
||||
var firstComponent = valueOffset & 0x3;
|
||||
var lastComponent = ( valueOffset + valueLength - 1 ) & 0x3;
|
||||
|
||||
static string VectorSwizzle( int firstComponent, int numComponents )
|
||||
=> numComponents == 4 ? "" : string.Concat( ".", "xyzw".AsSpan( firstComponent, numComponents ) );
|
||||
|
||||
if( firstVector == lastVector )
|
||||
{
|
||||
return ( $"{prefix}[{firstVector}]{VectorSwizzle( firstComponent, lastComponent + 1 - firstComponent )}", true );
|
||||
return ( $"{prefix}[{firstVector}]{VectorSwizzle( firstComponent, lastComponent )}", true );
|
||||
}
|
||||
|
||||
var parts = new string[lastVector + 1 - firstVector];
|
||||
parts[ 0 ] = $"{prefix}[{firstVector}]{VectorSwizzle( firstComponent, 4 - firstComponent )}";
|
||||
parts[ ^1 ] = $"[{lastVector}]{VectorSwizzle( 0, lastComponent + 1 )}";
|
||||
var sb = new StringBuilder( 128 );
|
||||
sb.Append( $"{prefix}[{firstVector}]{VectorSwizzle( firstComponent, 3 )}" );
|
||||
for( var i = firstVector + 1; i < lastVector; ++i )
|
||||
{
|
||||
parts[ i - firstVector ] = $"[{i}]";
|
||||
sb.Append( $", [{i}]" );
|
||||
}
|
||||
|
||||
return ( string.Join( ", ", parts ), false );
|
||||
}
|
||||
|
||||
private static string? MaterialParamName( bool componentOnly, int offset )
|
||||
{
|
||||
if( offset < 0 )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var component = "xyzw"[ offset & 0x3 ];
|
||||
|
||||
return componentOnly ? new string( component, 1 ) : $"[{offset >> 2}].{component}";
|
||||
sb.Append( $", [{lastVector}]{VectorSwizzle( 0, lastComponent )}" );
|
||||
return ( sb.ToString(), false );
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using Dalamud.Interface;
|
||||
|
|
@ -10,7 +9,6 @@ using FFXIVClientStructs.STD;
|
|||
using ImGuiNET;
|
||||
using OtterGui;
|
||||
using OtterGui.Raii;
|
||||
using Penumbra.GameData;
|
||||
using Penumbra.Interop.Loader;
|
||||
using Penumbra.String.Classes;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue