Files

233 lines
7.5 KiB
C#

using EDIDParser;
using EDIDParser.Descriptors;
using EDIDParser.Enums;
using NLog;
using NvAPIWrapper.Display;
using NvAPIWrapper.GPU;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using static novideo_srgb.Colorimetry;
namespace novideo_srgb
{
public class MonitorData : INotifyPropertyChanged
{
public event PropertyChangedEventHandler? PropertyChanged;
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
private readonly GPUOutput _output;
private bool _clamped;
private MainViewModel _viewModel;
public MonitorData(MainViewModel viewModel, int number, Display display, string path, bool hdrActive, bool clampSdr)
{
_viewModel = viewModel;
Number = number;
_output = display.Output;
Edid = Novideo.GetEDID(path, display);
Name = Edid.Descriptors.OfType<StringDescriptor>()
.FirstOrDefault(x => x.Type == StringDescriptorType.MonitorName)?.Value ?? "<no name>";
Path = path;
ClampSdr = clampSdr;
HdrActive = hdrActive;
var coords = Edid.DisplayParameters.ChromaticityCoordinates;
EdidColorSpace = new Colorimetry.ColorSpace
{
Red = new Colorimetry.Point { X = Math.Round(coords.RedX, 3), Y = Math.Round(coords.RedY, 3) },
Green = new Colorimetry.Point { X = Math.Round(coords.GreenX, 3), Y = Math.Round(coords.GreenY, 3) },
Blue = new Colorimetry.Point { X = Math.Round(coords.BlueX, 3), Y = Math.Round(coords.BlueY, 3) },
White = Colorimetry.D65
};
_clamped = Novideo.IsColorSpaceConversionActive(_output);
ProfilePath = "";
CustomGamma = 2.2;
CustomPercentage = 100;
}
public MonitorData(MainViewModel viewModel, int number, Display display, string path, bool hdrActive, bool clampSdr, bool useIcc, string profilePath,
bool calibrateGamma,
int selectedGamma, double customGamma, double customPercentage, int target, bool disableOptimization) :
this(viewModel, number, display, path, hdrActive, clampSdr)
{
UseIcc = useIcc;
ProfilePath = profilePath;
CalibrateGamma = calibrateGamma;
SelectedGamma = selectedGamma;
CustomGamma = customGamma;
CustomPercentage = customPercentage;
Target = target;
DisableOptimization = disableOptimization;
}
public int Number { get; }
public string Name { get; }
public EDID Edid { get; }
public string Path { get; }
public bool ClampSdr { get; set; }
public bool HdrActive { get; }
private void UpdateClamp(bool doClamp)
{
if (HdrActive)
{
_clamped = false;
return;
}
if (_clamped)
{
Novideo.DisableColorSpaceConversion(_output);
_clamped = Novideo.IsColorSpaceConversionActive(_output);
}
if (!doClamp)
{
return;
}
if (_clamped) Thread.Sleep(100);
if (UseEdid)
Novideo.SetColorSpaceConversion(_output, Colorimetry.RGBToRGB(TargetColorSpace, EdidColorSpace));
else if (UseIcc)
{
SetICCProfile(ProfilePath, SelectedGamma, TargetColorSpace);
}
}
private void SetICCProfile(string fileName, int selectedGamma, ColorSpace colorSpace)
{
var profile = ICCMatrixProfile.FromFile(fileName);
if (CalibrateGamma)
{
var trcBlack = Matrix.FromValues(new[,]
{
{ profile.trcs[0].SampleAt(0) },
{ profile.trcs[1].SampleAt(0) },
{ profile.trcs[2].SampleAt(0) }
});
var black = (profile.matrix * trcBlack)[1];
ToneCurve gamma;
switch (selectedGamma)
{
case 0:
gamma = new SrgbEOTF(black);
break;
case 1:
gamma = new GammaToneCurve(2.4, black, 0);
break;
case 2:
gamma = new GammaToneCurve(CustomGamma, black, CustomPercentage / 100);
break;
case 3:
gamma = new GammaToneCurve(CustomGamma, black, CustomPercentage / 100, true);
break;
default:
throw new NotSupportedException("Unsupported gamma type " + selectedGamma);
}
Novideo.SetColorSpaceConversion(_output, profile, colorSpace, gamma, DisableOptimization);
}
else
{
Novideo.SetColorSpaceConversion(_output, profile, colorSpace);
}
}
private void HandleClampException(Exception e)
{
Logger.Error(e);
//System.Windows.MessageBox.Show(e.Message);
_clamped = Novideo.IsColorSpaceConversionActive(_output);
ClampSdr = _clamped;
_viewModel.SaveConfig();
OnPropertyChanged(nameof(Clamped));
}
public bool Clamped
{
set
{
try
{
UpdateClamp(value);
ClampSdr = value;
_viewModel.SaveConfig();
}
catch (Exception e)
{
HandleClampException(e);
return;
}
_clamped = value;
OnPropertyChanged();
}
get => _clamped;
}
public void ReapplyClamp(bool? forceClamp = null)
{
try
{
if (!ClampSdr)
{
return;
}
var clamped = CanClamp && ClampSdr && (!forceClamp.HasValue || forceClamp.Value);
UpdateClamp(clamped);
_clamped = clamped;
OnPropertyChanged(nameof(CanClamp));
}
catch (Exception e)
{
HandleClampException(e);
}
}
public bool CanClamp => !HdrActive && (UseEdid && !EdidColorSpace.Equals(TargetColorSpace) || UseIcc && ProfilePath != "");
public string GPU => _output.PhysicalGPU.FullName;
public bool UseEdid
{
set => UseIcc = !value;
get => !UseIcc;
}
public bool UseIcc { set; get; }
public string ProfilePath { set; get; }
public bool CalibrateGamma { set; get; }
public int SelectedGamma { set; get; }
public double CustomGamma { set; get; }
public double CustomPercentage { set; get; }
public bool DisableOptimization { set; get; }
public int Target { set; get; }
public Colorimetry.ColorSpace EdidColorSpace { get; }
private Colorimetry.ColorSpace TargetColorSpace => Colorimetry.ColorSpaces[Target];
private void OnPropertyChanged([CallerMemberName] string? name = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
}
}