summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--LUT.cs243
-rwxr-xr-xPlugin.cs123
-rw-r--r--Shaders/alpha_as_luma.hlsl4
3 files changed, 160 insertions, 210 deletions
diff --git a/LUT.cs b/LUT.cs
index 1181216..f38010c 100644
--- a/LUT.cs
+++ b/LUT.cs
@@ -2,57 +2,23 @@
using System.Text;
using System.Numerics;
-using SharpPluginLoader.Core;
+using System.Runtime.InteropServices;
+
+using ImGuiNET;
using SharpPluginLoader.Core.Memory;
-using SharpPluginLoader.Core.Rendering;
+using SharpPluginLoader.Core.Resources;
+using SharpPluginLoader.Core.IO;
namespace WorldTuningTool
{
- public class WorldLUT
+ public class WorldLUTs
{
- private const string lutsPath = "nativePC/plugins/CSharp/LUT";
-
- public WorldLUT() { }
-
- private string[] lutList = [];
-
- public string[] GetLUTs()
- {
- return lutList;
- }
+ private const string addPath = "nativePC/plugins/CSharp/LUT";
- public void ReloadLUTs()
- {
- if (Directory.Exists(lutsPath))
- {
- lutList = Directory.GetFiles(lutsPath);
- }
- }
-
- public static nint ProbeD3DResource(nint lightingObject)
- {
- nint lutTexture = MemoryUtil.Read<nint>(lightingObject + 0x1C0);
- nint d3dResource = 0x0;
- if (lutTexture != 0x0)
- {
- if (Renderer.IsDirectX12)
- {
- d3dResource = MemoryUtil.Read<nint>(lutTexture + 0x10);
- }
- else
- {
- d3dResource = MemoryUtil.Read<nint>(lutTexture + 0x60);
- if (d3dResource != 0x0)
- {
- d3dResource = MemoryUtil.Read<nint>(d3dResource + 0x18);
- }
- }
- }
- return d3dResource;
- }
+ public WorldLUTs() { }
// https://github.com/AsteriskAmpersand/CrappyLUTStudio--CLUTS-/blob/5af10daaa5f295b106cc5db09530a6fe5a4320d4/LUT.py#L35
- public byte[]? parseWorldLUT(BinaryReader reader)
+ private byte[]? parseWorldLUT(BinaryReader reader)
{
byte[] signature = reader.ReadBytes(4);
if (!(signature[0] == 0x54 && signature[1] == 0x45 &&
@@ -87,12 +53,11 @@ namespace WorldTuningTool
// https://drive.google.com/file/d/143Eh08ZYncCAMwJ1q4gWxVOqR_OSWYvs/view
// When does DOMAIN_MIN/MAX apply?
- public byte[]? parseCubeLUT(StreamReader reader)
+ private byte[]? parseCubeLUT(StreamReader reader)
{
string? line;
- Vector3[,,]? parsed = null;
- int dim = 0, last = 0;
- int x = 0, y = 0, z = 0;
+ Vector3[]? parsed = null;
+ int dim = 0, idx = 0;
while ((line = reader.ReadLine()) != null)
{
if (line.StartsWith("LUT_3D_SIZE"))
@@ -113,8 +78,7 @@ namespace WorldTuningTool
{
return null;
}
- parsed = new Vector3[dim,dim,dim];
- last = dim - 1;
+ parsed = new Vector3[dim * dim * dim];
while ((line = reader.ReadLine()) != null)
{
if (line == "") continue;
@@ -132,7 +96,7 @@ namespace WorldTuningTool
{
try
{
- parsed[x,y,z] = Plugin.StringToVector3(line, ' ');
+ parsed[idx] = Plugin.StringToVector3(line, ' ');
}
catch (FormatException)
{
@@ -142,23 +106,7 @@ namespace WorldTuningTool
{
return null;
}
- if (x == last)
- {
- if (y == last)
- {
- z++;
- y = 0;
- }
- else
- {
- y++;
- }
- x = 0;
- }
- else
- {
- x++;
- }
+ idx++;
}
}
if (parsed == null)
@@ -166,71 +114,144 @@ namespace WorldTuningTool
return null;
}
const int lutDataSize = 32 * 32 * 32 * 8;
- byte[] data = new byte[lutDataSize], bytes;
+ byte[] data = new byte[lutDataSize];
float scale = MathF.Pow(2, 14) - 1;
- int idx = 0;
- for (z = 0; z < 32; z++)
+ for (idx = 0; idx < lutDataSize; idx+=8)
{
- for (y = 0; y < 32; y++)
+ Vector3 v = parsed[idx/8];
+ ushort normX = (ushort)Math.Round(v.X * scale);
+ ushort normY = (ushort)Math.Round(v.Y * scale);
+ ushort normZ = (ushort)Math.Round(v.Z * scale);
+ byte[] bytes = BitConverter.GetBytes(normX);
+ data[idx] = bytes[0];
+ data[idx + 1] = bytes[1];
+ bytes = BitConverter.GetBytes(normY);
+ data[idx + 2] = bytes[0];
+ data[idx + 3] = bytes[1];
+ bytes = BitConverter.GetBytes(normZ);
+ data[idx + 4] = bytes[0];
+ data[idx + 5] = bytes[1];
+ bytes = BitConverter.GetBytes(0x2B88); // Alpha constant.
+ data[idx + 6] = bytes[0];
+ data[idx + 7] = bytes[1];
+ }
+ return data;
+ }
+
+ private unsafe bool overwriteFromStream(nint texture, Stream stream, bool cube = false)
+ {
+ byte[]? data = null;
+ if (cube)
+ {
+ using (StreamReader reader = new StreamReader(stream))
{
- for (x = 0; x < 32; x++)
- {
- Vector3 v = parsed[x,y,z];
- ushort normX = (ushort)Math.Round(v.X * scale);
- ushort normY = (ushort)Math.Round(v.Y * scale);
- ushort normZ = (ushort)Math.Round(v.Z * scale);
- bytes = BitConverter.GetBytes(normX);
- data[idx] = bytes[0];
- data[idx + 1] = bytes[1];
- bytes = BitConverter.GetBytes(normY);
- data[idx + 2] = bytes[0];
- data[idx + 3] = bytes[1];
- bytes = BitConverter.GetBytes(normZ);
- data[idx + 4] = bytes[0];
- data[idx + 5] = bytes[1];
- bytes = BitConverter.GetBytes(0x2B88); // Alpha constant.
- data[idx + 6] = bytes[0];
- data[idx + 7] = bytes[1];
- idx += 8;
- }
+ data = parseCubeLUT(reader);
}
}
- return data;
+ else
+ {
+ using (BinaryReader reader = new BinaryReader(stream, Encoding.ASCII, false))
+ {
+ data = parseWorldLUT(reader);
+ }
+ }
+ if (data == null)
+ {
+ return false;
+ }
+#if TEXTURE_FEATURE
+ fixed (byte *dataPointer = (byte[])data)
+ {
+ // DXGI_FORMAT_R16G16B16A16_FLOAT = 10
+ return new Texture(texture).Replace(dataPointer, 10, 32, 32, 32);
+ }
+#else
+ return true;
+#endif
}
- public unsafe bool OverwriteFromFile(nint resource, string path)
+ private unsafe bool overwriteFromFile(nint texture, string path)
{
+ string ext = path.Split('.').Last().ToLower();
using (FileStream stream = File.Open(path, FileMode.Open))
{
- byte[]? data = null;
- string ext = path.Split('.').Last().ToLower();
- if (ext == "tex")
+ return overwriteFromStream(texture, stream, ext == "cube");
+ }
+ }
+
+ private void reloadBlendLUT(nint lightingObject)
+ {
+ MemoryUtil.GetRef<float>(lightingObject + 0x1D4) = MemoryUtil.GetRef<float>(lightingObject + 0x1D0) + 1.0f;
+ }
+
+ private string[] fileList = [];
+ private static string[] selectedFile = [ "", "" ];
+ private static bool[] selectionStarted = [ false, false ];
+ private static bool[] selectedInvalid = [ false, false ];
+
+ public void DrawLUT(nint texture, nint lightingObject, int i, float width)
+ {
+ ImGui.PushID(i);
+ string lutPath = Marshal.PtrToStringAnsi(texture + 0xC)!;
+ ImGui.Text($"LUT {i}: {lutPath}");
+#if TEXTURE_FEATURE
+ if (ImGui.Button("Reset"))
+ {
+ MtFileStream? file = MtFileStream.FromPath($"native:\\{lutPath}.tex", OpenMode.Read, false);
+ if (file != null)
{
- using (BinaryReader reader = new BinaryReader(stream, Encoding.ASCII, false))
+ if (overwriteFromStream(texture, new MemoryStream(file.Read(file.Length))))
{
- data = parseWorldLUT(reader);
+ reloadBlendLUT(lightingObject);
}
+ file.Close();
}
- else if (ext == "cube")
+ selectedFile[i] = "";
+ selectedInvalid[i] = false;
+ }
+ ImGui.SameLine();
+ ImGui.SetNextItemWidth(width * 0.6f);
+ bool prevWasInvalid = selectedInvalid[i];
+ if (prevWasInvalid)
+ {
+ ImGui.PushStyleColor(ImGuiCol.Text, 0xFF0000FF);
+ }
+ if (ImGui.BeginCombo("##LUT Files", selectedFile[i], ImGuiComboFlags.HeightLarge))
+ {
+ if (prevWasInvalid)
{
- using (StreamReader reader = new StreamReader(stream))
- {
- data = parseCubeLUT(reader);
- }
+ ImGui.PopStyleColor();
}
- if (data == null)
+ if (!selectionStarted[i])
{
- return false;
+ fileList = Directory.Exists(addPath) ? Directory.GetFiles(addPath) : [];
+ selectionStarted[i] = true;
}
- fixed (byte *dataPointer = (byte[])data)
+ foreach (string filePath in fileList)
{
-#if TEXTURE_FEATURE
- // DXGI_FORMAT_R16G16B16A16_FLOAT = 10
- Renderer.ReplaceTexture(resource, dataPointer, 10, 32, 32, 32);
-#endif
+ string fileName = Path.GetFileName(filePath);
+ bool isSelected = selectedFile[i] == fileName;
+ if (ImGui.Selectable(fileName, isSelected))
+ {
+ selectedFile[i] = fileName;
+ if (!(selectedInvalid[i] = !overwriteFromFile(texture, filePath)))
+ {
+ reloadBlendLUT(lightingObject);
+ }
+ }
}
- return true;
+ ImGui.EndCombo();
}
+ else
+ {
+ if (prevWasInvalid)
+ {
+ ImGui.PopStyleColor();
+ }
+ selectionStarted[i] = false;
+ }
+#endif
+ ImGui.PopID();
}
}
}
diff --git a/Plugin.cs b/Plugin.cs
index 820b79f..6547a0a 100755
--- a/Plugin.cs
+++ b/Plugin.cs
@@ -6,7 +6,6 @@
using System.Numerics;
using System.Globalization;
using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
#if ENABLE_ASSERTS
using System.Diagnostics;
#endif
@@ -24,11 +23,10 @@ using SharpPluginLoader.Core.Resources;
#endif
// @TODO:
-// - Cleanup SSR patches.
// - Configurable Broad Area Shadow Resolution.
// - Hook sMhScene constructor to set hqMode.
// - Optimized update logic.
-// - Only update non-override values when ui is shown.
+// - Only update non-override values when UI is shown.
// - Map sky params.
// - Lights refactor.
// - Descriptions.
@@ -50,6 +48,7 @@ using SharpPluginLoader.Core.Resources;
// - The Rotten Vale jump out of Southeast Camp. Wall on the opposite side slightly to the left.
// - Special Arena.
// - Elder's Recess Lavasioth area.
+// - Hoarfrost pit area with wedge beetles.
//
// Known issues to think about:
// - Hair clipping while looking down.
@@ -828,8 +827,7 @@ namespace WorldTuningTool
if (NoOverride)
{
- // Dependent on overall ImGui style.
- ImGui.SetCursorPos(ImGui.GetCursorPos() + new Vector2(40.0f, 0.0f));
+ ImGui.SetCursorPos(ImGui.GetCursorPos() + new Vector2(ImGui.GetFrameHeight() + ImGui.GetStyle().ItemSpacing.X, 0.0f));
}
else if (!assumeOverride)
{
@@ -1592,16 +1590,10 @@ namespace WorldTuningTool
private Hook<CreateLightingObject>? createLightingObject;
private Hook<DestroyLightingObject>? destroyLightingObject;
private nint lightingObject = 0x0;
- private delegate void SetLightingParameters(nint lightingObjectInternal);
- private Hook<SetLightingParameters>? setLightingParams;
- private NativeAction<nint> setLightingParamsFunc;
private delegate void UpdateLightingParameters(nint stackOffset, nint lightingObjectInternal);
private Hook<UpdateLightingParameters>? updateLightingParams;
private Hook<UpdateLightingParameters>? updateLutBlend;
- private static WorldLUT lut = new WorldLUT();
- private static string selectedLut = "";
- private static bool lutSelectionStarted = false;
- private static bool selectedLutInvalid = false;
+ private static WorldLUTs luts = new WorldLUTs();
private static Parameter[] lightingParameters = {
newParameter<int>("Light Tone Map Type", 0x16C, ParameterType.INT, pMinMaxStep(1, 6, 1)),
newParameter<bool>("Light Compute Luminance", 0x170, ParameterType.BOOL),
@@ -1624,7 +1616,12 @@ namespace WorldTuningTool
};
private static Parameter[] brightnessParameters = {
newParameter<float>("Gamma Correct", 0x1C8, ParameterType.FLOAT, pStep(0.001f)),
- newParameter<float>("Gamma Correct EX", 0x1CC, ParameterType.FLOAT, pStep(0.001f))
+ newParameter<float>("Gamma Correct EX", 0x1CC, ParameterType.FLOAT, pStep(0.001f)),
+ newParameterView<bool>("Hdr Output", 0x21A, ParameterType.BOOL),
+ newParameter<float>("Hdr Output White Level", 0x21C, ParameterType.FLOAT, pStep(0.05f)),
+ newParameter<float>("Hdr Output Gamut Mapping Ratio", 0x220, ParameterType.FLOAT, pStep(0.001f)),
+ newParameter<float>("Hdr Output Gamma", 0x224, ParameterType.FLOAT, pStep(0.001f)),
+ newParameter<bool>("Hdr Is Gui Hdr Gamma", 0x228, ParameterType.BOOL)
};
private static MtObject? sLightProbes = null;
private static Parameter[] lightProbesParameters = {
@@ -1735,7 +1732,7 @@ namespace WorldTuningTool
private static Parameter[] allParameters = new Parameter[]{ hqMode }
.Concat(lodParameters)
.Concat(snowParameters)
- .Concat(new Parameter[] { shadowResParameter })
+ .Append(shadowResParameter)
.Concat(shadowParameters2)
.Concat(shadowCascadeParameters)
.Concat(broadAreaShadowParameters)
@@ -1745,6 +1742,7 @@ namespace WorldTuningTool
.Concat(sslrParameters)
.Concat(passthroughParameters)
.Concat(lightingParameters)
+ .Concat(brightnessParameters)
.Concat(bloomParameters)
.Concat(dofParameters)
.Concat(motionBlurParameters)
@@ -2143,7 +2141,7 @@ namespace WorldTuningTool
onAreaChange = Hook.Create<OnAreaChange>(0x141AC27D0, OnAreaChangeHook); // nint
- // Needed for at least "Broad Area Shadow Dir". Otherwise it will flicker during an update on center change.
+ // Needed for at least "Broad Area Shadow Dir". Otherwise it will flicker on center change.
evalSceneParams = Hook.Create<EvalSceneParams>(0x1423C3790, EvalSceneParamsHook); // nint, nint, int, nint
// Light Dir XZY is updated seperately at 0x1420397F0, we assume this function always happens later, though.
@@ -2156,8 +2154,6 @@ namespace WorldTuningTool
createLightingObject = Hook.Create<CreateLightingObject>(0x1424CDE20, CreateLightingObjectHook);
destroyLightingObject = Hook.Create<DestroyLightingObject>(0x1424CE380, DestroyLightingObjectHook); // nint, int
- setLightingParams = Hook.Create<SetLightingParameters>(0x1424CF1C0, SetLightingParametersHook); // nint
- setLightingParamsFunc = new NativeAction<nint>(0x1424CF1C0);
updateLutBlend = Hook.Create<UpdateLightingParameters>(0x1416D8DF0, UpdateLutBlendHook); // nint, nint
createBloomObject = Hook.Create<CreateBloomObject>(0x1424CB3C0, CreateBloomObjectHook);
@@ -2326,7 +2322,7 @@ namespace WorldTuningTool
ssrShr3 = new Patch(new IntPtr(0x14269E07A), [0x90, 0x90]);
ssrShr4 = new Patch(new IntPtr(0x14269E080), [0x90, 0x90]);
// Approximate depth mip resolution.
- ssrShr5 = new Patch(new IntPtr(0x14269DED3) + 0x2, [0x3]);
+ ssrShr5 = new Patch(new IntPtr(0x14269DED3) + 0x2, [0x3]); // 4 -> 3
ssrShr6 = new Patch(new IntPtr(0x14269DEDA) + 0x3, [0x3]);
// Depth mips pass 1 dispatch dimensions.
ssrSars1 = new Patch(new IntPtr(0x142282FD8) + 0x3, [0x3]); // 4 -> 3
@@ -2913,15 +2909,6 @@ namespace WorldTuningTool
return destroyLightingObject!.Original(lightingObjectInternal, unknownInt);
}
- private void SetLightingParametersHook(nint lightingObjectInternal)
- {
- setLightingParams!.Original(lightingObjectInternal);
- if (lightingObject == lightingObjectInternal)
- {
- selectedLut = "";
- }
- }
-
private void UpdateLutBlendHook(nint stackOffset, nint lightingObjectInternal)
{
updateLutBlend!.Original(stackOffset, lightingObjectInternal);
@@ -3862,91 +3849,33 @@ namespace WorldTuningTool
}
ImGui.PopID();
- /*
- ImGui.PushID("Snow");
- if (ImGui.CollapsingHeader("Snow"))
- {
- ImGui.Text($"Address: 0x{sMhScene!.Instance:X}");
- foreach (Parameter param in snowParameters)
- {
- param.Draw(width);
- }
- }
- ImGui.PopID();
- */
-
ImGui.PushID("Lighting");
if (ImGui.CollapsingHeader("Lighting"))
{
+ ImGui.Text($"Address: 0x{lightingObject:X}");
if (lightingObject != 0x0)
{
- ImGui.Text($"Address: 0x{lightingObject:X}");
- if (ImGui.CollapsingHeader("LUT"))
+ if (ImGui.CollapsingHeader("LUTs"))
{
- nint d3dResource = WorldLUT.ProbeD3DResource(lightingObject);
- if (d3dResource != 0x0)
- {
- if (ImGui.Button("Reset"))
- {
- // Attempt to force check for reloading LUT to pass.
- MemoryUtil.GetRef<float>(lightingObject + 0x1D4) = MemoryUtil.GetRef<float>(lightingObject + 0x1D0) + 1.0f;
- }
- ImGui.SameLine();
- ImGui.SetNextItemWidth(width * 0.625f);
- bool prevLutWasInvalid = selectedLutInvalid;
- if (prevLutWasInvalid)
- {
- ImGui.PushStyleColor(ImGuiCol.Text, 0xFF0000FF);
- }
- if (ImGui.BeginCombo("##LUT Files", selectedLut, ImGuiComboFlags.HeightLarge))
- {
- if (prevLutWasInvalid)
- {
- ImGui.PopStyleColor();
- }
- if (!lutSelectionStarted)
- {
- lut.ReloadLUTs();
- lutSelectionStarted = true;
- }
- foreach (string lutPath in lut.GetLUTs())
- {
- string lutFile = Path.GetFileName(lutPath);
- bool isSelected = selectedLut == lutFile;
- if (ImGui.Selectable(lutFile, isSelected))
- {
- selectedLutInvalid = !lut.OverwriteFromFile(d3dResource, lutPath);
- selectedLut = lutFile;
- }
- }
- ImGui.EndCombo();
- }
- else
- {
- if (prevLutWasInvalid)
- {
- ImGui.PopStyleColor();
- }
- lutSelectionStarted = false;
- }
- }
+ nint lutBlendTexture = MemoryUtil.Read<nint>(lightingObject + 0x1C0);
+ ImGui.Text($"LUT Blend: 0x{lutBlendTexture:X}");
nint lutMap0 = MemoryUtil.Read<nint>(lightingObject + 0x1A8);
if (lutMap0 != 0x0)
{
- ImGui.Text($"LUT Map 0: {Marshal.PtrToStringAnsi(lutMap0 + 0xC)!}");
+ luts.DrawLUT(lutMap0, lightingObject, 0, width);
}
nint lutMap1 = MemoryUtil.Read<nint>(lightingObject + 0x1B0);
if (lutMap1 != 0x0)
{
- ImGui.Text($"LUT Map 1: {Marshal.PtrToStringAnsi(lutMap1 + 0xC)!}");
+ luts.DrawLUT(lutMap1, lightingObject, 1, width);
}
}
foreach (Parameter param in lightingParameters)
{
param.Draw(width);
}
- ImGui.Separator();
}
+ ImGui.Separator();
ImGui.Text($"Address: 0x{sMhRender!.Instance:X}");
foreach (Parameter param in brightnessParameters)
{
@@ -3964,9 +3893,9 @@ namespace WorldTuningTool
ImGui.PushID("Bloom");
if (ImGui.CollapsingHeader("Bloom"))
{
+ ImGui.Text($"Address: 0x{bloomObject:X}");
if (bloomObject != 0x0)
{
- ImGui.Text($"Address: 0x{bloomObject:X}");
foreach (Parameter param in bloomParameters)
{
param.Draw(width);
@@ -3978,9 +3907,9 @@ namespace WorldTuningTool
ImGui.PushID("DepthOfField");
if (ImGui.CollapsingHeader("Depth of Field"))
{
+ ImGui.Text($"Address: 0x{dofObject:X}");
if (dofObject != 0x0)
{
- ImGui.Text($"Address: 0x{dofObject:X}");
foreach (Parameter param in dofParameters)
{
param.Draw(width);
@@ -3992,9 +3921,9 @@ namespace WorldTuningTool
ImGui.PushID("MotionBlur");
if (ImGui.CollapsingHeader("Motion Blur"))
{
+ ImGui.Text($"Address: 0x{motionBlurObject:X}");
if (motionBlurObject != 0x0)
{
- ImGui.Text($"Address: 0x{motionBlurObject:X}");
foreach (Parameter param in motionBlurParameters)
{
param.Draw(width);
@@ -4006,9 +3935,9 @@ namespace WorldTuningTool
ImGui.PushID("FXAA");
if (ImGui.CollapsingHeader("FXAA"))
{
+ ImGui.Text($"Address: 0x{fxaaObject:X}");
if (fxaaObject != 0x0)
{
- ImGui.Text($"Address: 0x{fxaaObject:X}");
foreach (Parameter param in fxaaParameters)
{
param.Draw(width);
@@ -4020,9 +3949,9 @@ namespace WorldTuningTool
ImGui.PushID("TAA");
if (ImGui.CollapsingHeader("TAA"))
{
+ ImGui.Text($"Address: 0x{taaObject:X}");
if (taaObject != 0x0)
{
- ImGui.Text($"Address: 0x{taaObject:X}");
foreach (Parameter param in taaParameters)
{
param.Draw(width);
diff --git a/Shaders/alpha_as_luma.hlsl b/Shaders/alpha_as_luma.hlsl
index 525f3c6..dff76c6 100644
--- a/Shaders/alpha_as_luma.hlsl
+++ b/Shaders/alpha_as_luma.hlsl
@@ -1,14 +1,14 @@
// https://stackoverflow.com/a/37624009
float inverseGamma(float t)
{
- return ((t <= 0.0404482362771076) ? (t/12.92) : pow((t + 0.055)/1.055, 2.4));
+ return (t <= 0.0404482362771076) ? (t/12.92) : pow((t + 0.055)/1.055, 2.4);
}
// CIE L*a*b* f function (used to convert XYZ to L*a*b*)
// http://en.wikipedia.org/wiki/Lab_color_space
float LABF(float t)
{
- return ((t >= 8.85645167903563082e-3) ? pow(t, (1.0/3.0)) : (841.0/108.0)*t + (4.0/29.0));
+ return (t >= 8.85645167903563082e-3) ? pow(t, (1.0/3.0)) : (841.0/108.0)*t + (4.0/29.0);
}
float rgbToCIEL(float3 p)