Skip to content

Commit

Permalink
Export array textures + color table updates
Browse files Browse the repository at this point in the history
  • Loading branch information
PassiveModding committed Nov 19, 2024
1 parent f195e96 commit f1b487f
Show file tree
Hide file tree
Showing 7 changed files with 280 additions and 98 deletions.
78 changes: 63 additions & 15 deletions Meddle/Meddle.Plugin/Models/Composer/CharacterComposer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,65 @@ public class CharacterComposer
{
private readonly DataProvider dataProvider;
private readonly Action<ProgressEvent>? progress;
private static TexFile? CubeMapTex;
private static PbdFile? PbdFile;
private static readonly object StaticFileLock = new();
private static PbdFile? DefaultPbdFile;
private readonly SkeletonUtils.PoseMode poseMode;
private readonly bool includePose;
private readonly TextureMode textureMode;
private bool arrayTexturesSaved;

private void SaveArrayTextures()
{
if (arrayTexturesSaved) return;
arrayTexturesSaved = true;
lock (StaticFileLock)
{
try
{
var outDir = Path.Combine(this.dataProvider.GetCacheDir(), "array_textures");

var catchlight = this.dataProvider.LookupData("chara/common/texture/sphere_d_array.tex");
if (catchlight == null) throw new Exception("Failed to load catchlight texture");
var catchLightTex = new TexFile(catchlight);
var catchlightOutDir = Path.Combine(outDir, "chara/common/texture/sphere_d_array");
Directory.CreateDirectory(catchlightOutDir);
for (int i = 0; i < catchLightTex.Header.CalculatedArraySize; i++)
{
var img = ImageUtils.GetTexData(catchLightTex, i, 0, 0);
var texture = img.ImageAsPng();
File.WriteAllBytes(Path.Combine(catchlightOutDir, $"sphere_d_array.{i}.png"), texture.ToArray());
}

var tileNorm = this.dataProvider.LookupData("chara/common/texture/tile_norm_array.tex");
if (tileNorm == null) throw new Exception("Failed to load tile norm texture");
var tileNormTex = new TexFile(tileNorm);
var tileNormOutDir = Path.Combine(outDir, "chara/common/texture/tile_norm_array");
Directory.CreateDirectory(tileNormOutDir);
for (int i = 0; i < tileNormTex.Header.CalculatedArraySize; i++)
{
var img = ImageUtils.GetTexData(tileNormTex, i, 0, 0);
var texture = img.ImageAsPng();
File.WriteAllBytes(Path.Combine(tileNormOutDir, $"tile_norm_array.{i}.png"), texture.ToArray());
}

var tileOrb = this.dataProvider.LookupData("chara/common/texture/tile_orb_array.tex");
if (tileOrb == null) throw new Exception("Failed to load tile orb texture");
var tileOrbTex = new TexFile(tileOrb);
var tileOrbOutDir = Path.Combine(outDir, "chara/common/texture/tile_orb_array");
Directory.CreateDirectory(tileOrbOutDir);
for (int i = 0; i < tileOrbTex.Header.CalculatedArraySize; i++)
{
var img = ImageUtils.GetTexData(tileOrbTex, i, 0, 0);
var texture = img.ImageAsPng();
File.WriteAllBytes(Path.Combine(tileOrbOutDir, $"tile_orb_array.{i}.png"), texture.ToArray());
}
}
catch (Exception e)
{
Plugin.Logger?.LogError(e, "Failed to save array textures");
}
}
}

public CharacterComposer(DataProvider dataProvider, Configuration config, Action<ProgressEvent>? progress = null)
{
Expand All @@ -32,21 +85,14 @@ public CharacterComposer(DataProvider dataProvider, Configuration config, Action
includePose = config.IncludePose;
poseMode = config.PoseMode;
textureMode = config.TextureMode;

lock (StaticFileLock)
{
if (CubeMapTex == null)
if (DefaultPbdFile == null)
{
var catchlight = this.dataProvider.LookupData("chara/common/texture/sphere_d_array.tex");
if (catchlight == null) throw new Exception("Failed to load catchlight texture");
CubeMapTex = new TexFile(catchlight);
}

if (PbdFile == null)
{
var pbdData = this.dataProvider.LookupData("chara/xls/boneDeformer/human.pbd");
if (pbdData == null) throw new Exception("Failed to load human.pbd");
PbdFile = new PbdFile(pbdData);
var pbdData = dataProvider.LookupData("chara/xls/boneDeformer/human.pbd");
if (pbdData == null) throw new InvalidOperationException("Failed to load default pbd file");
DefaultPbdFile = new PbdFile(pbdData);
}
}
}
Expand All @@ -56,6 +102,8 @@ private void HandleModel(GenderRace genderRace, CustomizeParameter customizePara
BoneNodeBuilder? rootBone,
Matrix4x4 transform)
{
SaveArrayTextures();

if (modelInfo.Path.GamePath.Contains("b0003_top"))
{
Plugin.Logger?.LogDebug("Skipping model {ModelPath}", modelInfo.Path.GamePath);
Expand Down Expand Up @@ -140,7 +188,7 @@ private void HandleModel(GenderRace genderRace, CustomizeParameter customizePara
var parsed = RaceDeformer.ParseRaceCode(modelInfo.Path.GamePath);
if (Enum.IsDefined(parsed))
{
deform = (parsed, genderRace, new RaceDeformer(PbdFile!, bones));
deform = (parsed, genderRace, new RaceDeformer(DefaultPbdFile!, bones));
}
else
{
Expand Down
1 change: 1 addition & 0 deletions Meddle/Meddle.Plugin/Models/Composer/DataProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ public class DataProvider
private readonly ConcurrentDictionary<int, Lazy<MaterialBuilder>> mtrlCache = new();
private readonly ConcurrentDictionary<string, Lazy<MtrlFile>> mtrlFileCache = new();
private readonly ConcurrentDictionary<string, Lazy<ShpkFile>> shpkFileCache = new();
public string GetCacheDir() => cacheDir;

public DataProvider(string cacheDir, SqPack dataManager, ILogger logger, CancellationToken cancellationToken)
{
Expand Down
58 changes: 58 additions & 0 deletions Meddle/Meddle.Plugin/Models/Composer/InstanceComposer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,63 @@ public class InstanceComposer : IDisposable
private readonly Action<ProgressEvent>? progress;
private readonly DataProvider dataProvider;
private int countProgress;
private bool arrayTexturesSaved;
private static readonly object StaticFileLock = new();
private void SaveArrayTextures()
{
if (arrayTexturesSaved) return;
arrayTexturesSaved = true;
lock (StaticFileLock)
{
try
{
var outDir= Path.Combine(this.dataProvider.GetCacheDir(), "array_textures");

var catchlight = this.dataProvider.LookupData("bgcommon/texture/sphere_d_array.tex");
if (catchlight == null) throw new Exception("Failed to load catchlight texture");
var catchLightTex = new TexFile(catchlight);
var catchlightOutDir = Path.Combine(outDir, "bgcommon/texture/sphere_d_array");
Directory.CreateDirectory(catchlightOutDir);

for (int i = 0; i < catchLightTex.Header.CalculatedArraySize; i++)
{
var img = ImageUtils.GetTexData(catchLightTex, i, 0, 0);
var texture = img.ImageAsPng();
File.WriteAllBytes(Path.Combine(catchlightOutDir, $"sphere_d_array.{i}.png"), texture.ToArray());
}

var detailD = this.dataProvider.LookupData("bgcommon/nature/detail/texture/detail_d_array.tex");
if (detailD == null) throw new Exception("Failed to load detail diffuse texture");
var detailDTex = new TexFile(detailD);
var detailDOutDir = Path.Combine(outDir, "bgcommon/nature/detail/texture/detail_d_array");
Directory.CreateDirectory(detailDOutDir);

for (int i = 0; i < detailDTex.Header.CalculatedArraySize; i++)
{
var img = ImageUtils.GetTexData(detailDTex, i, 0, 0);
var texture = img.ImageAsPng();
File.WriteAllBytes(Path.Combine(detailDOutDir, $"detail_d_array.{i}.png"), texture.ToArray());
}

var detailN = this.dataProvider.LookupData("bgcommon/nature/detail/texture/detail_n_array.tex");
if (detailN == null) throw new Exception("Failed to load tile orb texture");
var detailNTex = new TexFile(detailN);
var detailNOutDir = Path.Combine(outDir, "bgcommon/nature/detail/texture/detail_n_array");
Directory.CreateDirectory(detailNOutDir);

for (int i = 0; i < detailNTex.Header.CalculatedArraySize; i++)
{
var img = ImageUtils.GetTexData(detailNTex, i, 0, 0);
var texture = img.ImageAsPng();
File.WriteAllBytes(Path.Combine(detailNOutDir, $"detail_n_array.{i}.png"), texture.ToArray());
}
}
catch (Exception e)
{
Plugin.Logger?.LogError(e, "Failed to save array textures");
}
}
}

public InstanceComposer(
Configuration config,
Expand Down Expand Up @@ -93,6 +150,7 @@ public void Compose(SceneBuilder scene)
public NodeBuilder? ComposeInstance(SceneBuilder scene, ParsedInstance parsedInstance)
{
if (cancellationToken.IsCancellationRequested) return null;
SaveArrayTextures();
var root = new NodeBuilder();
var transform = parsedInstance.Transform;
if (parsedInstance is IPathInstance pathInstance)
Expand Down
69 changes: 45 additions & 24 deletions Meddle/Meddle.Plugin/Utils/UIUtil.cs
Original file line number Diff line number Diff line change
Expand Up @@ -84,17 +84,27 @@ public static void DrawColorTable(ColorTable table, ColorDyeTable? dyeTable = nu

public static void DrawColorTable(ReadOnlySpan<ColorTableRow> tableRows, ColorDyeTable? dyeTable = null)
{
if (ImGui.BeginTable("ColorTable", 9, ImGuiTableFlags.Borders | ImGuiTableFlags.Resizable))
if (ImGui.BeginTable("ColorTable", 16, ImGuiTableFlags.Borders |
ImGuiTableFlags.Resizable |
ImGuiTableFlags.SizingFixedFit |
ImGuiTableFlags.Hideable))
{
ImGui.TableSetupColumn("Row", ImGuiTableColumnFlags.WidthFixed, 50);
ImGui.TableSetupColumn("Diffuse", ImGuiTableColumnFlags.WidthFixed, 100);
ImGui.TableSetupColumn("Specular", ImGuiTableColumnFlags.WidthFixed, 100);
ImGui.TableSetupColumn("Emissive", ImGuiTableColumnFlags.WidthFixed, 100);
ImGui.TableSetupColumn("Material Repeat", ImGuiTableColumnFlags.WidthFixed, 100);
ImGui.TableSetupColumn("Material Skew", ImGuiTableColumnFlags.WidthFixed, 100);
ImGui.TableSetupColumn("Specular Strength", ImGuiTableColumnFlags.WidthFixed, 100);
ImGui.TableSetupColumn("Gloss", ImGuiTableColumnFlags.WidthFixed, 100);
ImGui.TableSetupColumn("Tile Set", ImGuiTableColumnFlags.WidthFixed, 100);
ImGui.TableSetupColumn("Sheen Rate", ImGuiTableColumnFlags.WidthFixed, 50);
ImGui.TableSetupColumn("Sheen Tint", ImGuiTableColumnFlags.WidthFixed, 50);
ImGui.TableSetupColumn("Sheen Apt.", ImGuiTableColumnFlags.WidthFixed, 50);
ImGui.TableSetupColumn("Roughness", ImGuiTableColumnFlags.WidthFixed, 50);
ImGui.TableSetupColumn("Metalness", ImGuiTableColumnFlags.WidthFixed, 50);
ImGui.TableSetupColumn("Anisotropy", ImGuiTableColumnFlags.WidthFixed, 50);
ImGui.TableSetupColumn("Tile Matrix", ImGuiTableColumnFlags.WidthFixed, 100);
ImGui.TableSetupColumn("Sphere Mask", ImGuiTableColumnFlags.WidthFixed, 50);
ImGui.TableSetupColumn("Sphere Idx", ImGuiTableColumnFlags.WidthFixed, 50);
ImGui.TableSetupColumn("Shader Idx", ImGuiTableColumnFlags.WidthFixed, 50);
ImGui.TableSetupColumn("Tile Index", ImGuiTableColumnFlags.WidthFixed, 50);
ImGui.TableSetupColumn("Tile Alpha", ImGuiTableColumnFlags.WidthFixed, 50);
ImGui.TableHeadersRow();

for (var i = 0; i < tableRows.Length; i++)
Expand Down Expand Up @@ -141,29 +151,40 @@ private static void DrawRow(int i, ColorTableRow row, ColorDyeTable? dyeTable)
}

ImGui.TableSetColumnIndex(4);
ImGui.Text($"{row.MaterialRepeat}");
ImGui.Text($"{row.SheenRate}");

ImGui.TableSetColumnIndex(5);
ImGui.Text($"{row.MaterialSkew}");
ImGui.Text($"{row.SheenTint}");

ImGui.TableSetColumnIndex(6);
if (dyeTable != null)
{
var specStrength = dyeTable.Value.Rows[i].SpecularStrength;
ImGui.Checkbox("##rowspecstrcheck", ref specStrength);
ImGui.SameLine();
}

ImGui.Text($"{row.SpecularStrength}");
ImGui.Text($"{row.SheenAptitude}");

ImGui.TableSetColumnIndex(7);
if (dyeTable != null)
{
var gloss = dyeTable.Value.Rows[i].Gloss;
ImGui.Checkbox("##rowglosscheck", ref gloss);
ImGui.SameLine();
}

ImGui.Text($"{row.GlossStrength}");
ImGui.Text($"{row.Roughness}");

ImGui.TableSetColumnIndex(8);
ImGui.Text($"{row.Metalness}");

ImGui.TableSetColumnIndex(9);
ImGui.Text($"{row.Anisotropy}");

ImGui.TableSetColumnIndex(10);
ImGui.Text($"UU: {row.TileMatrix.UU}, UV: {row.TileMatrix.UV}, VU: {row.TileMatrix.VU}, VV: {row.TileMatrix.VV}");

ImGui.TableSetColumnIndex(11);
ImGui.Text($"{row.SphereMask}");

ImGui.TableSetColumnIndex(12);
ImGui.Text($"{row.SphereIndex}");

ImGui.TableSetColumnIndex(13);
ImGui.Text($"{row.ShaderId}");

ImGui.TableSetColumnIndex(14);
ImGui.Text($"{row.TileIndex}");

ImGui.TableSetColumnIndex(15);
ImGui.Text($"{row.TileAlpha}");
}

public static unsafe void DrawCharacterAttaches(Pointer<Character> characterPointer)
Expand Down
Loading

0 comments on commit f1b487f

Please sign in to comment.