Skip to content

Commit bfa9549

Browse files
Merge pull request #51 from PassiveModding/feature/minor-fixes-2026-04
Feature/minor fixes 2026 04
2 parents a50555f + 29eb39c commit bfa9549

5 files changed

Lines changed: 187 additions & 11 deletions

File tree

Meddle/Meddle.Plugin/Models/Composer/CharacterComposer.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ private void HandleModel(ParsedCharacterInfo characterInfo, ParsedModelInfo m, S
134134
{
135135
{"modelGamePath", m.Path.GamePath},
136136
{"modelFullPath", m.Path.FullPath},
137+
{"modelEnabled", m.Enabled.ToString()},
137138
{"meshShapes", meshExport.Shapes != null ? string.Join(",", meshExport.Shapes) : ""},
138139
{"modelEnabledAttributes", string.Join(",", enabledAttributes)},
139140
{"modelAttributes", string.Join(",", model.AttributeMasks.Select(x => x.name))},
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
using System.Numerics;
2+
using Dalamud.Bindings.ImGui;
3+
using Dalamud.Game.ClientState.Objects.Types;
4+
using Dalamud.Interface.Textures;
5+
using Dalamud.Interface.Utility.Raii;
6+
using Dalamud.Plugin.Services;
7+
using FFXIVClientStructs.FFXIV.Client.Game.Character;
8+
using FFXIVClientStructs.FFXIV.Client.Graphics.Kernel;
9+
using FFXIVClientStructs.FFXIV.Client.Graphics.Render;
10+
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
11+
using FFXIVClientStructs.Interop;
12+
using Meddle.Plugin.Models;
13+
using Meddle.Plugin.Services;
14+
using Meddle.Plugin.Utils;
15+
using Microsoft.Extensions.Logging;
16+
17+
namespace Meddle.Plugin.UI;
18+
19+
public class ColorTableTester : ITab
20+
{
21+
private readonly ILogger<ColorTableTester> log;
22+
private readonly Configuration config;
23+
private readonly CommonUi commonUi;
24+
private readonly TextureCache textureCache;
25+
private readonly ITextureProvider textureProvider;
26+
private ICharacter? selectedCharacter;
27+
private OnRenderMaterialOutput? output;
28+
public string Name => "ColorTable Tester";
29+
public int Order => 100;
30+
public MenuType MenuType => MenuType.Debug;
31+
32+
public ColorTableTester(
33+
ILogger<ColorTableTester> log,
34+
Configuration config,
35+
CommonUi commonUi, TextureCache textureCache, ITextureProvider textureProvider)
36+
{
37+
this.log = log;
38+
this.config = config;
39+
this.commonUi = commonUi;
40+
this.textureCache = textureCache;
41+
this.textureProvider = textureProvider;
42+
}
43+
44+
public unsafe void Draw()
45+
{
46+
commonUi.DrawCharacterSelect(ref selectedCharacter, CharacterValidationFlags.IsVisible);
47+
if (output != null)
48+
{
49+
var serialized = System.Text.Json.JsonSerializer.Serialize(output, new System.Text.Json.JsonSerializerOptions
50+
{
51+
WriteIndented = true
52+
});
53+
ImGui.TextWrapped(serialized);
54+
if (output.DecalTexture != null)
55+
{
56+
var wrap = textureCache.GetOrAdd($"{output.DecalTexture.GetHashCode()}", () =>
57+
{
58+
var textureData = output.DecalTexture.Bitmap.GetPixelSpan();
59+
var wrap = textureProvider.CreateFromRaw(
60+
RawImageSpecification.Rgba32(output.DecalTexture.Width, output.DecalTexture.Height), textureData,
61+
$"Meddle_Decal_{output.DecalTexture.GetHashCode()}");
62+
return wrap;
63+
});
64+
var availableWidth = ImGui.GetContentRegionAvail().X;
65+
float displayWidth = output.DecalTexture.Width;
66+
float displayHeight = output.DecalTexture.Height;
67+
if (displayWidth > availableWidth)
68+
{
69+
var ratio = availableWidth / displayWidth;
70+
displayWidth *= ratio;
71+
displayHeight *= ratio;
72+
}
73+
ImGui.Image(wrap.Handle, new Vector2(displayWidth, displayHeight));
74+
}
75+
76+
if (ImGui.Button("Clear Output"))
77+
{
78+
output = null;
79+
}
80+
}
81+
82+
if (selectedCharacter == null)
83+
{
84+
ImGui.Text("No character selected");
85+
return;
86+
}
87+
88+
var character = (Character*)selectedCharacter.Address;
89+
var drawObject = character->GameObject.DrawObject;
90+
if (drawObject == null)
91+
{
92+
ImGui.Text("Draw object is null");
93+
return;
94+
}
95+
96+
if (drawObject->GetObjectType() != ObjectType.CharacterBase)
97+
{
98+
ImGui.Text("Draw object is not a character base");
99+
return;
100+
}
101+
102+
var cBase = (CharacterBase*)drawObject;
103+
var modelType = cBase->GetModelType();
104+
if (modelType != CharacterBase.ModelType.Human)
105+
{
106+
ImGui.Text("Model is not human");
107+
return;
108+
}
109+
110+
111+
// cPtr.Value->ColorTableTexturesSpan[(slotIdx * CSCharacterBase.MaterialsPerSlot) + materialIdx];
112+
var human = (Human*)cBase;
113+
// var colorTableContexts = new List<(Pointer<Model> Model, Pointer<Material> Material, Pointer<Texture> Texture, int ColorTableIdx)>();
114+
var colorTableDict = new Dictionary<int, (Pointer<Model> Model, Pointer<Material> Material)>();
115+
for (var modelIdx = 0; modelIdx < human->ModelsSpan.Length; modelIdx++)
116+
{
117+
var model = human->ModelsSpan[modelIdx];
118+
if (model == null || model.Value == null)
119+
{
120+
continue;
121+
}
122+
123+
for (var materialIdx = 0; materialIdx < model.Value->MaterialsSpan.Length; materialIdx++)
124+
{
125+
var material = model.Value->MaterialsSpan[materialIdx];
126+
if (material == null || material.Value == null)
127+
{
128+
continue;
129+
}
130+
131+
var index = ParseMaterialUtil.ResolveColorTableSetIndex((int)model.Value->SlotIndex, materialIdx);
132+
colorTableDict[index] = (model, material);
133+
}
134+
}
135+
for (var colorTableIdx = 0; colorTableIdx < human->ColorTableTexturesSpan.Length; colorTableIdx++)
136+
{
137+
var colorTableTexture = human->ColorTableTexturesSpan[colorTableIdx];
138+
if (colorTableTexture == null || colorTableTexture.Value == null)
139+
{
140+
continue;
141+
}
142+
143+
if (!colorTableDict.TryGetValue(colorTableIdx, out var modelMaterial))
144+
{
145+
continue;
146+
}
147+
148+
var modelName = modelMaterial.Model.Value->ModelResourceHandle->FileName;
149+
var materialName = modelMaterial.Material.Value->MaterialResourceHandle->FileName;
150+
var shortMaterialName = Path.GetFileName(materialName.ToString());
151+
152+
if (ImGui.CollapsingHeader($"Color Table Texture {colorTableIdx} - {shortMaterialName} - {colorTableTexture.Value->ActualWidth}x{colorTableTexture.Value->ActualHeight}"))
153+
{
154+
var colorTable = ParseMaterialUtil.ParseColorTableTexture(colorTableTexture);
155+
UiUtil.DrawColorTable(colorTable);
156+
}
157+
}
158+
}
159+
160+
161+
public void Dispose()
162+
{
163+
// TODO release managed resources here
164+
}
165+
}

Meddle/Meddle.Plugin/UI/LiveCharacterTab.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -551,8 +551,8 @@ private void DrawModel(Pointer<CharacterBase> cPtr, Pointer<CSModel> mPtr)
551551
{
552552
var localMaterialIdx = materialIdx;
553553
var materialPtr = model->MaterialsSpan[localMaterialIdx];
554-
DrawMaterial(materialPtr.Value, materialIdx, slotIdx => GetColorTableTexture(cBase, slotIdx, localMaterialIdx),
555-
GetMaterialName(model, localMaterialIdx));
554+
var colorTableLazy = new Lazy<Pointer<Texture>>(() => GetColorTableTexture(cBase, (int)model->SlotIndex, localMaterialIdx));
555+
DrawMaterial(materialPtr.Value, materialIdx, colorTableLazy, GetMaterialName(model, localMaterialIdx));
556556
}
557557
}
558558
}
@@ -697,7 +697,7 @@ private Pointer<Texture> GetColorTableTexture(Pointer<CSCharacterBase> cPtr, int
697697
return null;
698698
}
699699

