-
Notifications
You must be signed in to change notification settings - Fork 13
/
GamutCompress.dctl
113 lines (96 loc) · 3.88 KB
/
GamutCompress.dctl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
DEFINE_UI_PARAMS(th_c, thr c, DCTLUI_SLIDER_FLOAT, 0.15, 0.0, 0.3, 0.0)
DEFINE_UI_PARAMS(th_m, thr m, DCTLUI_SLIDER_FLOAT, 0.15, 0.0, 0.3, 0.0)
DEFINE_UI_PARAMS(th_y, thr y, DCTLUI_SLIDER_FLOAT, 0.15, 0.0, 0.3, 0.0)
DEFINE_UI_PARAMS(d_c, dist c, DCTLUI_SLIDER_FLOAT, 0.1, 0.0, 0.4, 0.0)
DEFINE_UI_PARAMS(d_m, dist m, DCTLUI_SLIDER_FLOAT, 0.2, 0.0, 0.4, 0.0)
DEFINE_UI_PARAMS(d_y, dist y, DCTLUI_SLIDER_FLOAT, 0.1, 0.0, 0.4, 0.0)
DEFINE_UI_PARAMS(working_colorspace, working space, DCTLUI_COMBO_BOX, 0, {acescct, acescc, acescg}, {acescct, acescc, acescg})
DEFINE_UI_PARAMS(invert, invert, DCTLUI_CHECK_BOX, 0)
// convert acescg to acescct
__DEVICE__ float lin_to_acescct(float in) {
if (in <= 0.0078125f) {
return 10.5402377416545f * in + 0.0729055341958355f;
} else {
return (_log2f(in) + 9.72f) / 17.52f;
}
}
// convert acescct to acescg
__DEVICE__ float acescct_to_lin(float in) {
if (in > 0.155251141552511f) {
return _powf( 2.0f, in*17.52f - 9.72f);
} else {
return (in - 0.0729055341958355f) / 10.5402377416545f;
}
}
// convert acescg to acescc
__DEVICE__ float lin_to_acescc(float in) {
if (in <= 0.0f) {
return -0.3584474886f;
} else if (in < _powf(2.0f, -15.0f)) {
return (_log2f(_powf(2.0f, -16.0f) + in * 0.5f) + 9.72f) / 17.52f;
} else {
return (_log2f(in) + 9.72f) / 17.52f;
}
}
// convert acescc to acescg
__DEVICE__ float acescc_to_lin(float in) {
if (in < -0.3013698630f) {
return (_powf( 2.0f, in * 17.52f - 9.72f) - _powf( 2.0f, -16.0f)) * 2.0f;
} else if (in < (_log2f(65504.0f)+9.72f)/17.52f) {
return _powf(2.0f, in * 17.52f - 9.72f);
} else {
return 65504.0f;
}
}
__DEVICE__ float3 transform(int p_Width, int p_Height, int p_X, int p_Y, float p_R, float p_G, float p_B)
{
float3 rgb = make_float3(p_R, p_G, p_B);
// Linearize working colorspace
if (working_colorspace == acescct) {
rgb.x = acescct_to_lin(rgb.x);
rgb.y = acescct_to_lin(rgb.y);
rgb.z = acescct_to_lin(rgb.z);
} else if (working_colorspace == acescc) {
rgb.x = acescc_to_lin(rgb.x);
rgb.y = acescc_to_lin(rgb.y);
rgb.z = acescc_to_lin(rgb.z);
}
// Amount of outer gamut to affect
float3 th = 1.0f-make_float3(th_c, th_m, th_y);
// Distance limit: How far beyond the gamut boundary to compress
float3 dl = 1.0f+make_float3(d_c, d_m, d_y);
// Calculate scale so compression function passes through distance limit: (x=dl, y=1)
float3 s;
s.x = (1.0f-th.x)/_sqrtf(_fmaxf(1.001f, dl.x)-1.0f);
s.y = (1.0f-th.y)/_sqrtf(_fmaxf(1.001f, dl.y)-1.0f);
s.z = (1.0f-th.z)/_sqrtf(_fmaxf(1.001f, dl.z)-1.0f);
// Achromatic axis
float ac = _fmaxf(rgb.x, _fmaxf(rgb.y, rgb.z));
// Inverse RGB Ratios: distance from achromatic axis
float3 d = ac == 0.0f ? make_float3(0.0f, 0.0f, 0.0f) : (ac-rgb)/_fabs(ac);
float3 cd; // Compressed distance
// Parabolic compression function: https://www.desmos.com/calculator/nvhp63hmtj
if (invert == 0) {
cd.x = d.x<th.x?d.x:s.x*_sqrtf(d.x-th.x+s.x*s.x/4.0f)-s.x*_sqrtf(s.x*s.x/4.0f)+th.x;
cd.y = d.y<th.y?d.y:s.y*_sqrtf(d.y-th.y+s.y*s.y/4.0f)-s.y*_sqrtf(s.y*s.y/4.0f)+th.y;
cd.z = d.z<th.z?d.z:s.z*_sqrtf(d.z-th.z+s.z*s.z/4.0f)-s.z*_sqrtf(s.z*s.z/4.0f)+th.z;
} else {
cd.x = d.x<th.x?d.x:_powf(d.x-th.x+s.x*_sqrtf(s.x*s.x/4.0f),2.0f)/(s.x*s.x)-s.x*s.x/4.0f+th.x;
cd.y = d.y<th.y?d.y:_powf(d.y-th.y+s.y*_sqrtf(s.y*s.y/4.0f),2.0f)/(s.y*s.y)-s.y*s.y/4.0f+th.y;
cd.z = d.z<th.z?d.z:_powf(d.z-th.z+s.z*_sqrtf(s.z*s.z/4.0f),2.0f)/(s.z*s.z)-s.z*s.z/4.0f+th.z;
}
// Inverse RGB Ratios to RGB
rgb = ac-cd*_fabs(ac);
// Linear to working colorspace
if (working_colorspace == acescct) {
rgb.x = lin_to_acescct(rgb.x);
rgb.y = lin_to_acescct(rgb.y);
rgb.z = lin_to_acescct(rgb.z);
} else if (working_colorspace == acescc) {
rgb.x = lin_to_acescc(rgb.x);
rgb.y = lin_to_acescc(rgb.y);
rgb.z = lin_to_acescc(rgb.z);
}
// Return output RGB
return rgb;
}