Skip to content

Commit

Permalink
ColorTable impl
Browse files Browse the repository at this point in the history
  • Loading branch information
PassiveModding committed Apr 6, 2024
1 parent 7cf43b0 commit 88d942e
Show file tree
Hide file tree
Showing 5 changed files with 232 additions and 138 deletions.
157 changes: 157 additions & 0 deletions Meddle/Meddle.Plugin/Models/ColorTable.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
using System.Collections;
using System.Numerics;

namespace Meddle.Plugin.Models;

// https://github.com/Ottermandias/Penumbra.GameData/blob/45679aa32cc37b59f5eeb7cf6bf5a3ea36c626e0/Files/MtrlFile.ColorTable.cs
public unsafe struct ColorTable : IEnumerable<ColorTable.Row>
{
public ColorTable(Half[] data)
{
fixed (byte* ptr = rowData)
{
for (var i = 0; i < NumRows; ++i)
{
var row = new Row();
var span = row.AsHalves();
for (var j = 0; j < 16; ++j)
span[j] = data[i * 16 + j];
((Row*)ptr)[i] = row;
}
}
}

public ColorTable()
{
for (var i = 0; i < NumRows; ++i)
this[i] = Row.Default;
}

public const int NumRows = 16;
private fixed byte rowData[NumRows * Row.Size];

public ref Row this[int i]
{
get
{
fixed (byte* ptr = rowData)
{
return ref ((Row*)ptr)[i];
}
}
}

public IEnumerator<Row> GetEnumerator()
{
for (var i = 0; i < NumRows; ++i)
yield return this[i];
}

IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}

public unsafe struct Row
{
public const int Size = 32;
private fixed ushort data[16];

public static readonly Row Default = new()
{
Diffuse = Vector3.One,
Specular = Vector3.One,
SpecularStrength = 1.0f,
Emissive = Vector3.Zero,
GlossStrength = 20.0f,
TileSet = 0,
MaterialRepeat = new Vector2(16.0f),
MaterialSkew = Vector2.Zero,
};

public Vector3 Diffuse
{
readonly get => new(ToFloat(0), ToFloat(1), ToFloat(2));
set
{
data[0] = FromFloat(value.X);
data[1] = FromFloat(value.Y);
data[2] = FromFloat(value.Z);
}
}

public Vector3 Specular
{
readonly get => new(ToFloat(4), ToFloat(5), ToFloat(6));
set
{
data[4] = FromFloat(value.X);
data[5] = FromFloat(value.Y);
data[6] = FromFloat(value.Z);
}
}

public Vector3 Emissive
{
readonly get => new(ToFloat(8), ToFloat(9), ToFloat(10));
set
{
data[8] = FromFloat(value.X);
data[9] = FromFloat(value.Y);
data[10] = FromFloat(value.Z);
}
}

public Vector2 MaterialRepeat
{
readonly get => new(ToFloat(12), ToFloat(15));
set
{
data[12] = FromFloat(value.X);
data[15] = FromFloat(value.Y);
}
}

public Vector2 MaterialSkew
{
readonly get => new(ToFloat(13), ToFloat(14));
set
{
data[13] = FromFloat(value.X);
data[14] = FromFloat(value.Y);
}
}

public float SpecularStrength
{
readonly get => ToFloat(3);
set => data[3] = FromFloat(value);
}

public float GlossStrength
{
readonly get => ToFloat(7);
set => data[7] = FromFloat(value);
}

public ushort TileSet
{
readonly get => (ushort)(ToFloat(11) * 64f);
set => data[11] = FromFloat((value + 0.5f) / 64f);
}

public readonly Span<Half> AsHalves()
{
fixed (ushort* ptr = data)
{
return new Span<Half>(ptr, 16);
}
}

private readonly float ToFloat(int idx)
=> (float)BitConverter.UInt16BitsToHalf(data[idx]);

private static ushort FromFloat(float x)
=> BitConverter.HalfToUInt16Bits((Half)x);
}
}
68 changes: 0 additions & 68 deletions Meddle/Meddle.Plugin/Models/ColorTableRow.cs

This file was deleted.

6 changes: 3 additions & 3 deletions Meddle/Meddle.Plugin/UI/CharacterTab.Utils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,7 @@ public static void DrawMaterial(Material material)
if (material.ColorTable != null)
{
if (ImGui.CollapsingHeader($"Color Table##{material.GetHashCode()}"))
DrawColorTable(material.ColorTable);
DrawColorTable(material.ColorTable.Value);
}
}

