using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BoneLib.BoneMenu;
using CineLab;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using MelonLoader;
using MelonLoader.Preferences;
using MelonLoader.Utils;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: MelonInfo(typeof(CineLabMod), "CineLab", "0.4.0", "CineLab contributors", null)]
[assembly: MelonGame("Stress Level Zero", "BONELAB")]
[assembly: MelonAdditionalDependencies(new string[] { "BoneLib" })]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("CineLab")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("CineLab")]
[assembly: AssemblyTitle("CineLab")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Embedded]
[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
namespace CineLab
{
public enum FilterChoice
{
Original,
Cinematic,
Vintage,
ColdSteel,
Noir,
GoldenHour
}
public enum TonemapChoice
{
GameDefault,
Neutral,
ACES
}
public sealed class FilterPreset
{
public string Name;
public Color Tint;
public Color Shadows;
public Color Highlights;
public float Balance;
public float Saturation;
public float Contrast;
public FilterPreset(string n, Color t, Color s, Color h, float b, float sat, float c)
{
//IL_0010: Unknown result type (might be due to invalid IL or missing references)
//IL_0011: Unknown result type (might be due to invalid IL or missing references)
//IL_0017: Unknown result type (might be due to invalid IL or missing references)
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
//IL_001e: Unknown result type (might be due to invalid IL or missing references)
//IL_0020: Unknown result type (might be due to invalid IL or missing references)
Name = n;
Tint = t;
Shadows = s;
Highlights = h;
Balance = b;
Saturation = sat;
Contrast = c;
}
}
public sealed class CineLabMod : MelonMod
{
internal static MelonPreferences_Category Category;
internal static MelonPreferences_Entry<bool> Enabled;
internal static MelonPreferences_Entry<float> Exposure;
internal static MelonPreferences_Entry<float> Temperature;
internal static MelonPreferences_Entry<float> BlackBoost;
internal static MelonPreferences_Entry<float> Contrast;
internal static MelonPreferences_Entry<float> Saturation;
internal static MelonPreferences_Entry<float> ShadowLift;
internal static MelonPreferences_Entry<float> FilterIntensity;
internal static MelonPreferences_Entry<int> Filter;
internal static MelonPreferences_Entry<int> Tonemap;
internal static MelonPreferences_Entry<string> LutFile;
internal static MelonPreferences_Entry<float> LutStrength;
internal static MelonPreferences_Entry<float> BloomIntensity;
internal static MelonPreferences_Entry<float> BloomThreshold;
internal static MelonPreferences_Entry<float> VignetteIntensity;
internal static MelonPreferences_Entry<float> GrainIntensity;
private static readonly Color White = Color.white;
private static readonly Color Grey = new Color(0.5f, 0.5f, 0.5f, 1f);
private static readonly FilterPreset[] Presets = new FilterPreset[6]
{
new FilterPreset("Original", White, Grey, Grey, 0f, 0f, 0f),
new FilterPreset("Cinematic", new Color(1f, 0.96f, 0.9f), new Color(0.35f, 0.45f, 0.6f), new Color(0.7f, 0.55f, 0.4f), 10f, -5f, 12f),
new FilterPreset("Vintage", new Color(1f, 0.92f, 0.78f), new Color(0.45f, 0.38f, 0.3f), new Color(0.75f, 0.62f, 0.45f), 0f, -30f, -10f),
new FilterPreset("Cold Steel", new Color(0.88f, 0.94f, 1f), new Color(0.25f, 0.4f, 0.65f), new Color(0.55f, 0.65f, 0.8f), -10f, -15f, 10f),
new FilterPreset("Noir", White, Grey, Grey, 0f, -100f, 30f),
new FilterPreset("Golden Hour", new Color(1f, 0.88f, 0.7f), new Color(0.45f, 0.35f, 0.35f), new Color(0.95f, 0.65f, 0.3f), 20f, 10f, 5f)
};
private Page cineLabPage;
private Page lutPage;
private BoolElement eEnabled;
private FloatElement eExposure;
private FloatElement eTemp;
private FloatElement eBlack;
private FloatElement eContrast;
private FloatElement eSat;
private FloatElement eShadow;
private FloatElement eFilterInt;
private FloatElement eLutStrength;
private FloatElement eBloom;
private FloatElement eBloomThr;
private FloatElement eVig;
private FloatElement eGrain;
private EnumElement eFilter;
private EnumElement eTonemap;
private GameObject volumeObj;
private Volume volume;
private VolumeProfile profile;
private ColorAdjustments colorAdj;
private WhiteBalance wb;
private LiftGammaGain lgg;
private SplitToning split;
private ColorLookup lookup;
private Tonemapping tonemap;
private Bloom bloom;
private Vignette vignette;
private FilmGrain grain;
private Texture2D currentLut;
private readonly Dictionary<string, Texture2D> lutCache = new Dictionary<string, Texture2D>();
private string lutDir;
private bool lutRestorePending = true;
private bool logLutState;
private float nextApply;
private float nextCamCheck;
private bool loggedPipeline;
public override void OnInitializeMelon()
{
Category = MelonPreferences.CreateCategory("CineLab", "CineLab Color Grading");
Enabled = Category.CreateEntry<bool>("Enabled", false, "Enable effect (starts disabled)", (string)null, false, false, (ValueValidator)null, (string)null);
Exposure = Category.CreateEntry<float>("ExposureEV", 0f, "Exposure in EV stops", (string)null, false, false, (ValueValidator)null, (string)null);
Temperature = Category.CreateEntry<float>("Temperature", 0f, "Cool (-1) to warm (+1)", (string)null, false, false, (ValueValidator)null, (string)null);
BlackBoost = Category.CreateEntry<float>("BlackBoost", 0f, "Lift dark values (0-1)", (string)null, false, false, (ValueValidator)null, (string)null);
Contrast = Category.CreateEntry<float>("Contrast", 1.1f, "Contrast multiplier", (string)null, false, false, (ValueValidator)null, (string)null);
Saturation = Category.CreateEntry<float>("Saturation", 1.15f, "Saturation multiplier", (string)null, false, false, (ValueValidator)null, (string)null);
ShadowLift = Category.CreateEntry<float>("ShadowLift", 0f, "Additional shadow lift (0-0.3)", (string)null, false, false, (ValueValidator)null, (string)null);
Filter = Category.CreateEntry<int>("Filter", 1, "0 Original, 1 Cinematic, 2 Vintage, 3 Cold Steel, 4 Noir, 5 Golden Hour", (string)null, false, false, (ValueValidator)null, (string)null);
FilterIntensity = Category.CreateEntry<float>("FilterIntensity", 0.65f, "Filter mix (0-1)", (string)null, false, false, (ValueValidator)null, (string)null);
LutFile = Category.CreateEntry<string>("LutFile", "", "File name of the selected LUT in UserData/CineLab/LUTs (empty = none)", (string)null, false, false, (ValueValidator)null, (string)null);
LutStrength = Category.CreateEntry<float>("LutStrength", 1f, "LUT strength (0-1)", (string)null, false, false, (ValueValidator)null, (string)null);
Tonemap = Category.CreateEntry<int>("Tonemapping", 0, "0 = leave the game's own, 1 = Neutral, 2 = ACES", (string)null, false, false, (ValueValidator)null, (string)null);
BloomIntensity = Category.CreateEntry<float>("BloomIntensity", 0f, "Bloom (0 = off, leaves the game's own bloom alone)", (string)null, false, false, (ValueValidator)null, (string)null);
BloomThreshold = Category.CreateEntry<float>("BloomThreshold", 0.5f, "Bloom brightness threshold", (string)null, false, false, (ValueValidator)null, (string)null);
VignetteIntensity = Category.CreateEntry<float>("VignetteIntensity", 0f, "Vignette (0 = off). Can be uncomfortable in VR.", (string)null, false, false, (ValueValidator)null, (string)null);
GrainIntensity = Category.CreateEntry<float>("FilmGrain", 0f, "Film grain (0 = off)", (string)null, false, false, (ValueValidator)null, (string)null);
SetupLutFolder();
BuildMenu();
}
private void BuildMenu()
{
//IL_000d: Unknown result type (might be due to invalid IL or missing references)
//IL_002a: Unknown result type (might be due to invalid IL or missing references)
//IL_006d: Unknown result type (might be due to invalid IL or missing references)
//IL_0080: Unknown result type (might be due to invalid IL or missing references)
//IL_009d: Unknown result type (might be due to invalid IL or missing references)
//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
//IL_0111: Unknown result type (might be due to invalid IL or missing references)
//IL_0133: Unknown result type (might be due to invalid IL or missing references)
//IL_0147: Unknown result type (might be due to invalid IL or missing references)
//IL_0195: Unknown result type (might be due to invalid IL or missing references)
//IL_01e3: Unknown result type (might be due to invalid IL or missing references)
//IL_0231: Unknown result type (might be due to invalid IL or missing references)
//IL_027f: Unknown result type (might be due to invalid IL or missing references)
//IL_02cd: Unknown result type (might be due to invalid IL or missing references)
//IL_031f: Unknown result type (might be due to invalid IL or missing references)
//IL_0333: Unknown result type (might be due to invalid IL or missing references)
//IL_0386: Unknown result type (might be due to invalid IL or missing references)
//IL_03d4: Unknown result type (might be due to invalid IL or missing references)
//IL_03ec: Unknown result type (might be due to invalid IL or missing references)
//IL_0439: Unknown result type (might be due to invalid IL or missing references)
//IL_0462: Unknown result type (might be due to invalid IL or missing references)
//IL_0476: Unknown result type (might be due to invalid IL or missing references)
//IL_04c1: Unknown result type (might be due to invalid IL or missing references)
//IL_050f: Unknown result type (might be due to invalid IL or missing references)
//IL_055d: Unknown result type (might be due to invalid IL or missing references)
//IL_05ab: Unknown result type (might be due to invalid IL or missing references)
//IL_05fd: Unknown result type (might be due to invalid IL or missing references)
try
{
cineLabPage = Page.Root.CreatePage("CineLab", Color.white, 0, true);
eEnabled = cineLabPage.CreateBool("Enable Color Grading", Color.white, Enabled.Value, (Action<bool>)delegate(bool v)
{
Enabled.Value = v;
});
Page val = cineLabPage.CreatePage("Presets", Color.yellow, 0, true);
val.CreateFunction("Cinematic", Color.white, (Action)delegate
{
ApplyPreset(0);
});
val.CreateFunction("Vivid", Color.white, (Action)delegate
{
ApplyPreset(1);
});
val.CreateFunction("Moody", Color.white, (Action)delegate
{
ApplyPreset(2);
});
val.CreateFunction("Retro Film", Color.white, (Action)delegate
{
ApplyPreset(3);
});
val.CreateFunction("Golden Hour", Color.white, (Action)delegate
{
ApplyPreset(4);
});
val.CreateFunction("Reset / Bypass", Color.red, (Action)ResetSettings);
Page val2 = cineLabPage.CreatePage("Color", Color.white, 0, true);
eExposure = val2.CreateFloat("Exposure", Color.white, Exposure.Value, 0.1f, -3f, 3f, (Action<float>)delegate(float v)
{
Exposure.Value = v;
});
eTemp = val2.CreateFloat("Warm / Cool", Color.white, Temperature.Value, 0.05f, -1f, 1f, (Action<float>)delegate(float v)
{
Temperature.Value = v;
});
eBlack = val2.CreateFloat("Black Boost", Color.white, BlackBoost.Value, 0.05f, 0f, 1f, (Action<float>)delegate(float v)
{
BlackBoost.Value = v;
});
eShadow = val2.CreateFloat("Shadow Lift", Color.white, ShadowLift.Value, 0.01f, 0f, 0.3f, (Action<float>)delegate(float v)
{
ShadowLift.Value = v;
});
eContrast = val2.CreateFloat("Contrast", Color.white, Contrast.Value, 0.05f, 0.5f, 1.8f, (Action<float>)delegate(float v)
{
Contrast.Value = v;
});
eSat = val2.CreateFloat("Saturation", Color.white, Saturation.Value, 0.05f, 0f, 2f, (Action<float>)delegate(float v)
{
Saturation.Value = v;
});
Page val3 = cineLabPage.CreatePage("Filter & LUT", Color.cyan, 0, true);
eFilter = val3.CreateEnum("Filter", Color.cyan, (Enum)(FilterChoice)Mathf.Clamp(Filter.Value, 0, Presets.Length - 1), (Action<Enum>)delegate(Enum v)
{
Filter.Value = (int)(FilterChoice)(object)v;
});
eFilterInt = val3.CreateFloat("Filter Intensity", Color.cyan, FilterIntensity.Value, 0.05f, 0f, 1f, (Action<float>)delegate(float v)
{
FilterIntensity.Value = v;
});
lutPage = val3.CreatePage("Choose LUT", Color.cyan, 0, true);
eLutStrength = val3.CreateFloat("LUT Strength", Color.cyan, LutStrength.Value, 0.05f, 0f, 1f, (Action<float>)delegate(float v)
{
LutStrength.Value = v;
});
val3.CreateFunction("Rescan LUT Folder", Color.cyan, (Action)RescanLuts);
RebuildLutMenu();
Page val4 = cineLabPage.CreatePage("Effects", Color.magenta, 0, true);
eTonemap = val4.CreateEnum("Tonemapping", Color.white, (Enum)(TonemapChoice)Mathf.Clamp(Tonemap.Value, 0, 2), (Action<Enum>)delegate(Enum v)
{
Tonemap.Value = (int)(TonemapChoice)(object)v;
});
eBloom = val4.CreateFloat("Bloom", Color.white, BloomIntensity.Value, 0.05f, 0f, 2f, (Action<float>)delegate(float v)
{
BloomIntensity.Value = v;
});
eBloomThr = val4.CreateFloat("Bloom Threshold", Color.white, BloomThreshold.Value, 0.05f, 0.3f, 2f, (Action<float>)delegate(float v)
{
BloomThreshold.Value = v;
});
eVig = val4.CreateFloat("Vignette", Color.white, VignetteIntensity.Value, 0.05f, 0f, 0.6f, (Action<float>)delegate(float v)
{
VignetteIntensity.Value = v;
});
eGrain = val4.CreateFloat("Film Grain", Color.white, GrainIntensity.Value, 0.05f, 0f, 1f, (Action<float>)delegate(float v)
{
GrainIntensity.Value = v;
});
cineLabPage.CreateFunction("Save Settings", Color.green, (Action)delegate
{
MelonPreferences.Save();
MelonLogger.Msg("CineLab: settings saved.");
});
MelonLogger.Msg("CineLab BoneMenu page created.");
}
catch (Exception ex)
{
MelonLogger.Error("Could not create CineLab BoneMenu page: " + ex);
}
}
private void SyncMenu()
{
try
{
if (eEnabled != null)
{
eEnabled.Value = Enabled.Value;
eExposure.Value = Exposure.Value;
eTemp.Value = Temperature.Value;
eBlack.Value = BlackBoost.Value;
eShadow.Value = ShadowLift.Value;
eContrast.Value = Contrast.Value;
eSat.Value = Saturation.Value;
eFilter.Value = (FilterChoice)Mathf.Clamp(Filter.Value, 0, Presets.Length - 1);
eFilterInt.Value = FilterIntensity.Value;
eLutStrength.Value = LutStrength.Value;
eTonemap.Value = (TonemapChoice)Mathf.Clamp(Tonemap.Value, 0, 2);
eBloom.Value = BloomIntensity.Value;
eBloomThr.Value = BloomThreshold.Value;
eVig.Value = VignetteIntensity.Value;
eGrain.Value = GrainIntensity.Value;
}
}
catch (Exception ex)
{
MelonLogger.Warning("CineLab: menu sync failed: " + ex.Message);
}
}
public override void OnApplicationQuit()
{
MelonPreferences.Save();
}
public override void OnSceneWasInitialized(int buildIndex, string sceneName)
{
if (!loggedPipeline)
{
loggedPipeline = true;
RenderPipelineAsset currentRenderPipeline = GraphicsSettings.currentRenderPipeline;
MelonLogger.Msg("CineLab: render pipeline = " + (((Object)(object)currentRenderPipeline == (Object)null) ? "NONE (Built-in)" : (((object)currentRenderPipeline).GetType().Name + " / " + ((Object)currentRenderPipeline).name)));
}
EnsureVolume();
EnableCameraPostProcessing();
if (lutRestorePending)
{
lutRestorePending = false;
RestoreSavedLut();
}
}
public override void OnUpdate()
{
float unscaledTime = Time.unscaledTime;
if (unscaledTime >= nextCamCheck)
{
nextCamCheck = unscaledTime + 2f;
EnsureVolume();
EnableCameraPostProcessing();
}
if (unscaledTime >= nextApply)
{
nextApply = unscaledTime + 0.05f;
Apply();
}
}
private void EnsureVolume()
{
//IL_002d: Unknown result type (might be due to invalid IL or missing references)
//IL_0037: Expected O, but got Unknown
if (!((Object)(object)volumeObj != (Object)null) || !((Object)(object)volume != (Object)null))
{
volumeObj = new GameObject("CineLab_Volume");
Object.DontDestroyOnLoad((Object)(object)volumeObj);
((Object)volumeObj).hideFlags = (HideFlags)61;
volume = volumeObj.AddComponent<Volume>();
volume.isGlobal = true;
volume.priority = 1000f;
volume.weight = 1f;
profile = ScriptableObject.CreateInstance<VolumeProfile>();
volume.sharedProfile = profile;
colorAdj = profile.Add<ColorAdjustments>(true);
wb = profile.Add<WhiteBalance>(true);
lgg = profile.Add<LiftGammaGain>(true);
split = profile.Add<SplitToning>(true);
lookup = profile.Add<ColorLookup>(true);
tonemap = profile.Add<Tonemapping>(true);
bloom = profile.Add<Bloom>(true);
vignette = profile.Add<Vignette>(true);
grain = profile.Add<FilmGrain>(true);
}
}
private void EnableCameraPostProcessing()
{
try
{
foreach (Camera item in (Il2CppArrayBase<Camera>)(object)Camera.allCameras)
{
UniversalAdditionalCameraData universalAdditionalCameraData = CameraExtensions.GetUniversalAdditionalCameraData(item);
if ((Object)(object)universalAdditionalCameraData != (Object)null && !universalAdditionalCameraData.renderPostProcessing)
{
universalAdditionalCameraData.renderPostProcessing = true;
}
}
}
catch (Exception ex)
{
MelonLogger.Warning("CineLab: camera post-processing flag failed: " + ex.Message);
}
}
private void Apply()
{
//IL_011a: Unknown result type (might be due to invalid IL or missing references)
//IL_0120: Unknown result type (might be due to invalid IL or missing references)
//IL_0126: Unknown result type (might be due to invalid IL or missing references)
//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
//IL_01ce: Unknown result type (might be due to invalid IL or missing references)
//IL_01d4: Unknown result type (might be due to invalid IL or missing references)
//IL_01ea: Unknown result type (might be due to invalid IL or missing references)
//IL_01f0: Unknown result type (might be due to invalid IL or missing references)
//IL_01f6: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)volume == (Object)null)
{
return;
}
((Behaviour)volume).enabled = Enabled.Value;
if (!Enabled.Value)
{
return;
}
FilterPreset filterPreset = Presets[Mathf.Clamp(Filter.Value, 0, Presets.Length - 1)];
float num = Mathf.Clamp01(FilterIntensity.Value);
((VolumeParameter<float>)(object)colorAdj.postExposure).Override(Exposure.Value);
((VolumeParameter<float>)(object)colorAdj.contrast).Override(Mathf.Clamp((Contrast.Value - 1f) * 100f + filterPreset.Contrast * num, -100f, 100f));
((VolumeParameter<float>)(object)colorAdj.saturation).Override(Mathf.Clamp((Saturation.Value - 1f) * 100f + filterPreset.Saturation * num, -100f, 100f));
((VolumeParameter<Color>)(object)colorAdj.colorFilter).Override(Color.Lerp(White, filterPreset.Tint, num));
((VolumeParameter<float>)(object)wb.temperature).Override(Mathf.Clamp(Temperature.Value, -1f, 1f) * 100f);
float num2 = Mathf.Clamp01(BlackBoost.Value) * 0.15f + Mathf.Clamp(ShadowLift.Value, 0f, 0.3f) * 0.3f;
((VolumeParameter<Vector4>)(object)lgg.lift).Override(new Vector4(1f, 1f, 1f, num2));
((VolumeParameter<Color>)(object)split.shadows).Override(Color.Lerp(Grey, filterPreset.Shadows, num));
((VolumeParameter<Color>)(object)split.highlights).Override(Color.Lerp(Grey, filterPreset.Highlights, num));
((VolumeParameter<float>)(object)split.balance).Override(filterPreset.Balance * num);
if ((Object)(object)currentLut != (Object)null)
{
((VolumeComponent)lookup).active = true;
((VolumeParameter<Texture>)(object)lookup.texture).Override((Texture)(object)currentLut);
((VolumeParameter<float>)(object)lookup.contribution).Override(Mathf.Clamp01(LutStrength.Value));
if (logLutState)
{
logLutState = false;
MelonLogger.Msg("CineLab: LUT texture " + ((Texture)currentLut).width + "x" + ((Texture)currentLut).height + ", URP asset LUT size " + TargetLutSize() + ", ColorLookup active = " + lookup.IsActive());
}
}
else
{
((VolumeComponent)lookup).active = false;
}
TonemapChoice tonemapChoice = (TonemapChoice)Mathf.Clamp(Tonemap.Value, 0, 2);
((VolumeComponent)tonemap).active = tonemapChoice != TonemapChoice.GameDefault;
if (((VolumeComponent)tonemap).active)
{
((VolumeParameter<TonemappingMode>)(object)tonemap.mode).Override((TonemappingMode)((tonemapChoice != TonemapChoice.ACES) ? 1 : 2));
}
((VolumeComponent)bloom).active = BloomIntensity.Value > 0.001f;
if (((VolumeComponent)bloom).active)
{
((VolumeParameter<float>)(object)bloom.intensity).Override(BloomIntensity.Value);
((VolumeParameter<float>)(object)bloom.threshold).Override(BloomThreshold.Value);
((VolumeParameter<float>)(object)bloom.scatter).Override(0.7f);
}
((VolumeComponent)vignette).active = VignetteIntensity.Value > 0.001f;
if (((VolumeComponent)vignette).active)
{
((VolumeParameter<float>)(object)vignette.intensity).Override(VignetteIntensity.Value);
((VolumeParameter<float>)(object)vignette.smoothness).Override(0.4f);
}
((VolumeComponent)grain).active = GrainIntensity.Value > 0.001f;
if (((VolumeComponent)grain).active)
{
((VolumeParameter<FilmGrainLookup>)(object)grain.type).Override((FilmGrainLookup)2);
((VolumeParameter<float>)(object)grain.intensity).Override(GrainIntensity.Value);
((VolumeParameter<float>)(object)grain.response).Override(0.8f);
}
}
private void SetLook(float exp, float temp, float black, float contrast, float sat, float shadow, FilterChoice filter, float filterInt, TonemapChoice tm, float bloomI, float grainI)
{
Enabled.Value = true;
Exposure.Value = exp;
Temperature.Value = temp;
BlackBoost.Value = black;
Contrast.Value = contrast;
Saturation.Value = sat;
ShadowLift.Value = shadow;
Filter.Value = (int)filter;
FilterIntensity.Value = filterInt;
Tonemap.Value = (int)tm;
BloomIntensity.Value = bloomI;
BloomThreshold.Value = 0.5f;
VignetteIntensity.Value = 0f;
GrainIntensity.Value = grainI;
SyncMenu();
}
private void ApplyPreset(int id)
{
switch (id)
{
case 0:
SetLook(0f, 0.08f, 0.08f, 1.12f, 1.18f, 0.02f, FilterChoice.Cinematic, 0.65f, TonemapChoice.ACES, 0.15f, 0.06f);
break;
case 1:
SetLook(0.1f, 0f, 0f, 1.15f, 1.35f, 0f, FilterChoice.Original, 0f, TonemapChoice.Neutral, 0.1f, 0f);
break;
case 2:
SetLook(-0.3f, -0.1f, 0.05f, 1.2f, 0.85f, 0.02f, FilterChoice.ColdSteel, 0.5f, TonemapChoice.ACES, 0.2f, 0.1f);
break;
case 3:
SetLook(0.1f, 0.15f, 0.15f, 0.95f, 0.9f, 0.04f, FilterChoice.Vintage, 0.7f, TonemapChoice.Neutral, 0.1f, 0.3f);
break;
case 4:
SetLook(0.1f, 0.25f, 0.05f, 1.1f, 1.2f, 0.02f, FilterChoice.GoldenHour, 0.6f, TonemapChoice.ACES, 0.25f, 0.05f);
break;
}
MelonLogger.Msg("CineLab: preset applied.");
}
private void ResetSettings()
{
Enabled.Value = false;
Exposure.Value = 0f;
Temperature.Value = 0f;
BlackBoost.Value = 0f;
Contrast.Value = 1f;
Saturation.Value = 1f;
ShadowLift.Value = 0f;
Filter.Value = 0;
FilterIntensity.Value = 0f;
Tonemap.Value = 0;
BloomIntensity.Value = 0f;
BloomThreshold.Value = 0.5f;
VignetteIntensity.Value = 0f;
GrainIntensity.Value = 0f;
SelectLut(null);
SyncMenu();
}
private void SetupLutFolder()
{
try
{
lutDir = Path.Combine(MelonEnvironment.UserDataDirectory, "CineLab", "LUTs");
Directory.CreateDirectory(lutDir);
string path = Path.Combine(lutDir, "README.txt");
if (!File.Exists(path))
{
File.WriteAllText(path, "Drop LUT files (.cube, or strip images .png/.jpg) in this folder, then use\nCineLab > Rescan LUT Folder in BoneMenu, or restart the game.\n\nImage format: a horizontal strip of N tiles, each N x N pixels, so the image is\nN*N wide and N tall. Common sizes: 256x16, 1024x32, 4096x64.\nThis is the same strip format Unity's URP Color Lookup uses.\n.cube files (3D, LUT_3D_SIZE 2-90) are converted automatically. 1D .cube files and square-grid images are not supported.\n");
}
MelonLogger.Msg("CineLab LUT folder: " + lutDir);
}
catch (Exception ex)
{
MelonLogger.Error("CineLab: could not create LUT folder: " + ex.Message);
}
}
private string[] ListLutFiles()
{
List<string> list = new List<string>();
try
{
if (lutDir != null && Directory.Exists(lutDir))
{
list.AddRange(Directory.GetFiles(lutDir, "*.cube"));
list.AddRange(Directory.GetFiles(lutDir, "*.png"));
list.AddRange(Directory.GetFiles(lutDir, "*.jpg"));
list.AddRange(Directory.GetFiles(lutDir, "*.jpeg"));
list.Sort(StringComparer.OrdinalIgnoreCase);
}
}
catch (Exception ex)
{
MelonLogger.Warning("CineLab: could not list LUT folder: " + ex.Message);
}
return list.ToArray();
}
private void RebuildLutMenu()
{
//IL_002c: Unknown result type (might be due to invalid IL or missing references)
//IL_007d: Unknown result type (might be due to invalid IL or missing references)
if (lutPage == null)
{
return;
}
try
{
lutPage.RemoveAll();
lutPage.CreateFunction("None (LUT off)", Color.gray, (Action)delegate
{
SelectLut(null);
});
string[] array = ListLutFiles();
foreach (string text in array)
{
string path = text;
lutPage.CreateFunction(Path.GetFileName(path), Color.white, (Action)delegate
{
SelectLut(path);
});
}
}
catch (Exception ex)
{
MelonLogger.Warning("CineLab: LUT menu rebuild failed: " + ex.Message);
}
}
private void RescanLuts()
{
currentLut = null;
foreach (KeyValuePair<string, Texture2D> item in lutCache)
{
if ((Object)(object)item.Value != (Object)null)
{
Object.Destroy((Object)(object)item.Value);
}
}
lutCache.Clear();
RebuildLutMenu();
RestoreSavedLut();
MelonLogger.Msg("CineLab: rescanned LUT folder (" + ListLutFiles().Length + " file(s)).");
}
private void RestoreSavedLut()
{
string value = LutFile.Value;
if (!string.IsNullOrEmpty(value) && lutDir != null)
{
string path = Path.Combine(lutDir, value);
if (File.Exists(path))
{
SelectLut(path);
}
else
{
MelonLogger.Warning("CineLab: saved LUT not found: " + value);
}
}
}
private void SelectLut(string path)
{
if (string.IsNullOrEmpty(path))
{
currentLut = null;
LutFile.Value = "";
MelonLogger.Msg("CineLab: LUT off.");
return;
}
Texture2D lut = GetLut(path);
if (!((Object)(object)lut == (Object)null))
{
currentLut = lut;
logLutState = true;
LutFile.Value = Path.GetFileName(path);
MelonLogger.Msg("CineLab: LUT selected: " + LutFile.Value);
}
}
private static int TargetLutSize()
{
try
{
UniversalRenderPipelineAsset asset = UniversalRenderPipeline.asset;
if ((Object)(object)asset != (Object)null)
{
return asset.colorGradingLutSize;
}
}
catch (Exception)
{
}
return 32;
}
private Texture2D GetLut(string path)
{
if (lutCache.TryGetValue(path, out var value) && (Object)(object)value != (Object)null)
{
return value;
}
try
{
string fileName = Path.GetFileName(path);
int n;
float[] array = (path.EndsWith(".cube", StringComparison.OrdinalIgnoreCase) ? LoadCube(path, out n) : LoadStrip(path, out n));
if (array == null)
{
return null;
}
int num = TargetLutSize();
if (n != num)
{
array = Resample(array, n, num);
MelonLogger.Msg("CineLab: " + fileName + " resampled from size " + n + " to " + num + " (URP asset LUT size).");
}
Texture2D val = BuildStrip(array, num);
((Texture)val).filterMode = (FilterMode)1;
((Texture)val).wrapMode = (TextureWrapMode)1;
((Texture)val).anisoLevel = 0;
((Object)val).hideFlags = (HideFlags)61;
Object.DontDestroyOnLoad((Object)(object)val);
lutCache[path] = val;
return val;
}
catch (Exception ex)
{
MelonLogger.Warning("CineLab: failed to load LUT " + Path.GetFileName(path) + ": " + ex.Message);
return null;
}
}
private static int Idx(int n, int r, int g, int b)
{
return (r + n * (g + n * b)) * 3;
}
private static float[] Resample(float[] src, int n, int t)
{
float[] array = new float[t * t * t * 3];
float num = ((float)n - 1f) / ((float)t - 1f);
for (int i = 0; i < t; i++)
{
for (int j = 0; j < t; j++)
{
for (int k = 0; k < t; k++)
{
float num2 = (float)k * num;
float num3 = (float)j * num;
float num4 = (float)i * num;
int num5 = Mathf.Min((int)num2, n - 2);
int num6 = Mathf.Min((int)num3, n - 2);
int num7 = Mathf.Min((int)num4, n - 2);
int r = num5 + 1;
int g = num6 + 1;
int b = num7 + 1;
float num8 = num2 - (float)num5;
float num9 = num3 - (float)num6;
float num10 = num4 - (float)num7;
for (int l = 0; l < 3; l++)
{
float num11 = Mathf.Lerp(src[Idx(n, num5, num6, num7) + l], src[Idx(n, r, num6, num7) + l], num8);
float num12 = Mathf.Lerp(src[Idx(n, num5, g, num7) + l], src[Idx(n, r, g, num7) + l], num8);
float num13 = Mathf.Lerp(src[Idx(n, num5, num6, b) + l], src[Idx(n, r, num6, b) + l], num8);
float num14 = Mathf.Lerp(src[Idx(n, num5, g, b) + l], src[Idx(n, r, g, b) + l], num8);
array[Idx(t, k, j, i) + l] = Mathf.Lerp(Mathf.Lerp(num11, num12, num9), Mathf.Lerp(num13, num14, num9), num10);
}
}
}
}
return array;
}
private static Texture2D BuildStrip(float[] data, int size)
{
//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
//IL_00c2: Expected O, but got Unknown
int num = size * size;
byte[] array = new byte[num * size * 4];
for (int i = 0; i < size; i++)
{
for (int j = 0; j < size; j++)
{
for (int k = 0; k < size; k++)
{
int num2 = Idx(size, k, j, i);
int num3 = (j * num + i * size + k) * 4;
array[num3] = ToByte(data[num2]);
array[num3 + 1] = ToByte(data[num2 + 1]);
array[num3 + 2] = ToByte(data[num2 + 2]);
array[num3 + 3] = byte.MaxValue;
}
}
}
Texture2D val = new Texture2D(num, size, (TextureFormat)4, false, true);
Il2CppStructArray<byte> val2 = Il2CppStructArray<byte>.op_Implicit(array);
val.LoadRawTextureData(val2);
val.Apply(false, false);
return val;
}
private float[] LoadStrip(string path, out int n)
{
//IL_0017: Unknown result type (might be due to invalid IL or missing references)
//IL_001d: Expected O, but got Unknown
//IL_012c: Unknown result type (might be due to invalid IL or missing references)
//IL_0131: Unknown result type (might be due to invalid IL or missing references)
//IL_0146: Unknown result type (might be due to invalid IL or missing references)
//IL_015b: Unknown result type (might be due to invalid IL or missing references)
//IL_0170: Unknown result type (might be due to invalid IL or missing references)
n = 0;
byte[] array = File.ReadAllBytes(path);
Il2CppStructArray<byte> val = Il2CppStructArray<byte>.op_Implicit(array);
Texture2D val2 = new Texture2D(2, 2, (TextureFormat)4, false, true);
try
{
if (!ImageConversion.LoadImage(val2, val, false))
{
MelonLogger.Warning("CineLab: could not decode image: " + Path.GetFileName(path));
return null;
}
if (((Texture)val2).height < 2 || ((Texture)val2).width != ((Texture)val2).height * ((Texture)val2).height)
{
MelonLogger.Warning("CineLab: " + Path.GetFileName(path) + " is " + ((Texture)val2).width + "x" + ((Texture)val2).height + ", not a LUT strip (width must equal height x height, e.g. 1024x32). Skipped.");
return null;
}
n = ((Texture)val2).height;
int width = ((Texture)val2).width;
Il2CppStructArray<Color32> pixels = val2.GetPixels32();
float[] array2 = new float[n * n * n * 3];
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n; j++)
{
for (int k = 0; k < n; k++)
{
Color32 val3 = ((Il2CppArrayBase<Color32>)(object)pixels)[j * width + i * n + k];
int num = Idx(n, k, j, i);
array2[num] = (float)(int)val3.r / 255f;
array2[num + 1] = (float)(int)val3.g / 255f;
array2[num + 2] = (float)(int)val3.b / 255f;
}
}
}
return array2;
}
finally
{
Object.Destroy((Object)(object)val2);
}
}
private static float ParseF(string s)
{
return float.Parse(s, NumberStyles.Float, CultureInfo.InvariantCulture);
}
private static byte ToByte(float v)
{
return (byte)Mathf.RoundToInt(Mathf.Clamp01(v) * 255f);
}
private float[] LoadCube(string path, out int n)
{
n = 0;
string fileName = Path.GetFileName(path);
int num = 0;
float[] array = null;
int num2 = 0;
bool flag = false;
char[] separator = null;
foreach (string item in File.ReadLines(path))
{
string text = item.Trim();
if (text.Length == 0 || text[0] == '#')
{
continue;
}
string[] array2 = text.Split(separator, StringSplitOptions.RemoveEmptyEntries);
if (char.IsLetter(text[0]))
{
string text2 = array2[0].ToUpperInvariant();
switch (text2)
{
case "LUT_3D_SIZE":
{
if (array2.Length < 2 || !int.TryParse(array2[1], out var result) || result < 2 || result > 90)
{
MelonLogger.Warning("CineLab: " + fileName + " has an unsupported LUT_3D_SIZE (need 2-90). Skipped.");
return null;
}
num = result;
array = new float[num * num * num * 3];
break;
}
case "LUT_1D_SIZE":
MelonLogger.Warning("CineLab: " + fileName + " is a 1D LUT, which is not supported. Skipped.");
return null;
case "DOMAIN_MIN":
case "DOMAIN_MAX":
if (array2.Length >= 4 && !flag)
{
float num3 = ((text2 == "DOMAIN_MIN") ? 0f : 1f);
if (Mathf.Abs(ParseF(array2[1]) - num3) > 0.001f)
{
flag = true;
MelonLogger.Warning("CineLab: " + fileName + " has a non-standard DOMAIN; it is ignored, so colors may look off.");
}
}
break;
}
continue;
}
if (array == null)
{
MelonLogger.Warning("CineLab: " + fileName + " has data before LUT_3D_SIZE. Skipped.");
return null;
}
if (array2.Length >= 3)
{
if (num2 >= num * num * num)
{
break;
}
array[num2 * 3] = ParseF(array2[0]);
array[num2 * 3 + 1] = ParseF(array2[1]);
array[num2 * 3 + 2] = ParseF(array2[2]);
num2++;
}
}
if (array == null || num2 != num * num * num)
{
MelonLogger.Warning("CineLab: " + fileName + " is incomplete (expected " + num * num * num + " rows, found " + num2 + "). Skipped.");
return null;
}
n = num;
return array;
}
}
}