700-
var colorTableTexturePtr = cPtr.Value->ColorTableTexturesSpan[(slotIdx * CSCharacterBase.MaterialsPerSlot) + materialIdx];
700+
var colorTableTexturePtr = cPtr.Value->ColorTableTexturesSpan[ParseMaterialUtil.ResolveColorTableSetIndex(slotIdx, materialIdx)];
701701
return colorTableTexturePtr;
702702
}
703703

@@ -713,7 +713,7 @@ private Pointer<Texture> GetColorTableTexture(Pointer<CSCharacterBase> cPtr, int
713713
return materialName;
714714
}
715715

716-
private void DrawMaterial(Pointer<CSMaterial> mtPtr, int materialIdx, Func<int, Pointer<Texture>>? getColorTableTexture, string? materialName)
716+
private void DrawMaterial(Pointer<CSMaterial> mtPtr, int materialIdx, Lazy<Pointer<Texture>> getColorTableTexture, string? materialName)
717717
{
718718
if (mtPtr == null || mtPtr.Value == null || mtPtr.Value->MaterialResourceHandle == null)
719719
{
@@ -819,7 +819,7 @@ private void DrawMaterial(Pointer<CSMaterial> mtPtr, int materialIdx, Func<int,
819819
ImGui.Text($"Shader Flags: 0x{material->ShaderFlags:X8}");
820820

821821

822-
var colorTableTexturePtr = getColorTableTexture?.Invoke(materialIdx);
822+
var colorTableTexturePtr = getColorTableTexture.Value;
823823
if (colorTableTexturePtr != null && colorTableTexturePtr.Value != null &&
824824
ImGui.CollapsingHeader("Color Table"))
825825
{

Meddle/Meddle.Plugin/UI/TestFunctionTab.cs renamed to Meddle/Meddle.Plugin/UI/OnRenderMaterialTester.cs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,21 +13,21 @@
1313

1414
namespace Meddle.Plugin.UI;
1515

16-
public class TestFunctionTab : ITab
16+
public class OnRenderMaterialTester : ITab
1717
{
18-
private readonly ILogger<TestFunctionTab> log;
18+
private readonly ILogger<OnRenderMaterialTester> log;
1919
private readonly Configuration config;
2020
private readonly CommonUi commonUi;
2121
private readonly TextureCache textureCache;
2222
private readonly ITextureProvider textureProvider;
2323
private ICharacter? selectedCharacter;
2424
private OnRenderMaterialOutput? output;
25-
public string Name => "Test Functions";
25+
public string Name => "OnRenderMaterial Tester";
2626
public int Order => 100;
2727
public MenuType MenuType => MenuType.Debug;
2828

29-
public TestFunctionTab(
30-
ILogger<TestFunctionTab> log,
29+
public OnRenderMaterialTester(
30+
ILogger<OnRenderMaterialTester> log,
3131
Configuration config,
3232
CommonUi commonUi, TextureCache textureCache, ITextureProvider textureProvider)
3333
{
@@ -156,6 +156,11 @@ public unsafe void Draw()
156156
}
157157
}
158158
}
159+
160+
public unsafe void DisplayAllColorTables()
161+
{
162+
163+
}
159164

160165

161166
public void Dispose()

Meddle/Meddle.Plugin/Utils/ParseMaterialUtil.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,11 @@ public static unsafe ParsedHumanInfo ParseHuman(Pointer<CharacterBase> character
205205
EquipmentModelIds = equipData.ToArray()
206206
};
207207
}
208+
209+
public static int ResolveColorTableSetIndex(int slotIdx, int materialIdx)
210+
{
211+
return (slotIdx * CharacterBase.MaterialsPerSlot) + materialIdx;
212+
}
208213

209214
private static unsafe IColorTableSet? GetColorTableSet(Pointer<Model> modelPtr, Pointer<Material> materialPtr, uint materialIndex, Dictionary<int, IColorTableSet> colorTableSets)
210215
{
@@ -221,7 +226,7 @@ public static unsafe ParsedHumanInfo ParseHuman(Pointer<CharacterBase> character
221226

222227
var model = modelPtr.Value;
223228
var material = materialPtr.Value;
224-
if (colorTableSets.TryGetValue((int)(modelPtr.Value->SlotIndex * CharacterBase.MaterialsPerSlot) + (int)materialIndex, out var gpuColorTable))
229+
if (colorTableSets.TryGetValue(ResolveColorTableSetIndex((int)model->SlotIndex, (int)materialIndex), out var gpuColorTable))
225230
{
226231
colorTable = gpuColorTable;
227232
}

0 commit comments

Comments
 (0)