summaryrefslogtreecommitdiff
path: root/LUT.cs
diff options
context:
space:
mode:
Diffstat (limited to 'LUT.cs')
-rw-r--r--LUT.cs207
1 files changed, 207 insertions, 0 deletions
diff --git a/LUT.cs b/LUT.cs
new file mode 100644
index 0000000..cb8975c
--- /dev/null
+++ b/LUT.cs
@@ -0,0 +1,207 @@
+//#define TEXTURE_FEATURE
+
+using System.Text;
+using System.Numerics;
+using SharpPluginLoader.Core;
+using SharpPluginLoader.Core.Rendering;
+
+namespace WorldTuningTool
+{
+ public class WorldLUT
+ {
+ private const string lutsPath = "nativePC/plugins/CSharp/LUT";
+
+ public WorldLUT() { }
+
+ public string[] GetLUTs()
+ {
+ if (!Directory.Exists(lutsPath))
+ {
+ return [];
+ }
+ return Directory.GetFiles(lutsPath);
+ }
+
+ // https://github.com/AsteriskAmpersand/CrappyLUTStudio--CLUTS-/blob/5af10daaa5f295b106cc5db09530a6fe5a4320d4/LUT.py#L35
+ public byte[]? parseWorldLUT(BinaryReader reader)
+ {
+ byte[] signature = reader.ReadBytes(4);
+ if (!(signature[0] == 0x54 && signature[1] == 0x45 &&
+ (signature[2] == 0x58 && signature[3] == 0x0)))
+ {
+ return null;
+ }
+ ulong version = reader.ReadUInt64();
+ uint datablock = reader.ReadUInt32();
+ uint format = reader.ReadUInt32();
+ uint mipCount = reader.ReadUInt32();
+ uint width = reader.ReadUInt32();
+ uint height = reader.ReadUInt32();
+ uint mipListCount = reader.ReadUInt32();
+ uint typeData = reader.ReadUInt32();
+ uint depth = reader.ReadUInt32();
+ byte[] NULL0 = reader.ReadBytes(12);
+ int NEG0 = reader.ReadInt32();
+ byte[] NULL1 = reader.ReadBytes(8);
+ int Special = reader.ReadInt32();
+ byte[] NULL2 = reader.ReadBytes(16);
+ byte[] NEG1 = reader.ReadBytes(32);
+ byte[] flags = reader.ReadBytes(32);
+ byte[] NULLX = reader.ReadBytes(32);
+ reader.BaseStream.Position = (long)reader.ReadUInt64();
+ if (!(width == 32 && height == 32 && depth == 32))
+ {
+ return null;
+ }
+ return reader.ReadBytes((int)(width * height * depth * 8));
+ }
+
+ // https://drive.google.com/file/d/143Eh08ZYncCAMwJ1q4gWxVOqR_OSWYvs/view
+ // When does DOMAIN_MIN/MAX apply?
+ public byte[]? parseCubeLUT(StreamReader reader)
+ {
+ string? line;
+ Vector3[,,]? parsed = null;
+ int dim = 0, last = 0;
+ int x = 0, y = 0, z = 0;
+ while ((line = reader.ReadLine()) != null)
+ {
+ if (line.StartsWith("LUT_3D_SIZE"))
+ {
+ try
+ {
+ dim = Convert.ToInt32(line.Split(' ').Last());
+ }
+ catch (FormatException)
+ {
+ return null;
+ }
+ catch (OverflowException)
+ {
+ return null;
+ }
+ if (dim != 32)
+ {
+ return null;
+ }
+ parsed = new Vector3[dim,dim,dim];
+ last = dim - 1;
+ while ((line = reader.ReadLine()) != null)
+ {
+ if (line == "") continue;
+ if (line[0] == '0' || line[0] == '1')
+ {
+ break;
+ }
+ }
+ if (line == null)
+ {
+ break;
+ }
+ }
+ if (parsed != null)
+ {
+ try
+ {
+ parsed[x,y,z] = Plugin.StringToVector3(line, ' ');
+ }
+ catch (FormatException)
+ {
+ return null;
+ }
+ catch (OverflowException)
+ {
+ return null;
+ }
+ if (x == last)
+ {
+ if (y == last)
+ {
+ z++;
+ y = 0;
+ }
+ else
+ {
+ y++;
+ }
+ x = 0;
+ }
+ else
+ {
+ x++;
+ }
+ }
+ }
+ if (parsed == null)
+ {
+ return null;
+ }
+ const int lutDataSize = 32 * 32 * 32 * 8;
+ byte[] data = new byte[lutDataSize], bytes;
+ float scale = MathF.Pow(2, 14) - 1;
+ int idx = 0;
+ for (z = 0; z < 32; z++)
+ {
+ for (y = 0; y < 32; y++)
+ {
+ 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;
+ }
+ }
+ }
+ return data;
+ }
+
+ public unsafe bool OverwriteFromFile(nint resource, string path)
+ {
+ using (FileStream stream = File.Open(path, FileMode.Open))
+ {
+ byte[]? data = null;
+ string ext = path.Split('.').Last().ToLower();
+ if (ext == "tex")
+ {
+ using (BinaryReader reader = new BinaryReader(stream, Encoding.ASCII, false))
+ {
+ data = parseWorldLUT(reader);
+ }
+ }
+ else if (ext == "cube")
+ {
+ using (StreamReader reader = new StreamReader(stream))
+ {
+ data = parseCubeLUT(reader);
+ }
+ }
+ if (data == null)
+ {
+ return false;
+ }
+ fixed (byte *dataPointer = (byte[])data)
+ {
+#if TEXTURE_FEATURE
+ // DXGI_FORMAT_R16G16B16A16_FLOAT = 10
+ Renderer.ReplaceTexture(resource, dataPointer, 10, 32, 32, 32);
+#endif
+ }
+ return true;
+ }
+ }
+ }
+}