Expand All @@ -375,9 +375,9 @@ public static void DrawColorTable(ColorTable table)
ImGui.TableSetupColumn("Emissive", ImGuiTableColumnFlags.WidthFixed, 50);
ImGui.TableHeadersRow();

for (var i = 0; i < table.Rows.Length; i++)
for (var i = 0; i < ColorTable.NumRows; i++)
{
var row = table.Rows[i];
var row = table[i];
ImGui.TableNextRow();
ImGui.TableNextColumn();
ImGui.Text($"Row {i}");
Expand Down
69 changes: 2 additions & 67 deletions Meddle/Meddle.Plugin/Utility/MaterialUtility.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System.Numerics;
using Lumina.Data.Parsing;
using Meddle.Plugin.Models;
using Meddle.Plugin.Utility.Materials;
using SharpGLTF.Materials;
using SkiaSharp;

Expand All @@ -16,7 +17,7 @@ public static MaterialBuilder BuildCharacter(Material material, string name)
{
var normal = material.GetTexture(TextureUsage.SamplerNormal);

var operation = new ProcessCharacterNormalOperation(normal.Resource.ToTexture(), material.ColorTable!).Run();
var operation = new ProcessCharacterNormalOperation(normal.Resource.ToTexture(), material.ColorTable!.Value).Run();

var baseColor = operation.BaseColor;
if (material.TryGetTexture(TextureUsage.SamplerDiffuse, out var diffuseTexture))
Expand Down Expand Up @@ -291,70 +292,4 @@ public static SKTexture MultiplyBitmaps(SKTexture target, SKTexture multiplier,

return result;
}

private class ProcessCharacterNormalOperation(SKTexture normal, ColorTable table)
{
public SKTexture Normal { get; } = normal.Copy();
public SKTexture BaseColor { get; } = new(normal.Width, normal.Height);
public SKTexture Specular { get; } = new(normal.Width, normal.Height);
public SKTexture Emissive { get; } = new(normal.Width, normal.Height);

private static TableRow GetTableRowIndices(float input)
{
// These calculations are ported from character.shpk.
var smoothed = (MathF.Floor(input * 7.5f % 1.0f * 2)
* (-input * 15 + MathF.Floor(input * 15 + 0.5f)))
+ (input * 15);

var stepped = MathF.Floor(smoothed + 0.5f);

return new TableRow
{
Stepped = (int)stepped,
Previous = (int)MathF.Floor(smoothed),
Next = (int)MathF.Ceiling(smoothed),
Weight = smoothed % 1,
};
}

private ref struct TableRow
{
public int Stepped;
public int Previous;
public int Next;
public float Weight;
}

public ProcessCharacterNormalOperation Run()
{
for (var y = 0; y < normal.Height; y++)
for (var x = 0; x < normal.Width; x++)
{
var normalPixel = Normal[x, y].ToVector4();

// Table row data (.a)
var tableRow = GetTableRowIndices(normalPixel.W);
var prevRow = table.Rows[tableRow.Previous];
var nextRow = table.Rows[tableRow.Next];

// Base colour (table, .b)
var lerpedDiffuse = Vector3.Lerp(prevRow.Diffuse, nextRow.Diffuse, tableRow.Weight);
BaseColor[x, y] = new Vec4Ext(lerpedDiffuse, normalPixel.Z);

// Specular (table)
var lerpedSpecularColor = Vector3.Lerp(prevRow.Specular, nextRow.Specular, tableRow.Weight);
var lerpedSpecularFactor = float.Lerp(prevRow.SpecularStrength, nextRow.SpecularStrength, tableRow.Weight);
Specular[x, y] = new Vec4Ext(lerpedSpecularColor, lerpedSpecularFactor);

// Emissive (table)
var lerpedEmissive = Vector3.Lerp(prevRow.Emissive, nextRow.Emissive, tableRow.Weight);
Emissive[x, y] = lerpedEmissive.ToSkColor();

// Normal (.rg)
Normal[x, y] = new Vec4Ext(normalPixel.X, normalPixel.Y, 1, normalPixel.Z);
}

return this;
}
}
}
Loading

0 comments on commit 88d942e

Please sign in to comment.