├── .gitattributes
├── .gitignore
├── README.md
├── ME_hue-Sat_Ramp.dctl
├── IDTs
├── ME_BMD P6k Film Gen4 to DI.dctl
├── ME_Fuji F-Log2 IDT.dctl
└── ME_Sony Slog1 IDT.dctl
├── ME_Desatch.dctl
├── ME_HCV Transform.dctl
├── ME_Smooth_Tetra.dctl
├── ME_Hue Tetra v1.0.dctl
├── ME_Color Models v1.0.dctl
├── LICENSE
├── ME_Ratio Shaper v1.2.dctl
└── ME_Filmic Contrast new curve.dctl
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 | *.dctl linguist-language=C
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | Old versions/ME_Filmic Contrast v1.1.1.dctl
3 | Old versions/ME_Filmic Contrast.dctl
4 | Old versions/ME_Hue Curve v1.0.dctl
5 | Old versions/ME_Hue Curve v1.1.1.dctl
6 | Old versions/ME_Hue Curve v1.1.dctl
7 | Old versions/ME_Ratio Shaper v1.0.dctl
8 | Old versions/ME_Trimmer.dctl
9 | Old versions/S-curve Contrast.dctl
10 | Old versions/Template.dctl
11 | Old versions/Template_Interactive.dctl
12 | Old versions/Test.dctl
13 | ME_Filmic Contrast v1.1.1.dctl
14 | ME_Filmic Contrast.dctl
15 | ME_Hue Curve v1.0.dctl
16 | ME_Hue Curve v1.1.1.dctl
17 | ME_Hue Curve v1.1.dctl
18 | ME_Hue Curve v1.2
19 | ME_Ratio Shaper v1.0.dctl
20 | ME_Ratio Shaper v1.1
21 | S-curve Contrast.dctl
22 | ME_Trimmer.dctl
23 | Template.dctl
24 | Template_Interactive.dctl
25 | Test.dctl
26 | Old versions/desatch.dctl
27 | Desatch.dctl
28 | ME_Ratio Shaper v1.1.dctl
29 | ME_Hue Curve v1.2.dctl
30 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Installation
2 | DCTLs should be placed in the following folder:
3 |
4 | **MacOS**: `/Library/Application Support/Blackmagic Design/DaVinci Resolve/LUT`
5 |
6 | **Windows**: `C:\ProgramData\Blackmagic Design\DaVinci Resolve\Support\LUT`
7 |
8 | Fuses should be placed in the following folder to install them into the Fusion page of DaVinci Resolve:
9 |
10 | **MacOS**: `/Library/Application Support/Blackmagic Design/DaVinci Resolve/Fusion/Fuses`
11 |
12 | **Windows**: `C:\ProgramData\Blackmagic Design\DaVinci Resolve\Fusion\Fuses`
13 |
14 | Fuses should also be placed in the following folder to install them for Fusion Studio:
15 |
16 | **MacOS**: `/Library/Application Support/Blackmagic Design/Fusion/Fuses`
17 |
18 | **Windows**: `C:\ProgramData\Blackmagic Design\Fusion\Fuses`
19 |
20 | If a DCTL is not working, you can usually find logs in these directories. If you find that there is a problem, make an Issue on Github with your OS and Resolve version so I can fix it.
21 |
22 | **MacOS**: `[Your user directory]/Library/Application Support/Blackmagic Design/DaVinci Resolve/logs/davinci_resolve.log` or `/Library/Application Support/Blackmagic Design/DaVinci Resolve/logs/davinci_resolve.log`
23 |
24 | **Windows**: `C:\ProgramData\Blackmagic Design\DaVinci Resolve\Support\logs\davinci_resolve.log` or `[Your user directory]\AppData\Blackmagic Design\DaVinci Resolve\Support\logs\davinci_resolve.log`
25 |
26 | ## License
27 |
28 | This project is licensed under the [GNU General Public License v3.0](LICENSE).
29 |
--------------------------------------------------------------------------------
/ME_hue-Sat_Ramp.dctl:
--------------------------------------------------------------------------------
1 | #line 2
2 | // Hue-Sat Ramp
3 | //based on baldavenger's SatRamp DCTL
4 |
5 |
6 | __DEVICE__ float3 RGBtoHSV(float3 RGB) {
7 | float3 HSV;
8 | float min = _fminf(_fminf(RGB.x, RGB.y), RGB.z);
9 | float max = _fmaxf(_fmaxf(RGB.x, RGB.y), RGB.z);
10 | HSV.z = max;
11 | float delta = max - min;
12 | if (max != 0.0f) {
13 | HSV.y = delta / max;
14 | } else {
15 | HSV.y = 0.0f;
16 | HSV.x = 0.0f;
17 | return HSV;
18 | }
19 | if (delta == 0.0f) {
20 | HSV.x = 0.0f;
21 | } else if (RGB.x == max) {
22 | HSV.x = (RGB.y - RGB.z) / delta;
23 | } else if (RGB.y == max) {
24 | HSV.x = 2.0f + (RGB.z - RGB.x) / delta;
25 | } else {
26 | HSV.x = 4.0f + (RGB.x - RGB.y) / delta;
27 | }
28 | HSV.x *= 1.0f / 6.0f;
29 | if (HSV.x < 0.0f)
30 | HSV.x += 1.0f;
31 | return HSV;
32 | } //Convert to HSV
33 |
34 | __DEVICE__ float3 HSVtoRGB(float3 HSV) {
35 | float3 RGB;
36 | if (HSV.y == 0.0f) {
37 | RGB.x = RGB.y = RGB.z = HSV.z;
38 | } else {
39 | HSV.x *= 6.0f;
40 | int i = floor(HSV.x);
41 | float f = HSV.x - i;
42 | i = (i >= 0) ? (i % 6) : (i % 6) + 6;
43 | float p = HSV.z * (1.0f - HSV.y);
44 | float q = HSV.z * (1.0f - HSV.y * f);
45 | float t = HSV.z * (1.0f - HSV.y * (1.0f - f));
46 | RGB.x = i == 0 ? HSV.z : i == 1 ? q : i == 2 ? p : i == 3 ? p : i == 4 ? t : HSV.z;
47 | RGB.y = i == 0 ? t : i == 1 ? HSV.z : i == 2 ? HSV.z : i == 3 ? q : i == 4 ? p : p;
48 | RGB.z = i == 0 ? p : i == 1 ? p : i == 2 ? t : i == 3 ? HSV.z : i == 4 ? HSV.z : q;
49 | }
50 | return RGB;
51 | } //Convert HSV to RGB
52 |
53 |
54 | DEFINE_UI_PARAMS(p_hue, Hue, DCTLUI_SLIDER_FLOAT, 1f, 0.0f, 1f, 0.01f)
55 | DEFINE_UI_PARAMS(p_overlay, Overlay mode, DCTLUI_CHECK_BOX, 0)
56 |
57 |
58 | __DEVICE__ float3 transform(int p_Width, int p_Height, int p_X, int p_Y, float p_R, float p_G, float p_B) {
59 |
60 | float3 RGB;
61 | float3 in_RGB = make_float3(p_R, p_G, p_B);
62 |
63 | // float width = (float)p_Width;
64 | float height = (float)p_Height;
65 | //float X = (float)p_X;
66 | float Y = height - (float)p_Y;
67 | //Relative X,Y
68 | float rY = Y / height;
69 | //float rX = X / width;
70 |
71 |
72 |
73 | float X = p_X;
74 |
75 |
76 | float s = X / (p_Width-1);
77 | float h = s > 0.0f ? 1.0f : 0.0f;
78 | float l = 0.5f;
79 |
80 | float q = l < 0.5f ? l * (1.0f + s) : l + s - l * s;
81 | float p = 2.0f * l - q;
82 |
83 | float rh = h + 1.0f / 3.0f < 0.0f ? h + 1.0f / 3.0f + 1.0f :
84 | h + 1.0f / 3.0f > 1.0f ? h + 1.0f / 3.0f - 1.0f : h + 1.0f / 3.0f;
85 |
86 | float rr = rh < 1.0f / 6.0f ? p + (q - p) * 6.0f * rh :
87 | rh < 1.0f / 2.0f ? q : rh < 2.0f / 3.0f ? p + (q - p) * (2.0f / 3.0f - rh) * 6.0f : p;
88 |
89 | float gh = h < 0.0f ? h + 1.0f : h > 1.0f ? h - 1.0f : h;
90 |
91 | float gg = gh < 1.0f / 6.0f ? p + (q - p) * 6.0f * gh :
92 | gh < 1.0f / 2.0f ? q : gh < 2.0f / 3.0f ? p + (q - p) * (2.0f / 3.0f - gh) * 6.0f : p;
93 |
94 | float bh = h - 1.0f / 3.0f < 0.0f ? h - 1.0f / 3.0f + 1.0f :
95 | h - 1.0f / 3.0f > 1.0f ? h - 1.0f / 3.0f - 1.0f : h - 1.0f / 3.0f;
96 |
97 | float bb = bh < 1.0f / 6.0f ? p + (q - p) * 6.0f * bh :
98 | bh < 1.0f / 2.0f ? q : bh < 2.0f / 3.0f ? p + (q - p) * (2.0f / 3.0f - bh) * 6.0f : p;
99 |
100 |
101 | float r = s == 0.0f ? l : rr;
102 | float g = s == 0.0f ? l : gg;
103 | float b = s == 0.0f ? l : bb;
104 |
105 |
106 | RGB = make_float3(r, g, b);
107 |
108 | //rotate hue in HSV
109 | RGB = RGBtoHSV(RGB);
110 | RGB.x = RGB.x + p_hue;
111 | RGB = HSVtoRGB(RGB);
112 |
113 |
114 |
115 |
116 | if (p_overlay == 1) {
117 | if (rY > .2f) {RGB = in_RGB;}
118 | }
119 | return RGB;
120 | }
--------------------------------------------------------------------------------
/IDTs/ME_BMD P6k Film Gen4 to DI.dctl:
--------------------------------------------------------------------------------
1 | #line 2
2 | //------------- Blackmagic Design Pocket Camera 6k Film Gen 4 IDT -------------//
3 | // DCTL by Moaz Elgabry
4 | // Converts BMD Pocket 6k Film Gen 4 to Davinci wide gamut.
5 | //
6 | // Input: BMD Pocket 6k Film Gen 4
7 | // Output: Davinci Widegamut/Davinci Intermediate
8 |
9 |
10 | // Custom 3x3 matrix struct float3x3
11 | typedef struct {
12 | float3 x, y, z;
13 | } float3x3;
14 |
15 |
16 | __DEVICE__ float3x3 make_float3x3(float3 a, float3 b, float3 c) {
17 | float3x3 d;
18 | d.x = a, d.y = b, d.z = c;
19 | return d;
20 | }
21 | __DEVICE__ float3 mult_f3_f33(float3 a, float3x3 m) {
22 | return make_float3(
23 | m.x.x * a.x + m.x.y * a.y + m.x.z * a.z,
24 | m.y.x * a.x + m.y.y * a.y + m.y.z * a.z,
25 | m.z.x * a.x + m.z.y * a.y + m.z.z * a.z);
26 | }
27 |
28 |
29 |
30 |
31 |
32 |
33 | //matrices use bradford white adaptation
34 | //moving to XYZ
35 | #define matrix_blackmagicwg_to_xyz make_float3x3(make_float3(0.644999f, 0.256084f, 0.098917f), make_float3(0.284726f, 0.819635f, -0.104361f), make_float3(-0.027776f, -0.077820f, 1.105596f))
36 | #define matrix_dwg_to_xyz make_float3x3(make_float3(0.745602f, 0.183144f, 0.071254f), make_float3(0.295008f, 0.857088f, -0.152096f), make_float3(-0.091799f, -0.124611f, 1.216410))
37 |
38 | //moving from XYZ
39 | #define matrix_xyz_to_blackmagicwg make_float3x3(make_float3(1.798141f, -0.582297f, -0.215844f), make_float3(-0.624485f, 1.433317f, 0.191168f), make_float3(0.001219f, 0.086259f, 0.912522))
40 | #define matrix_xyz_to_dwg make_float3x3(make_float3(1.456001f, -0.329511f, -0.126489f), make_float3(-0.490572f, 1.299367f, 0.191205f), make_float3(0.059625f, 0.108242f, 0.832133))
41 |
42 |
43 | #define matrix_blackmagicwg_to_dwg make_float3x3(make_float3(0.848813f, 0.112622f, 0.038565f), make_float3(0.048234f, 0.924500f, 0.027266f), make_float3(0.046164f, 0.039231f, 0.914605))
44 |
45 |
46 | __DEVICE__ float3 BMD6Kgen4_to_Linear(float3 in) {
47 |
48 | float A = 4.724515510884684f;
49 | float B = 0.07305940816299691f;
50 | float C = 0.027941380463157067f;
51 | float D = 0.15545874964938466f;
52 | float E = 0.6272665887366995f;
53 | //float cut = A*0.005+B;
54 | float cut = 0.09449554857962233f;
55 |
56 |
57 | float3 out;
58 |
59 | out.x = in.x <= cut ? (in.x - B) / A : _expf((in.x - E) / D) - C;
60 | out.y = in.y <= cut ? (in.y - B) / A : _expf((in.y - E) / D) - C;
61 | out.z = in.z <= cut ? (in.z - B) / A : _expf((in.z - E) / D) - C;
62 |
63 | return out;
64 | }
65 |
66 | __DEVICE__ float3 LinToDI (float3 in) {
67 | float3 out;
68 |
69 | out.x = in.x <= 0.00262409f ? in.x * 10.44426855f : (_log2f(in.x + 0.0075f) + 7.0f) * 0.07329248f;
70 | out.y = in.y <= 0.00262409f ? in.y * 10.44426855f : (_log2f(in.y + 0.0075f) + 7.0f) * 0.07329248f;
71 | out.z = in.z <= 0.00262409f ? in.z * 10.44426855f : (_log2f(in.z + 0.0075f) + 7.0f) * 0.07329248f;
72 |
73 | return out;
74 | }
75 |
76 |
77 | DEFINE_UI_PARAMS(bypass, Bypass, DCTLUI_CHECK_BOX, 0)
78 | DEFINE_UI_PARAMS(log2lin, Linearize, DCTLUI_CHECK_BOX, 1)
79 | DEFINE_UI_PARAMS(lin2log, To Davinci Intermediate, DCTLUI_CHECK_BOX, 1)
80 |
81 | __DEVICE__ float3 transform(int p_Width, int p_Height, int p_X, int p_Y, float p_R, float p_G, float p_B){
82 |
83 | float3 in = make_float3 (p_R, p_G, p_B);
84 | if (bypass) { return in;}
85 |
86 | float3 out;
87 |
88 | //Linearize input RGB
89 | if (log2lin == 1) out = BMD6Kgen4_to_Linear(in);
90 | else if (log2lin == 0) out = in;
91 |
92 |
93 | //convert from linear to Davinci intermediate
94 | if (lin2log) {
95 | //Matrix vector multiply A by rgb_linear
96 | out = mult_f3_f33(out, matrix_blackmagicwg_to_dwg);
97 | //transform to Davinci Intermediate
98 | out = LinToDI(out);
99 | }
100 | // retrn the result
101 | return out;
102 | }
103 |
--------------------------------------------------------------------------------
/IDTs/ME_Fuji F-Log2 IDT.dctl:
--------------------------------------------------------------------------------
1 | #line 2
2 | /**
3 | * DCTL written by Moaz ELgabry
4 | * F-log2 to DWG conversion.
5 | * Goes from F-Log2 and F-Log2 gamut (equivalent to BT 2020 gamut)
6 | * to Davinci Wide Gamut Intermediate.
7 | *
8 | * This can be used as an IDT in Resolve.
9 | */
10 |
11 | __DEVICE__ float oetf_fujifilm_flog2(float x, int inv) {
12 | /* Fujifilm F-Log2
13 | https://dl.fujifilm-x.com/support/lut/F-Log2_DataSheet_E_Ver.1.0.pdf
14 | */
15 | const float a = 5.555556f;
16 | const float b = 0.064829f;
17 | const float c = 0.245281f;
18 | const float d = 0.384316f;
19 | const float e = 8.799461f;
20 | const float f = 0.092864f;
21 | const float cut1 = 0.000889f;
22 | const float cut2 = 0.100686685370811f;
23 |
24 | if (inv == 1) {
25 | return x < cut2 ? (x-f)/e : (_exp10f(((x - d)/c))/a - b/a);
26 | } else {
27 | return x < cut1 ? e*x+f : c*_log10f(a*x + b) + d;
28 | }
29 | }
30 |
31 |
32 | __DEVICE__ float oetf_davinci_intermediate(float x, int inv) {
33 | /* DaVinci Intermediate Log
34 | https://documents.blackmagicdesign.com/InformationNotes/DaVinci_Resolve_17_Wide_Gamut_Intermediate.pdf
35 | */
36 |
37 | const float A = 0.0075f;
38 | const float B = 7.0f;
39 | const float C = 0.07329248f;
40 | const float M = 10.44426855f;
41 | const float LIN_CUT = 0.00262409f;
42 | const float LOG_CUT = 0.02740668f;
43 |
44 | if (inv == 1) {
45 | return x <= LOG_CUT ? x/M : _exp2f(x/C - B) - A;
46 | } else {
47 | return x <= LIN_CUT ? x*M : (_log2f(x + A) + B)*C;
48 | }
49 | }
50 |
51 | __DEVICE__ inline float flog2_to_linear(float t)
52 | {
53 | const float a = 5.555556f;
54 | const float b = 0.064829f;
55 | const float c = 0.245281f;
56 | const float d = 0.384316f;
57 | const float e = 8.799461f;
58 | const float f = 0.092864f;
59 | const float cut1 = 0.000889f; // Should be equal to ((cut2 - f) / e)
60 | const float cut2 = 0.100686685370811f; // should be equal to (e * cut1 + f)
61 |
62 | if (t >= cut2) {
63 | return ((_exp10f((t - d) / c) - b) / a);
64 | } else {
65 | return ((t - f) / e);
66 | }
67 | }
68 |
69 | // Used values calculated from http://color.support/colorspacecalculator.html
70 | // source color space BT 2020 and Output DWG, with Bradford chromatic adaptation.
71 | __CONSTANT__ float matrix[9] = {
72 | 0.892112, 0.024369, 0.083519,
73 | 0.032617, 0.786138, 0.181246,
74 | 0.069977, 0.104749, 0.825273,
75 | };
76 |
77 | // Used values calculated from http://color.support/colorspacecalculator.html
78 | // source color space DWG and Output BT 2020, with Bradford chromatic adaptation.
79 | __CONSTANT__ float inv_matrix[9] = {
80 | 1.130302, -0.020393, -0.109909,
81 | -0.025547, 1.310849, -0.285302,
82 | -0.092599, -0.164653, 1.257252,
83 | };
84 |
85 |
86 |
87 | DEFINE_UI_PARAMS(invert, invert, DCTLUI_CHECK_BOX, 0);
88 |
89 |
90 | __DEVICE__ float3 transform(int p_Width, int p_Height, int p_X, int p_Y, float p_R, float p_G, float p_B)
91 | {
92 | float3 in = make_float3(p_R,p_G,p_B);
93 |
94 |
95 |
96 | if (invert) {
97 | in.x = oetf_davinci_intermediate(in.x,invert);
98 | in.y = oetf_davinci_intermediate(in.y,invert);
99 | in.z = oetf_davinci_intermediate(in.z,invert);
100 |
101 | in.x = ( inv_matrix[0] * in.x) + ( inv_matrix[1] * in.y) + ( inv_matrix[2] * in.z);
102 | in.y = ( inv_matrix[3] * in.x) + ( inv_matrix[4] * in.y) + ( inv_matrix[5] * in.z);
103 | in.z = ( inv_matrix[6] * in.x) + ( inv_matrix[7] * in.y) + ( inv_matrix[8] * in.z);
104 |
105 | in.x = oetf_fujifilm_flog2(in.x,1-invert);
106 | in.y = oetf_fujifilm_flog2(in.y,1-invert);
107 | in.z = oetf_fujifilm_flog2(in.z,1-invert);
108 |
109 | } else {
110 |
111 |
112 | in.x = oetf_fujifilm_flog2(in.x,1-invert);
113 | in.y = oetf_fujifilm_flog2(in.y,1-invert);
114 | in.z = oetf_fujifilm_flog2(in.z,1-invert);
115 |
116 | in.x = ( matrix[0] * in.x) + ( matrix[1] * in.y) + ( matrix[2] * in.z);
117 | in.y = ( matrix[3] * in.x) + ( matrix[4] * in.y) + ( matrix[5] * in.z);
118 | in.z = ( matrix[6] * in.x) + ( matrix[7] * in.y) + ( matrix[8] * in.z);
119 |
120 | in.x = oetf_davinci_intermediate(in.x,invert);
121 | in.y = oetf_davinci_intermediate(in.y,invert);
122 | in.z = oetf_davinci_intermediate(in.z,invert);
123 | }
124 |
125 |
126 |
127 |
128 | float3 IDT = in;
129 | return IDT;
130 | }
--------------------------------------------------------------------------------
/ME_Desatch.dctl:
--------------------------------------------------------------------------------
1 | #line 2
2 | //Cone model code fromby Juan Pablo Zambrano
3 | //Base transformation to Chen/Spherical coordinates from Quinn Leiho
4 | //Modifications to convert into 'Cone Coordinates' inspired by Steve Yedlin and Matthias Stoopman
5 | //Thanks for the help to Jan Karow, Kaur Hendrikson, Nico Wieseneder,and Keidrych Wasley
6 |
7 |
8 | __DEVICE__ float3 rgb_to_cone(float3 rgb) {
9 | const float pi= 3.14159265359f;
10 | const float rtr = rgb.x * 0.81649658f + rgb.y * -0.40824829f + rgb.z * -0.40824829f;
11 | const float rtg = rgb.x * 0.0f + rgb.y * 0.70710678f + rgb.z * -0.70710678f;
12 | const float rtb = rgb.x * 0.57735027f + rgb.y * 0.57735027f + rgb.z * 0.57735027f;
13 |
14 | const float art = _atan2f(rtg, rtr);
15 |
16 | const float sphr = _sqrtf(rtr*rtr + rtg*rtg + rtb*rtb);
17 | const float spht = art < 0.0f ? art + 2.0f * 3.141592653589f : art;
18 | const float sphp = _atan2f(_sqrtf(rtr*rtr + rtg*rtg), rtb);
19 |
20 | //This is to modify the lum component which is the main reason why the saturation component has a different behavior
21 | const float huecoef1= 1.0f/(2.0f-(0.78539816f/0.61547971f));
22 | const float huecoef2 = 2.0f*sphp*_sinf((2.0f*pi/3.0f)-_fmod(spht,(pi/3.0f)))/1.7320508075688f;
23 | const float huemag =((_acosf(_cosf(3.0f*spht+pi)))/(pi*huecoef1)+(((0.78539816f/0.61547971f))-1.0f))*huecoef2;
24 | const float satmag = _sinf(huemag+0.61547971f);
25 |
26 |
27 |
28 | return make_float3(
29 | sphr*satmag,
30 | spht * 0.15915494309189535f,
31 | sphp * 1.0467733744265997f
32 | );
33 | }
34 |
35 | __DEVICE__ float3 cone_to_rgb(float3 sph) {
36 |
37 | const float pi= 3.14159265359f;
38 | sph.y *= 6.283185307179586f;
39 | sph.z *= 0.9553166181245093f;
40 | const float huecoef1= 1.0f/(2.0f-(0.78539816f/0.61547971f));
41 | const float huecoef2 = 2.0f*sph.z*_sinf((2.0f*pi/3.0f)- _fmod(sph.y,(pi/3.0f)))/1.7320508075688f;
42 | const float huemag =((_acosf(_cosf(3.0f*sph.y+pi)))/(pi*huecoef1)+(((0.78539816f/0.61547971f))-1.0f))*huecoef2;
43 | const float satmagsp = _sinf(huemag+0.61547971f);
44 | sph.x *= 1.0f/satmagsp;
45 |
46 | const float ctr = sph.x * _sinf(sph.z) * _cosf(sph.y);
47 | const float ctg = sph.x * _sinf(sph.z) * _sinf(sph.y);
48 | const float ctb = sph.x * _cosf(sph.z);
49 |
50 | return make_float3(
51 | ctr * 0.81649658f + ctg * 0.0f + ctb * 0.57735027f,
52 | ctr * -0.40824829f + ctg * 0.70710678f + ctb * 0.57735027f,
53 | ctr * -0.40824829f + ctg * -0.70710678f + ctb * 0.57735027f
54 | );
55 | }
56 |
57 |
58 | DEFINE_UI_PARAMS(global_sat, Global deSatch, DCTLUI_SLIDER_FLOAT, 0.0, -1.0, 0.0, 0.0001)
59 | DEFINE_UI_PARAMS(r_sat, Red deSatch, DCTLUI_SLIDER_FLOAT, 0.0, -1.0, 0.0, 0.0001)
60 | DEFINE_UI_PARAMS(g_sat, Green deSatch, DCTLUI_SLIDER_FLOAT, 0.0, -1.0, 0.0, 0.0001)
61 | DEFINE_UI_PARAMS(b_sat, Blue deSatch, DCTLUI_SLIDER_FLOAT, 0.0, -1.0, 0.0, 0.0001)
62 | DEFINE_UI_PARAMS(c_sat, Cyan deSatch, DCTLUI_SLIDER_FLOAT, 0.0, -1.0, 0.0, 0.0001)
63 | DEFINE_UI_PARAMS(m_sat, Magenta deSatch, DCTLUI_SLIDER_FLOAT, 0.0, -1.0, 0.0, 0.0001)
64 | DEFINE_UI_PARAMS(y_sat, Yellow deSatch, DCTLUI_SLIDER_FLOAT, 0.0, -1.0, 0.0, 0.0001)
65 |
66 |
67 |
68 |
69 | __DEVICE__ float3 transform(int p_Width, int p_Height, int p_X, int p_Y, float p_R, float p_G, float p_B) {
70 |
71 |
72 | float3 RGB = make_float3(p_R, p_G, p_B);
73 |
74 | RGB = rgb_to_cone(RGB);
75 | //Initialize variables
76 |
77 | const float3 rgb = make_float3(RGB.x, RGB.y, RGB.z);
78 |
79 | float r = rgb.x;
80 | float g = rgb.y;
81 | float b = rgb.z;
82 |
83 | const float r_pos = 0.0f;
84 | const float g_pos = 0.333f;
85 | const float b_pos = 0.666f;
86 | const float c_pos = 0.4999f;
87 | const float m_pos = 0.8333f;
88 | const float y_pos = 0.1666f;
89 |
90 | const float r_rad = 0.1666f;
91 | const float g_rad = 0.1666f;
92 | const float b_rad = 0.1666f;
93 | const float c_rad = 0.1666f;
94 | const float m_rad = 0.1666f;
95 | const float y_rad = 0.1666f;
96 |
97 |
98 |
99 | //Global deSatch
100 | r = r*(global_sat*b+1.0f);
101 | //g = g-(global_sat/15.0f*b+1.0f);
102 |
103 | //RED
104 | if ( g <= r_pos + r_rad){
105 |
106 |
107 | float r_dist = _fabs(g - r_pos);
108 | float r_offset = (r_dist - 0)/ (r_rad - 0) -1;
109 | r = r*(r_sat*-r_offset*b+1);
110 |
111 |
112 | }
113 |
114 | if ( g >= (r_pos - r_rad+1)){
115 |
116 | float r_dist = _fabs(g - (r_pos+1));
117 | float r_offset = (r_dist - 0)/ (r_rad - 0) -1;
118 | r = r*(r_sat*-r_offset*b+1);
119 |
120 | }
121 |
122 | //GREEN
123 | if (g >= g_pos - g_rad && g <= g_pos + g_rad){
124 |
125 | float g_dist = _fabs(g - g_pos);
126 | float g_offset = (g_dist - 0)/ (g_rad - 0) -1;
127 | r = r*(g_sat*-g_offset*b+1);
128 |
129 |
130 | }
131 |
132 | //BLUE
133 | if (g >= b_pos - b_rad && g <= b_pos + b_rad){
134 |
135 | float b_dist = _fabs(g - b_pos);
136 | float b_offset = (b_dist - 0)/ (b_rad - 0) -1;
137 | r = r*(b_sat*-b_offset*b+1);
138 |
139 | }
140 |
141 | //CYAN
142 | if (g >= c_pos - c_rad && g <= c_pos + c_rad){
143 |
144 | float c_dist = _fabs(g - c_pos);
145 | float c_offset = (c_dist - 0)/ (c_rad - 0) -1;
146 | r = r*(c_sat*-c_offset*b+1);
147 |
148 | }
149 |
150 | //MANGETA
151 | if (g >= m_pos - m_rad && g <= m_pos + m_rad){
152 |
153 | float m_dist = _fabs(g - m_pos);
154 | float m_offset = (m_dist - 0)/ (m_rad - 0) -1;
155 | r = r*(m_sat*-m_offset*b+1);
156 |
157 | }
158 |
159 |
160 | //YELLOW
161 | if (g >= y_pos - y_rad && g <= y_pos + y_rad){
162 |
163 | float y_dist = _fabs(g - y_pos);
164 | float y_offset = (y_dist - 0)/ (y_rad - 0) -1;
165 | r = r*(y_sat*-y_offset*b+1);
166 |
167 | }
168 |
169 | RGB = make_float3 (r,g,b);
170 | RGB = cone_to_rgb(RGB);
171 |
172 |
173 | return RGB;
174 | }
175 |
--------------------------------------------------------------------------------
/ME_HCV Transform.dctl:
--------------------------------------------------------------------------------
1 | #line 2
2 |
3 | /* HCV Color Model Transform v1.3 DCTL
4 | Ported from Akiyoshi Kitaoka
5 | Modified by Moaz Elgabry, moazelgabry.com
6 | This tools is for experiment and demonestration purposes only and is not meant for grading.
7 | */
8 |
9 | // UI Controls
10 | //DEFINE_UI_PARAMS(Direction, Direction, DCTLUI_COMBO_BOX, 0, {forward, inverse}, {Forward RGB to HCV, Inverse HCV to RGB})
11 | DEFINE_UI_PARAMS(ColorSpace, Color Space, DCTLUI_COMBO_BOX, 0, {sRGB, DWG}, {sRGB, DaVinci Wide Gamut})
12 | DEFINE_UI_PARAMS(LumMethod, Luma method, DCTLUI_COMBO_BOX, 0, {simple, iterative}, {Simple Luma, Iterative Luma})
13 | DEFINE_UI_PARAMS(showPatch, Show Patch, DCTLUI_CHECK_BOX, 0)
14 | DEFINE_UI_PARAMS(Direction, Inverse Direction, DCTLUI_CHECK_BOX, 0)
15 | DEFINE_UI_PARAMS(customR, Custom R, DCTLUI_SLIDER_FLOAT, 142, 0.0, 1.0, 0.01)
16 | DEFINE_UI_PARAMS(customG, Custom G, DCTLUI_SLIDER_FLOAT, 204, 0.0, 1.0, 0.01)
17 | DEFINE_UI_PARAMS(customB, Custom B, DCTLUI_SLIDER_FLOAT, 92, 0.0, 1.0, 0.01)
18 | DEFINE_UI_PARAMS(customH, Custom H, DCTLUI_SLIDER_FLOAT, 100, 0, 359, 1)
19 | DEFINE_UI_PARAMS(customC, Custom C, DCTLUI_SLIDER_FLOAT, 0.5, 0.0, 1.0, 0.01)
20 | DEFINE_UI_PARAMS(customV, Custom V, DCTLUI_SLIDER_FLOAT, 0.5, 0.0, 1.0, 0.01)
21 |
22 | // Function to linearize sRGB values
23 | __DEVICE__ float3 srgb_to_linear(float3 gammaRGB) {
24 | return make_float3(
25 | gammaRGB.x <= 0.04045f ? gammaRGB.x / 12.92f : _powf((gammaRGB.x + 0.055f) / 1.055f, 2.4f),
26 | gammaRGB.y <= 0.04045f ? gammaRGB.y / 12.92f : _powf((gammaRGB.y + 0.055f) / 1.055f, 2.4f),
27 | gammaRGB.z <= 0.04045f ? gammaRGB.z / 12.92f : _powf((gammaRGB.z + 0.055f) / 1.055f, 2.4f)
28 | );
29 | }
30 |
31 | // Function to apply sRGB gamma encoding
32 | __DEVICE__ float3 linear_to_srgb(float3 linearRGB) {
33 | return make_float3(
34 | linearRGB.x <= 0.0031308f ? linearRGB.x * 12.92f : 1.055f * _powf(linearRGB.x, 1.0f / 2.4f) - 0.055f,
35 | linearRGB.y <= 0.0031308f ? linearRGB.y * 12.92f : 1.055f * _powf(linearRGB.y, 1.0f / 2.4f) - 0.055f,
36 | linearRGB.z <= 0.0031308f ? linearRGB.z * 12.92f : 1.055f * _powf(linearRGB.z, 1.0f / 2.4f) - 0.055f
37 | );
38 | }
39 |
40 | __DEVICE__ float di_to_linear(float t) {
41 | float a = 0.0075f;
42 | float b = 7.0f;
43 | float c = 0.07329248f;
44 | float m = 10.44426855f;
45 | float log_cut = 0.02740668f; // should be equal to (e * cut1 + f)
46 |
47 | if (t > log_cut) {
48 | return _exp2f((t / c) - b) - a;
49 | } else {
50 | return t / m;
51 | }
52 | }
53 |
54 | __DEVICE__ float3 di_to_linear3(float3 in) {return make_float3(di_to_linear(in.x),di_to_linear(in.y),di_to_linear(in.z));}
55 |
56 | __DEVICE__ float linear_to_di(float x) {
57 | float a = 0.0075f;
58 | float b = 7.0f;
59 | float c = 0.07329248f;
60 | float m = 10.44426855f;
61 | float lin_cut = 0.00262409f; // Should be equal to ((cut2 - f) / e)
62 |
63 | if (x > lin_cut) {
64 | return (_log2f(x + a) + b) * c;
65 | } else {
66 | return x * m;
67 | }
68 | }
69 | __DEVICE__ float3 linear_to_di3(float3 in) {return make_float3(linear_to_di(in.x),linear_to_di(in.y),linear_to_di(in.z));}
70 |
71 |
72 | // RGB to HCV conversion (no arbitrary scaling applied)
73 | __DEVICE__ float3 rgb_to_hcv(float3 rgb, int ColorSpace,float3 lumaCoeffs) {
74 | if(ColorSpace ==0){rgb = srgb_to_linear(rgb);} else {rgb = di_to_linear3(rgb);} // Convert to linear light
75 |
76 | float maxVal = _fmaxf(_fmaxf(rgb.x, rgb.y), rgb.z);
77 | float minVal = _fminf(_fminf(rgb.x, rgb.y), rgb.z);
78 | float delta = maxVal - minVal;
79 |
80 | float hue = 0.0f;
81 | if (delta > 0.0f) {
82 | if (rgb.x == maxVal) hue = _fmod(((rgb.y - rgb.z) / delta) * 60.0f + 360.0f, 360.0f);
83 | else if (rgb.y == maxVal) hue = _fmod(((rgb.z - rgb.x) / delta) * 60.0f + 120.0f, 360.0f);
84 | else hue = _fmod(((rgb.x - rgb.y) / delta) * 60.0f + 240.0f, 360.0f);
85 | }
86 |
87 | float chroma = delta; // No scaling applied
88 | float luminance = (lumaCoeffs.x * rgb.x + lumaCoeffs.y * rgb.y + lumaCoeffs.z * rgb.z); // No scaling applied
89 |
90 | return make_float3(hue, chroma, luminance);
91 | }
92 |
93 | // HCV to RGB conversion (with non-scaled chroma/luminance)
94 | __DEVICE__ float3 hcv_to_rgb(float3 hcv, int Method, int ColorSpace,float3 lumaCoeffs) {
95 | float h = hcv.x;
96 | float c = hcv.y; // No scaling applied
97 | float v = hcv.z; // No scaling applied
98 |
99 | float x = c * (1.0f - _fabs(_fmod(h / 60.0f, 2.0f) - 1.0f));
100 | float3 rgb;
101 |
102 | if (h < 60.0f) rgb = make_float3(c, x, 0.0f);
103 | else if (h < 120.0f) rgb = make_float3(x, c, 0.0f);
104 | else if (h < 180.0f) rgb = make_float3(0.0f, c, x);
105 | else if (h < 240.0f) rgb = make_float3(0.0f, x, c);
106 | else if (h < 300.0f) rgb = make_float3(x, 0.0f, c);
107 | else rgb = make_float3(c, 0.0f, x);
108 |
109 | // Adjust luminance
110 | if (Method == 0) {
111 | // Simple correction
112 | float Y_target = v;
113 | float M = Y_target - (lumaCoeffs.x * rgb.x + lumaCoeffs.y * rgb.y + lumaCoeffs.z * rgb.z);
114 | rgb = make_float3(rgb.x + M, rgb.y + M, rgb.z + M);
115 | } else {
116 | // Iterative refinement
117 | float bestMatchDiff = 99999.0f;
118 | for (int i = 0; i <= 1000; i++) {
119 | float m = (float)i / 1000.0f;
120 | float3 testRGB = make_float3(rgb.x + m, rgb.y + m, rgb.z + m);
121 | float testY = lumaCoeffs.x * testRGB.x + lumaCoeffs.y * testRGB.y + lumaCoeffs.z * testRGB.z;
122 |
123 | float diff = _fabs(testY - v);
124 | if (diff < bestMatchDiff) {
125 | bestMatchDiff = diff;
126 | rgb = testRGB;
127 | }
128 | }
129 | }
130 |
131 | // Apply gamma correction
132 | if (ColorSpace ==0){rgb = linear_to_srgb(rgb);} else { rgb = linear_to_di3(rgb);}
133 | return rgb;
134 | }
135 |
136 | // Main DCTL function
137 | __DEVICE__ float3 transform(int p_Width, int p_Height, int p_X, int p_Y, float p_R, float p_G, float p_B) {
138 | float3 inputRGB = make_float3(p_R, p_G, p_B);
139 | float3 lumaCoeffs = (ColorSpace == 0) ? make_float3(0.2126f, 0.7152f, 0.0722f) : make_float3(0.27411851f, 0.87363190f, -0.14775041f);
140 |
141 | float3 patchRGB = make_float3(customR, customG, customB); // Already in 0-1 range
142 | float3 patchHCV = make_float3(customH, customC, customV);
143 |
144 | // Apply transformation
145 | float3 outputColor = Direction == 0 ? rgb_to_hcv(inputRGB, ColorSpace, lumaCoeffs) : hcv_to_rgb(inputRGB, LumMethod, ColorSpace, lumaCoeffs);
146 |
147 | // Display patch overlay in bottom-right corner
148 | if (showPatch) {
149 | int patchWidth = p_Width * 0.2f;
150 | int patchHeight = p_Height * 0.15f;
151 | if (p_X > p_Width - patchWidth && p_Y > p_Height - patchHeight) {
152 | outputColor = Direction == 0 ? rgb_to_hcv(patchRGB, ColorSpace, lumaCoeffs) : hcv_to_rgb(patchHCV, LumMethod, ColorSpace, lumaCoeffs);
153 | }
154 | }
155 |
156 | return outputColor;
157 | }
158 |
--------------------------------------------------------------------------------
/IDTs/ME_Sony Slog1 IDT.dctl:
--------------------------------------------------------------------------------
1 | #line 2
2 | /*
3 | Custom Input color transform from Sony Slog / S-Gamut
4 | written by Moazelgabry. moazelgabry.com
5 |
6 | */
7 | typedef struct {
8 | float3 x, y, z;
9 | } float3x3;
10 |
11 | __DEVICE__ float3x3 make_float3x3(float3 a, float3 b, float3 c) {
12 | float3x3 d;
13 | d.x = a, d.y = b, d.z = c;
14 | return d;
15 | }
16 |
17 | __DEVICE__ inline float3x3 inv_f33(float3x3 m) {
18 | float d = m.x.x * (m.y.y * m.z.z - m.z.y * m.y.z) - m.x.y * (m.y.x * m.z.z - m.y.z * m.z.x) + m.x.z * (m.y.x * m.z.y - m.y.y * m.z.x);
19 | float id = 1.0f / d;
20 | float3x3 c = make_float3x3(make_float3(1.0f, 0.0f, 0.0f), make_float3(0.0f, 1.0f, 0.0f), make_float3(0.0f, 0.0f, 1.0f));
21 | c.x.x = id * (m.y.y * m.z.z - m.z.y * m.y.z);
22 | c.x.y = id * (m.x.z * m.z.y - m.x.y * m.z.z);
23 | c.x.z = id * (m.x.y * m.y.z - m.x.z * m.y.y);
24 | c.y.x = id * (m.y.z * m.z.x - m.y.x * m.z.z);
25 | c.y.y = id * (m.x.x * m.z.z - m.x.z * m.z.x);
26 | c.y.z = id * (m.y.x * m.x.z - m.x.x * m.y.z);
27 | c.z.x = id * (m.y.x * m.z.y - m.z.x * m.y.y);
28 | c.z.y = id * (m.z.x * m.x.y - m.x.x * m.z.y);
29 | c.z.z = id * (m.x.x * m.y.y - m.y.x * m.x.y);
30 | return c;
31 | }
32 | __DEVICE__ float powf(float base, float exp) {
33 | return _powf(_fabs(base), exp);
34 | }
35 | //Helper Function to Multiply 3x3 Matrix with Vector3:
36 |
37 | __DEVICE__ float3x3 mult_f3_f33_f33(float3 a, float3 b, float3x3 ma, float3x3 mb) {
38 | float3x3 mc;
39 | mc.x.x = mb.x.x * (b.x/a.x) * ma.x.x + mb.x.y * (b.y/a.y) * ma.y.x + mb.x.z * (b.z/a.z) * ma.z.x;
40 | mc.x.y = mb.x.x * (b.x/a.x) * ma.x.y + mb.x.y * (b.y/a.y) * ma.y.y + mb.x.z * (b.z/a.z) * ma.z.y;
41 | mc.x.z = mb.x.x * (b.x/a.x) * ma.x.z + mb.x.y * (b.y/a.y) * ma.y.z + mb.x.z * (b.z/a.z) * ma.z.z;
42 | mc.y.x = mb.y.x * (b.x/a.x) * ma.x.x + mb.y.y * (b.y/a.y) * ma.y.x + mb.y.z * (b.z/a.z) * ma.z.x;
43 | mc.y.y = mb.y.x * (b.x/a.x) * ma.x.y + mb.y.y * (b.y/a.y) * ma.y.y + mb.y.z * (b.z/a.z) * ma.z.y;
44 | mc.y.z = mb.y.x * (b.x/a.x) * ma.x.z + mb.y.y * (b.y/a.y) * ma.y.z + mb.y.z * (b.z/a.z) * ma.z.z;
45 | mc.z.x = mb.z.x * (b.x/a.x) * ma.x.x + mb.z.y * (b.y/a.y) * ma.y.x + mb.z.z * (b.z/a.z) * ma.z.x;
46 | mc.z.y = mb.z.x * (b.x/a.x) * ma.x.y + mb.z.y * (b.y/a.y) * ma.y.y + mb.z.z * (b.z/a.z) * ma.z.y;
47 | mc.z.z = mb.z.x * (b.x/a.x) * ma.x.z + mb.z.y * (b.y/a.y) * ma.y.z + mb.z.z * (b.z/a.z) * ma.z.z;
48 | return mc;
49 | }
50 | __DEVICE__ float3 mult_f33_f3(float3x3 m, float3 a){
51 | return make_float3( m.x.x * a.x + m.x.y * a.y + m.x.z * a.z,
52 | m.y.x * a.x + m.y.y * a.y + m.y.z * a.z,
53 | m.z.x * a.x + m.z.y * a.y + m.z.z * a.z);
54 | }
55 |
56 |
57 |
58 | #define whitepaper_SGamut_to_XYZ make_float3x3(make_float3(0.7648271319f, 0.2709796708f, -0.0096778454f), make_float3(0.1288010498f, 0.7866064112f, 0.0046000375f), make_float3(0.1151721641f, -0.0575860820f, 1.094135587f))
59 | #define bradford_SGamut_to_XYZ make_float3x3(make_float3(0.749592f, 0.156488f, 0.093920f), make_float3(0.291356f, 0.770315f, -0.061670f), make_float3(-0.009867f, 0.006001f, 1.003866f))
60 | #define CAT02_SGamut_to_XYZ make_float3x3(make_float3( 0.743451f, 0.165740f, 0.090809f), make_float3( 0.287051f, 0.776851f, -0.063902f), make_float3(-0.009709f, 0.003346f, 1.006363f))
61 | #define test_SGamut_to_XYZ make_float3x3(make_float3( 0.743309f, 0.135515f, 0.121176f), make_float3( 0.270980f, 0.786606f, -0.057586f), make_float3(-0.008886f, 0.004224f, 1.004663f))
62 | #define matrix_dwg_to_xyz make_float3x3(make_float3(0.745602f, 0.183144f, 0.071254f), make_float3(0.295008f, 0.857088f, -0.152096f), make_float3(-0.091799f, -0.124611f, 1.216410f))
63 | #define matrix_xyz_to_dwg make_float3x3(make_float3(1.51667204202f, -0.281478047879f, -0.146963633237f), make_float3(-0.464917101233f, 1.25142377568f, 0.174884608865f), make_float3(0.064849047067f, 0.109139343711f, 0.76141462155f))
64 | #define matrix_xyz_to_logc3 make_float3x3(make_float3(1.78906555097f, -0.482533863771f, -0.200075792936f), make_float3(-0.639848659902f, 1.39639995686f, 0.194432291778f), make_float3(-0.041531545853f, 0.082335373554f, 0.878868480293f))
65 | #define matrix_davinciwg_to_xyz make_float3x3(make_float3( 0.700622320175f, 0.148774802685f, 0.101058728993f), make_float3( 0.274118483067f, 0.873631775379f,-0.147750422359f), make_float3(-0.098962903023f,-0.137895315886f, 1.325916051865f))
66 | #define matrix_dwg_WPfix make_float3x3(make_float3( 1.032449f, -0.063055f, 0.030605f), make_float3(-0.006363f, 0.998049f, 0.008314f),make_float3(-0.009737f, -0.008747f, 1.018484f))
67 |
68 | __DEVICE__ float3 inline oetf_sony_slog2(float3 x, int inv) {
69 | /* Sony S-Log2
70 | from the pdf originally retrieved from :
71 | https://pro.sony/ue_US/?sonyref=pro.sony.com/bbsccms/assets/files/micro/dmpc/training/S-Log2_Technical_PaperV1_0.pdf
72 | Link is down, here is a mirror:
73 | https://mega.nz/file/e6hDxC5b#YaRzePfGFFPkx_hRtmqw2gTT0NIPuzlJycwCP38H720
74 | */
75 | const float c0 = 0.432699f;
76 | const float c1 = 155.0f;
77 | const float c2 = 219.0f;
78 | const float c3 = 0.037584f;
79 | const float c4 = 0.616596f;
80 | const float c5 = 0.03f;
81 | const float c6 = 3.53881278538813f;
82 | const float c7 = 0.030001222851889303f;
83 |
84 | float3 result;
85 |
86 | if (inv == 1) {
87 | // Inverse transformation
88 | float3 normalized = (x - (64.0f / 1023.0f)) / (876.0f / 1023.0f);
89 | result.x = (normalized.x < c7) ? (normalized.x - c7) / c6
90 | : c2 * (_exp10f((normalized.x - c4 - c5) / c0) - c3) / c1;
91 | result.y = (normalized.y < c7) ? (normalized.y - c7) / c6
92 | : c2 * (_exp10f((normalized.y - c4 - c5) / c0) - c3) / c1;
93 | result.z = (normalized.z < c7) ? (normalized.z - c7) / c6
94 | : c2 * (_exp10f((normalized.z - c4 - c5) / c0) - c3) / c1;
95 | result = result * 0.9f;
96 | } else {
97 | // Forward transformation
98 | float3 scaled = x / 0.9f;
99 | result.x = (scaled.x < 0.0f) ? scaled.x * c6 + c7
100 | : (c0 * _log10f(c1 * scaled.x / c2 + c3) + c4) + c5;
101 | result.y = (scaled.y < 0.0f) ? scaled.y * c6 + c7
102 | : (c0 * _log10f(c1 * scaled.y / c2 + c3) + c4) + c5;
103 | result.z = (scaled.z < 0.0f) ? scaled.z * c6 + c7
104 | : (c0 * _log10f(c1 * scaled.z / c2 + c3) + c4) + c5;
105 | result = result * (876.0f / 1023.0f) + (64.0f / 1023.0f);
106 | }
107 |
108 | return result;
109 | }
110 | __DEVICE__ float3 inline oetf_davinci_intermediate(float3 x, int inv) {
111 | /* DaVinci Intermediate Log OETF and Inverse OETF
112 | Reference:
113 | https://documents.blackmagicdesign.com/InformationNotes/DaVinci_Resolve_17_Wide_Gamut_Intermediate.pdf
114 | */
115 |
116 | // Constants as per DaVinci Intermediate Log specification
117 | const float A = 0.0075f;
118 | const float B = 7.0f;
119 | const float C = 0.07329248f;
120 | const float M = 10.44426855f;
121 | const float LIN_CUT = 0.00262409f;
122 | const float LOG_CUT = 0.02740668f;
123 |
124 | float3 result;
125 |
126 | if (inv == 1) {
127 | // **Inverse Transformation (Log to Linear)**
128 |
129 | // Step 1: Apply piecewise transformation to each component
130 | // If x <= LOG_CUT, apply linear scaling: x / M
131 | // Else, apply exponential scaling: exp2(x / C - B) - A
132 | result.x = (x.x <= LOG_CUT) ? (x.x / M) : (_exp2f(x.x / C - B) - A);
133 | result.y = (x.y <= LOG_CUT) ? (x.y / M) : (_exp2f(x.y / C - B) - A);
134 | result.z = (x.z <= LOG_CUT) ? (x.z / M) : (_exp2f(x.z / C - B) - A);
135 | }
136 | else {
137 | // **Forward Transformation (Linear to Log)**
138 |
139 | // Step 1: Apply piecewise transformation to each component
140 | // If x <= LIN_CUT, apply linear scaling: x * M
141 | // Else, apply logarithmic scaling: (log2(x + A) + B) * C
142 | result.x = (x.x <= LIN_CUT) ? (x.x * M) : ((_log2f(x.x + A) + B) * C);
143 | result.y = (x.y <= LIN_CUT) ? (x.y * M) : ((_log2f(x.y + A) + B) * C);
144 | result.z = (x.z <= LIN_CUT) ? (x.z * M) : ((_log2f(x.z + A) + B) * C);
145 | }
146 |
147 | return result;
148 | }
149 | __DEVICE__ float3 inline oetf_arri_logc3(float3 x, int inv) {
150 | /* Arri Alexa LogC3
151 | Formerly known as Alexa V3LogC EI800
152 | https://www.arri.com/resource/blob/31918/66f56e6abb6e5b6553929edf9aa7483e/2017-03-alexa-logc-curve-in-vfx-data.pdf
153 | */
154 | const float cut = 0.010591f;
155 | const float a = 5.555556f;
156 | const float b = 0.052272f;
157 | const float c = 0.247190f;
158 | const float d = 0.385537f;
159 | const float e = 5.367655f;
160 | const float f = 0.092809f;
161 |
162 | float3 result;
163 |
164 | if (inv == 1) {
165 | // **Inverse Transformation**
166 | // Apply the inverse OETF to each channel
167 | if (x.x < e * cut + f) {
168 | result.x = (x.x - f) / e;
169 | } else {
170 | result.x = (_exp10f((x.x - d) / c) - b) / a;
171 | }
172 |
173 | if (x.y < e * cut + f) {
174 | result.y = (x.y - f) / e;
175 | } else {
176 | result.y = (_exp10f((x.y - d) / c) - b) / a;
177 | }
178 |
179 | if (x.z < e * cut + f) {
180 | result.z = (x.z - f) / e;
181 | } else {
182 | result.z = (_exp10f((x.z - d) / c) - b) / a;
183 | }
184 | } else {
185 | // **Forward Transformation**
186 | // Apply the forward OETF to each channel
187 | if (x.x < cut) {
188 | result.x = e * x.x + f;
189 | } else {
190 | result.x = c * _log10f(a * x.x + b) + d;
191 | }
192 |
193 | if (x.y < cut) {
194 | result.y = e * x.y + f;
195 | } else {
196 | result.y = c * _log10f(a * x.y + b) + d;
197 | }
198 |
199 | if (x.z < cut) {
200 | result.z = e * x.z + f;
201 | } else {
202 | result.z = c * _log10f(a * x.z + b) + d;
203 | }
204 | }
205 |
206 | return result;
207 | }
208 |
209 | __DEVICE__ float inline slog1_encode(float t) {
210 | return (0.432699f * _log10f(t + 0.037584f) + 0.616596f) + 0.03f;
211 | }
212 | __DEVICE__ float inline slog1_decode(float t) {
213 | return _powf(10.0f, (t - 0.616596f - 0.03f) / 0.432699f) - 0.037584f;
214 | }
215 | __DEVICE__ float3 inline oetf_slog1(float3 rgb, int inverse, int bypass_gamut) {
216 |
217 | float3 output_rgb = rgb;
218 |
219 | if (inverse) { // Decode S-Log1 to Linear
220 | // Decode each channel
221 | output_rgb.x = slog1_decode(rgb.x);
222 | output_rgb.y = slog1_decode(rgb.y);
223 | output_rgb.z = slog1_decode(rgb.z);
224 |
225 | // Convert S-Gamut to XYZ
226 | if (bypass_gamut == 0) { output_rgb = mult_f33_f3(bradford_SGamut_to_XYZ, output_rgb);}
227 | return output_rgb;
228 | }
229 | else { // Encode Linear to S-Log1
230 | // Convert XYZ to S-Gamut
231 | if (bypass_gamut == 0) {output_rgb = mult_f33_f3(inv_f33(bradford_SGamut_to_XYZ), rgb);}
232 |
233 | // Encode each channel
234 | output_rgb.x = slog1_encode(output_rgb.x);
235 | output_rgb.y = slog1_encode(output_rgb.y);
236 | output_rgb.z = slog1_encode(output_rgb.z);
237 | return output_rgb;
238 | }
239 | }
240 |
241 |
242 | // UI Parameters
243 | DEFINE_UI_PARAMS(bypass, Bypass, DCTLUI_CHECK_BOX, 0)
244 | DEFINE_UI_PARAMS(bypass_gamut, Bypass Gamut Conversion, DCTLUI_CHECK_BOX, 0)
245 | DEFINE_UI_PARAMS(P_convert, Convert, DCTLUI_COMBO_BOX, 1, {log2lin, slog2, DWGDI,logc3,lin2log}, {to linear / CIE XYZ, to Slog2 / S-Gamut, to DWG / DI,to LogC3 / Arri Wide Gamut 3, Lin to Slog 1 / S-Gamut})
246 |
247 |
248 |
249 | __DEVICE__ float3 transform(int p_Width, int p_Height, int p_X, int p_Y, float p_R, float p_G, float p_B) {
250 | // Create a float3 vector from the input RGB values
251 | float3 rgb = make_float3(p_R, p_G, p_B);
252 | float3 out = rgb;
253 |
254 | //do nothing in bypass option
255 | if (bypass) { return rgb;}
256 |
257 |
258 | if (P_convert == 0){ // Apply S-Log1 Transformation
259 | out = oetf_slog1(rgb, 1,bypass_gamut);
260 | } else if (P_convert == 1){ //convert to Slog 2 S-Gamut
261 | out = oetf_slog1(rgb, 1,bypass_gamut);
262 | if (bypass_gamut == 0) { out =mult_f33_f3(inv_f33(bradford_SGamut_to_XYZ), out); }
263 | out = oetf_sony_slog2(out,0);
264 |
265 | } else if (P_convert == 2) { // convert to DWG DI
266 | out = oetf_slog1(rgb, 1,bypass_gamut);
267 | if (bypass_gamut == 0) { out = mult_f33_f3(matrix_xyz_to_dwg, out);}
268 | out = oetf_davinci_intermediate(out , 0);
269 |
270 |
271 | } else if (P_convert == 3) {
272 | out = oetf_slog1(rgb, 1,bypass_gamut);
273 | if (bypass_gamut == 0) { out = mult_f33_f3(matrix_xyz_to_logc3, out); }
274 | out = oetf_arri_logc3(out , 0);
275 | } else if (P_convert == 4) {
276 | out = oetf_slog1(rgb, 0,bypass_gamut);
277 | }
278 |
279 |
280 | return out;
281 | }
282 |
--------------------------------------------------------------------------------
/ME_Smooth_Tetra.dctl:
--------------------------------------------------------------------------------
1 | #line 2
2 | /*
3 | Written by Moaz ELgabry | moazelgabry.com
4 |
5 | ME_Smooth Tetra v0.3.10
6 |
7 | - Added: Continuous Energy Reconstruction (Luma Stability)
8 | - Improved: Stability Logic uses smooth derivatives to avoid hard edges
9 | - Native smooth sector map in an axis-locked basis
10 | - Neutrals preserved (operations vanish at c=0)
11 | - Six C∞ angular windows (partition of unity) -> tetrahedra "aware" of each other
12 | */
13 |
14 | /* ------------------------------------------------------------------------------------
15 | Primary UI
16 | ------------------------------------------------------------------------------------ */
17 | DEFINE_UI_PARAMS(RED_HUE, [R] _ RED HUE, DCTLUI_SLIDER_FLOAT, 0.0, -1.0, 1.0, 0.001)
18 | DEFINE_UI_PARAMS(RED_SAT, [R] _ Red Sat, DCTLUI_SLIDER_FLOAT, 0.0, -1.0, 1.0, 0.001)
19 | DEFINE_UI_PARAMS(RED_VAL, [R] _ Red Value, DCTLUI_SLIDER_FLOAT, 0.0, -1.0, 1.0, 0.001)
20 | DEFINE_UI_PARAMS(GRN_HUE, [G] _ GREEN HUE, DCTLUI_SLIDER_FLOAT, 0.0, -1.0, 1.0, 0.001)
21 | DEFINE_UI_PARAMS(GRN_SAT, [G] _ Green Sat, DCTLUI_SLIDER_FLOAT, 0.0, -1.0, 1.0, 0.001)
22 | DEFINE_UI_PARAMS(GRN_VAL, [G] _ Green Value, DCTLUI_SLIDER_FLOAT, 0.0, -1.0, 1.0, 0.001)
23 | DEFINE_UI_PARAMS(BLU_HUE, [B] _ BLUE HUE, DCTLUI_SLIDER_FLOAT, 0.0, -1.0, 1.0, 0.001)
24 | DEFINE_UI_PARAMS(BLU_SAT, [B] _ Blue Sat, DCTLUI_SLIDER_FLOAT, 0.0, -1.0, 1.0, 0.001)
25 | DEFINE_UI_PARAMS(BLU_VAL, [B] _ Blue Value, DCTLUI_SLIDER_FLOAT, 0.0, -1.0, 1.0, 0.001)
26 | DEFINE_UI_PARAMS(CYN_HUE, [C] _ CYAN HUE, DCTLUI_SLIDER_FLOAT, 0.0, -1.0, 1.0, 0.001)
27 | DEFINE_UI_PARAMS(CYN_SAT, [C] _ Cyan Sat, DCTLUI_SLIDER_FLOAT, 0.0, -1.0, 1.0, 0.001)
28 | DEFINE_UI_PARAMS(CYN_VAL, [C] _ Cyan Value, DCTLUI_SLIDER_FLOAT, 0.0, -1.0, 1.0, 0.001)
29 | DEFINE_UI_PARAMS(MAG_HUE, [M] _ MAGENTA HUE, DCTLUI_SLIDER_FLOAT, 0.0, -1.0, 1.0, 0.001)
30 | DEFINE_UI_PARAMS(MAG_SAT, [M] _ Magenta Sat, DCTLUI_SLIDER_FLOAT, 0.0, -1.0, 1.0, 0.001)
31 | DEFINE_UI_PARAMS(MAG_VAL, [M] _ Magenta Value, DCTLUI_SLIDER_FLOAT, 0.0, -1.0, 1.0, 0.001)
32 | DEFINE_UI_PARAMS(YEL_HUE, [Y] _ YELLOW HUE, DCTLUI_SLIDER_FLOAT, 0.0, -1.0, 1.0, 0.001)
33 | DEFINE_UI_PARAMS(YEL_SAT, [Y] _ Yellow Sat, DCTLUI_SLIDER_FLOAT, 0.0, -1.0, 1.0, 0.001)
34 | DEFINE_UI_PARAMS(YEL_VAL, [Y] _ Yellow Value, DCTLUI_SLIDER_FLOAT, 0.0, -1.0, 1.0, 0.001)
35 |
36 | DEFINE_UI_PARAMS(HUE_SHARPNESS, Hue Sharpness, DCTLUI_SLIDER_FLOAT, .880, 0.50, 1.80, 0.01)
37 | DEFINE_UI_PARAMS(VAL_STABILITY, Luma Stability, DCTLUI_SLIDER_FLOAT, 0.45, 0.00, 1.00, 0.01)
38 | DEFINE_UI_PARAMS(CLAMP_OUT, Clamp Output, DCTLUI_CHECK_BOX, 1)
39 |
40 | /* ------------------------------------------------------------------------------------
41 | Helpers
42 | ------------------------------------------------------------------------------------ */
43 | __DEVICE__ inline float3 add3(float3 a,float3 b){return make_float3(a.x+b.x,a.y+b.y,a.z+b.z);}
44 | __DEVICE__ inline float3 sub3(float3 a,float3 b){return make_float3(a.x-b.x,a.y-b.y,a.z-b.z);}
45 | __DEVICE__ inline float3 muls(float3 a,float s){return make_float3(a.x*s,a.y*s,a.z*s);}
46 | __DEVICE__ inline float dot3(float3 a,float3 b){return a.x*b.x+a.y*b.y+a.z*b.z;}
47 | __DEVICE__ inline float3 cross3(float3 a,float3 b){return make_float3(a.y*b.z-a.z*b.y, a.z*b.x-a.x*b.z, a.x*b.y-a.y*b.x);}
48 | __DEVICE__ inline float len3(float3 a){return _sqrtf(dot3(a,a));}
49 | __DEVICE__ inline float3 norm3(float3 a){float L=len3(a);return (L>1e-8f)?muls(a,1.0f/L):make_float3(0.577f,0.577f,0.577f);}
50 | __DEVICE__ inline float3 clamp01(float3 v){v.x=_fminf(_fmaxf(v.x,0.0f),1.0f);v.y=_fminf(_fmaxf(v.y,0.0f),1.0f);v.z=_fminf(_fmaxf(v.z,0.0f),1.0f);return v;}
51 | __DEVICE__ inline float wrap_pi(float a){const float TW=6.28318530718f,PI=3.141592653589f;return a - TW*_floorf((a+PI)/TW);}
52 | __DEVICE__ inline float smoothstep(float e0,float e1,float x){float d=_fmaxf(e1-e0,1e-12f);float t=_fminf(1.0f,_fmaxf(0.0f,(x-e0)/d));return t*t*(3.0f-2.0f*t);}
53 | __DEVICE__ inline float lerp(float a, float b, float t){ return a + t*(b - a); }
54 | __DEVICE__ inline float max3(float a, float b, float c) { return _fmaxf(a, _fmaxf(b, c)); }
55 |
56 | /* basis */
57 | typedef struct { float3 n,u,v; float Lbw; } Basis;
58 | __DEVICE__ inline Basis build_basis(float3 blk,float3 wht){
59 | Basis B; float3 d=sub3(wht,blk);
60 | B.n=norm3(d);
61 | float3 a=make_float3(1,0,0); if(_fabs(B.n.x)>0.9f) a=make_float3(0,1,0);
62 | float3 ut=sub3(a,muls(B.n,dot3(a,B.n))); B.u=norm3(ut);
63 | B.v=cross3(B.u,B.n); if(dot3(cross3(B.u,B.v),B.n)<0.0f) B.v=muls(B.v,-1.0f);
64 | B.Lbw=_fmaxf(dot3(d,B.n),1e-8f);
65 | return B;
66 | }
67 | __DEVICE__ inline float3 to_coords(float3 x,float3 blk,Basis B){float3 d=sub3(x,blk);return make_float3(dot3(d,B.n)/B.Lbw,dot3(d,B.u),dot3(d,B.v));}
68 | __DEVICE__ inline float ang_of(float3 dir,Basis B){float3 dp=sub3(dir,muls(B.n,dot3(dir,B.n)));return _atan2f(dot3(dp,B.v),dot3(dp,B.u));}
69 |
70 | /* headroom */
71 | __DEVICE__ inline float headroom_soft_unbiased(float3 N, float3 D, float beta){
72 | const float BIG = 1e8f;
73 |
74 | float tx = (_fabs(D.x)<1e-8f)?BIG:(D.x>0.0f?(1.0f-N.x)/D.x:(0.0f-N.x)/D.x);
75 | float ty = (_fabs(D.y)<1e-8f)?BIG:(D.y>0.0f?(1.0f-N.y)/D.y:(0.0f-N.y)/D.y);
76 | float tz = (_fabs(D.z)<1e-8f)?BIG:(D.z>0.0f?(1.0f-N.z)/D.z:(0.0f-N.z)/D.z);
77 |
78 | float m = _fminf(tx, _fminf(ty, tz));
79 | float ex = _expf(-beta*(tx - m));
80 | float ey = _expf(-beta*(ty - m));
81 | float ez = _expf(-beta*(tz - m));
82 | float s = ex + ey + ez;
83 | float r_soft = m - (_logf(s) / _fmaxf(beta,1e-6f));
84 |
85 | float wx = ex / _fmaxf(s, 1e-20f);
86 | float wy = ey / _fmaxf(s, 1e-20f);
87 | float wz = ez / _fmaxf(s, 1e-20f);
88 | float inv_sum_sq = 1.0f / _fmaxf(wx*wx + wy*wy + wz*wz, 1e-12f);
89 | float K_eff = _fminf(3.0f, _fmaxf(1.0f, inv_sum_sq));
90 |
91 | float bias = _logf(K_eff) / _fmaxf(beta, 1e-6f);
92 | float r_unbiased = r_soft + bias;
93 |
94 | return _fmaxf(r_unbiased, 0.0f);
95 | }
96 |
97 | __DEVICE__ inline float soft_knee_down(float x, float t) {
98 | float tt = _fmaxf(t, 1e-8f);
99 | float u = x / tt;
100 | return x / (1.0f + u*u);
101 | }
102 |
103 | typedef struct {
104 | float hue_gate_bias, hue_gate_floor, hue_gate_mix, hue_gate_k;
105 | float beta_lo;
106 | float val_range, val_bias;
107 | float UI_EPS;
108 | } Tunables;
109 |
110 | /* ------------------------------------------------------------------------------------
111 | main
112 | ------------------------------------------------------------------------------------ */
113 | __DEVICE__ float3 transform(int p_Width, int p_Height, int p_X, int p_Y, float p_R, float p_G, float p_B)
114 | {
115 | Tunables cfg;
116 | cfg.hue_gate_bias = 0.958f; cfg.hue_gate_floor = 0.06f;
117 | cfg.hue_gate_mix = 0.775f; cfg.hue_gate_k = 0.031f;
118 | cfg.beta_lo = 6.0f;
119 | cfg.val_range = 0.25f; cfg.val_bias = 1.70f;
120 | cfg.UI_EPS = 1e-4f;
121 |
122 | const float3 BLK = make_float3(0,0,0), WHT = make_float3(1,1,1);
123 | const float PI = 3.141592653589f, LN2 = 0.69314718056f;
124 |
125 | // ---------------- Basis & coordinates ----------------
126 | Basis B = build_basis(BLK, WHT);
127 | float3 P = make_float3(p_R, p_G, p_B);
128 |
129 | // Track Energy
130 | float E_in = max3(P.x, P.y, P.z);
131 |
132 | const float UI_MAG =
133 | _fabs(RED_HUE)+_fabs(RED_SAT)+_fabs(RED_VAL)+
134 | _fabs(GRN_HUE)+_fabs(GRN_SAT)+_fabs(GRN_VAL)+
135 | _fabs(BLU_HUE)+_fabs(BLU_SAT)+_fabs(BLU_VAL)+
136 | _fabs(CYN_HUE)+_fabs(CYN_SAT)+_fabs(CYN_VAL)+
137 | _fabs(MAG_HUE)+_fabs(MAG_SAT)+_fabs(MAG_VAL)+
138 | _fabs(YEL_HUE)+_fabs(YEL_SAT)+_fabs(YEL_VAL);
139 |
140 | if (UI_MAG == 0.0f) {
141 | float3 out0 = P; if (CLAMP_OUT) out0 = clamp01(out0);
142 | return out0;
143 | }
144 |
145 | // Scene coords & polar
146 | float3 scv = to_coords(P, BLK, B);
147 | float s = scv.x;
148 | float cu = scv.y;
149 | float cv = scv.z;
150 | float c = _sqrtf(cu*cu + cv*cv);
151 | float h = _atan2f(cv, cu);
152 |
153 | // Base axis & chroma norm
154 | float3 N0 = add3(BLK, muls(B.n, s * B.Lbw));
155 | float ch = _cosf(h), sh = _sinf(h);
156 | float3 dir0 = add3(muls(B.u, ch), muls(B.v, sh));
157 | float R0s = headroom_soft_unbiased(N0, dir0, cfg.beta_lo);
158 | float alpha0 = (R0s > 1e-8f) ? _fminf(c/R0s, 1.0f) : 0.0f;
159 |
160 | // --- Compute rho0 at the current angle (axis N0, dir0_u) for chroma-aware kappa ---
161 | float3 dir0_u = norm3(add3(muls(B.u, ch), muls(B.v, sh)));
162 | float R0 = headroom_soft_unbiased(N0, dir0_u, cfg.beta_lo);
163 | float rho0 = (R0 > 1e-8f) ? (c / R0) : 0.0f; // 0..1-ish relative chroma
164 |
165 | // --- Six hue window centres ---
166 | float aR=ang_of(make_float3(1,0,0),B);
167 | float aY=ang_of(make_float3(1,1,0),B);
168 | float aG=ang_of(make_float3(0,1,0),B);
169 | float aC=ang_of(make_float3(0,1,1),B);
170 | float aB=ang_of(make_float3(0,0,1),B);
171 | float aM=ang_of(make_float3(1,0,1),B);
172 |
173 | // --- rho-aware sharpness: soften windows near axis to avoid boundary kinks ---
174 | float k_user = _fminf(4.0f, 3.0f*HUE_SHARPNESS);
175 | float k_chroma = smoothstep(0.12f, 0.35f, rho0); // 0 near axis, 1 when reasonably saturated
176 | float kappa_eff = k_user * k_chroma;
177 |
178 | // --- rounded cosine lobes (p<1 blunts the peak) ---
179 | float p_cos = 0.90f;
180 | float dR = wrap_pi(h - aR), dY = wrap_pi(h - aY), dG = wrap_pi(h - aG);
181 | float dC = wrap_pi(h - aC), dB = wrap_pi(h - aB), dM = wrap_pi(h - aM);
182 |
183 | float cR = _powf(_fmaxf(_cosf(dR), 0.0f), p_cos);
184 | float cY = _powf(_fmaxf(_cosf(dY), 0.0f), p_cos);
185 | float cG = _powf(_fmaxf(_cosf(dG), 0.0f), p_cos);
186 | float cC = _powf(_fmaxf(_cosf(dC), 0.0f), p_cos);
187 | float cB = _powf(_fmaxf(_cosf(dB), 0.0f), p_cos);
188 | float cM = _powf(_fmaxf(_cosf(dM), 0.0f), p_cos);
189 |
190 | // --- tempered softmax with a tiny floor, then renormalise (prevents hard handovers) ---
191 | float eR = _expf(kappa_eff * cR);
192 | float eY = _expf(kappa_eff * cY);
193 | float eG = _expf(kappa_eff * cG);
194 | float eC = _expf(kappa_eff * cC);
195 | float eB = _expf(kappa_eff * cB);
196 | float eM = _expf(kappa_eff * cM);
197 |
198 | const float epsW = 1e-5f; // small weight floor to keep all regions “alive”
199 | eR += epsW; eY += epsW; eG += epsW; eC += epsW; eB += epsW; eM += epsW;
200 |
201 | float es = eR+eY+eG+eC+eB+eM;
202 | float wR = eR/es, wY = eY/es, wG = eG/es, wC = eC/es, wB = eB/es, wM = eM/es;
203 |
204 | // --- Regional asks + UI engagement (unchanged below; reuse your UI_EPS mix) ---
205 | float dHue=(PI/3.0f)*(wR*RED_HUE+wY*YEL_HUE+wG*GRN_HUE+wC*CYN_HUE+wB*BLU_HUE+wM*MAG_HUE);
206 | float dSat=(wR*RED_SAT+wY*YEL_SAT+wG*GRN_SAT+wC*CYN_SAT+wB*BLU_SAT+wM*MAG_SAT);
207 | float dVal=(wR*RED_VAL+wY*YEL_VAL+wG*GRN_VAL+wC*CYN_VAL+wB*BLU_VAL+wM*MAG_VAL);
208 |
209 | float adj_mag = _fabs(dHue)+_fabs(dSat)+_fabs(dVal);
210 | float ui_mix = smoothstep(cfg.UI_EPS, 8.0f*cfg.UI_EPS, adj_mag);
211 | dHue*=ui_mix; dSat*=ui_mix; dVal*=ui_mix;
212 |
213 |
214 | float alpha_abs = c / (c + cfg.hue_gate_k);
215 | float a_mix = (1.0f - cfg.hue_gate_mix)*alpha0 + cfg.hue_gate_mix*alpha_abs;
216 | float chi = _powf(_fmaxf(a_mix, cfg.hue_gate_floor), cfg.hue_gate_bias);
217 |
218 | // Rotation
219 | float theta = chi * dHue;
220 | float cost = _cosf(theta), sint = _sinf(theta);
221 | float cu_r = cu*cost - cv*sint;
222 | float cv_r = cu*sint + cv*cost;
223 |
224 | float3 C_rot = add3(muls(B.u, cu_r), muls(B.v, cv_r));
225 | float r2 = cu_r*cu_r + cv_r*cv_r;
226 | float3 dir_used = (r2 > 1e-16f) ? norm3(C_rot) : dir0;
227 |
228 | // Value
229 | float dVal_soft = dVal / (1.0f + 0.8f*_fabs(dVal));
230 | float g_val = _powf(alpha0, cfg.val_bias);
231 | float s2 = _fminf(_fmaxf(s + cfg.val_range*dVal_soft*g_val, 0.0f), 1.0f);
232 |
233 | // Saturation
234 | float c_sat = c * _expf(chi * dSat * LN2);
235 |
236 | // Recompute ρ at the *rotated* angle for better locality
237 | float r2_rot = cu_r*cu_r + cv_r*cv_r;
238 | float c_rot = _sqrtf(r2_rot);
239 | float R_rot = headroom_soft_unbiased(N0, norm3(add3(muls(B.u, cu_r/_fmaxf(c_rot,1e-16f)),
240 | muls(B.v, cv_r/_fmaxf(c_rot,1e-16f)))),
241 | cfg.beta_lo);
242 | float rho_rot = (R_rot > 1e-8f) ? (c_rot / R_rot) : 0.0f;
243 |
244 | // Gate by ρ so behaviour near the axis is extra smooth regardless of sector shape
245 | float tip_gate = smoothstep(0.06f, 0.24f, rho_rot);
246 | float c_req = lerp(c, c_sat, tip_gate);
247 |
248 |
249 | // Limiter
250 | float use_val = _fminf(1.0f, _fabs(dVal));
251 | float s_used = lerp(s, s2, use_val);
252 | float3 N_wall = add3(BLK, muls(B.n, s_used * B.Lbw));
253 | float R_wall = headroom_soft_unbiased(N_wall, dir_used, 16.0f);
254 | float excess = _fmaxf(0.0f, c_req - R_wall);
255 | float knee = 0.18f * _fmaxf(R_wall, 1e-6f);
256 | float excess_s = soft_knee_down(excess, knee);
257 | float c_limited = c_req - excess + excess_s;
258 |
259 | // Build
260 | float3 Cprime = muls(dir_used, c_limited);
261 | const float Lbw_eps = _fmaxf(B.Lbw, 1e-8f);
262 | float Y_in = dot3(P, B.n);
263 | float Y_target = Y_in + (s2 - s) * B.Lbw;
264 | float s_fix = Y_target / Lbw_eps;
265 | float s_final = _fminf(1.0f, _fmaxf(0.0f, s_fix));
266 | float3 N_out = add3(BLK, muls(B.n, s_final * B.Lbw));
267 | float R_final = headroom_soft_unbiased(N_out, dir_used, 16.0f);
268 | float c_final = _fminf(c_limited, _fmaxf(R_final*(1.0f - 1e-5f), 0.0f));
269 |
270 | float3 out = add3(N_out, muls(dir_used, c_final));
271 |
272 | /* ------------------------------------------------------------------------------------
273 | ENERGY RECONSTRUCTION (Smoothed)
274 | Restores Max-RGB energy lost during hue rotation.
275 | ------------------------------------------------------------------------------------ */
276 | // 1. Measure output energy
277 | float E_out = max3(out.x, out.y, out.z);
278 |
279 | // 2. Conflict Detection:
280 | // If user *wants* to darken (dVal < 0), fade out the restoration.
281 | // Smoothstep ensures no hard switch-off.
282 | float user_darken_intent = smoothstep(-0.25f, -0.05f, dVal); // 0.0 = dark Intent, 1.0 = normal/bright
283 |
284 | // 3. Loss Calculation:
285 | // How much did we lose? (Ratio > 1.0 means loss)
286 | float loss_ratio = (E_out > 1e-6f) ? (E_in / E_out) : 1.0f;
287 |
288 | // 4. Boost Calculation:
289 | // We apply boost smoothly based on saturation (chi) and slider strength.
290 | // We use `softplus` logic implicitly by blending the gain.
291 | float restoration_mask = chi * user_darken_intent; // Only saturated pixels, unless darkened by user
292 |
293 | // We define "Boost" as the extra gain needed (e.g. 1.5x gain is +0.5 boost)
294 | // We scale this boost by the slider (now up to 2.0x strength)
295 | float raw_boost = _fmaxf(0.0f, loss_ratio - 1.0f);
296 |
297 | // Apply Boost smoothly
298 | float applied_gain = 1.0f + (raw_boost * VAL_STABILITY * restoration_mask);
299 |
300 | out = muls(out, applied_gain);
301 |
302 | if (CLAMP_OUT) out = clamp01(out);
303 |
304 | return out;
305 | }
--------------------------------------------------------------------------------
/ME_Hue Tetra v1.0.dctl:
--------------------------------------------------------------------------------
1 | #line 2
2 |
3 | /*
4 | Written by Moaz Elgabry
5 |
6 | ME_Hue Tetra V 1.0.1
7 |
8 | This tool uses the Tetra HSV model to manipulate 6 vectors of hues
9 | with the added functionality of mixing back original saturation and luminance.
10 | by using a couple of different color models to separate the color elements the results can vary in interesting ways.
11 |
12 | Tetra HSV code is based on this DCTL
13 | https://github.com/hotgluebanjo/TetraInterp-DCTL/blob/master/TetraInterpHSV.dctl
14 |
15 | */
16 |
17 | __DEVICE__ float3 mv_33_3(float mat[3][3], float3 v) {
18 | float3 out = make_float3(mat[0][0] * v.x + mat[0][1] * v.y + mat[0][2] * v.z,
19 | mat[1][0] * v.x + mat[1][1] * v.y + mat[1][2] * v.z,
20 | mat[2][0] * v.x + mat[2][1] * v.y + mat[2][2] * v.z);
21 | return out;
22 | }
23 |
24 |
25 | __DEVICE__ float mod(float x, float y) {
26 | if (x < 0) {
27 | return y + _fmod(x, y);
28 | } else {
29 | return _fmod(x, y);
30 | }
31 | }
32 |
33 | //color models
34 | __DEVICE__ float3 RGBtoCHEN(float3 in) {
35 | float r = in.x;
36 | float g = in.y;
37 | float b = in.z;
38 |
39 | float h;
40 | float c;
41 | float l;
42 |
43 | const float rtr = r * 0.81649658f + g * -0.40824829f + b * -0.40824829f;
44 | const float rtg = r * 0.0f + g * 0.70710678f + b * -0.70710678f;
45 | const float rtb = r * 0.57735027f + g * 0.57735027f + b * 0.57735027f;
46 |
47 | const float art = _atan2f(rtg, rtr);
48 |
49 | const float sphr = _sqrtf(rtr*rtr + rtg*rtg + rtb*rtb);
50 | const float spht = art < 0.0f ? art + 2.0f * 3.141592653589f : art;
51 | const float sphp = _atan2f(_sqrtf(rtr*rtr + rtg*rtg), rtb);
52 |
53 | l = sphr * 0.5773502691896258f;
54 | h = spht * 0.15915494309189535f;
55 | c = sphp * 1.0467733744265997f;
56 |
57 | return make_float3(h, c, l);
58 | } //by Kaur Hendrikson
59 |
60 | __DEVICE__ float3 CHENtoRGB(float3 in) {
61 | float h = in.x * 6.283185307179586f;
62 | float c = in.y * 0.9553166181245093f;
63 | float l = in.z * 1.7320508075688772f;
64 |
65 | float r = 0;
66 | float g = 0;
67 | float b = 0;
68 |
69 | const float ctr = l * _sinf(c) * _cosf(h);
70 | const float ctg = l * _sinf(c) * _sinf(h);
71 | const float ctb = l * _cosf(c);
72 |
73 | r = ctr * 0.81649658f + ctg * 0.0f + ctb * 0.57735027f;
74 | g = ctr * -0.40824829f + ctg * 0.70710678f + ctb * 0.57735027f;
75 | b = ctr * -0.40824829f + ctg * -0.70710678f + ctb * 0.57735027f;
76 |
77 | return make_float3(r, g, b);
78 | } //by Kaur Hendrikson
79 |
80 | __DEVICE__ float3 rgb_to_reuleaux(float3 rgb) {
81 | #define PI 3.1415926535897932384626
82 |
83 | float3 NORM_MULTS = make_float3(2.0f * PI, _sqrtf(2.0f), 1.0f);
84 | float3 rot = { _sqrtf(2.0f) / 6.0f * (2.0f * rgb.x - rgb.y - rgb.z),
85 | (rgb.y - rgb.z) / _sqrtf(6.0f),
86 | (rgb.x + rgb.y + rgb.z) / 3.0f};
87 | float3 rlx = { PI - _atan2f(rot.y, -rot.x),
88 | rot.z == 0.0f ? 0.0f : _hypotf(rot.x, rot.y) / rot.z,
89 | _fmaxf(rgb.x, _fmaxf(rgb.y, rgb.z))};
90 | return rlx / NORM_MULTS;
91 | }
92 |
93 | __DEVICE__ float3 reuleaux_to_rgb(float3 rlx) {
94 | #define PI 3.1415926535897932384626
95 | float3 NORM_MULTS = make_float3(2.0f * PI, _sqrtf(2.0f), 1.0f);
96 | rlx *= NORM_MULTS;
97 | float m = NORM_MULTS.y * _fmaxf(_cosf(rlx.x), _fmaxf(_cosf(rlx.x + NORM_MULTS.x / 3.0f), _cosf(rlx.x - NORM_MULTS.x / 3.0f))) + 1.0f/rlx.y;
98 | float3 ocs = { rlx.z * _cosf(rlx.x) / m,
99 | rlx.z * _sinf(rlx.x) / m,
100 | rlx.z};
101 | float3 rgb = { ocs.z - _sqrtf(3.0f / 2.0f) * _fmaxf(_fabs(ocs.y) - _sqrtf(3.0f) * ocs.x, 0.0f),
102 | ocs.z - _sqrtf(3.0f / 2.0f) * (_fmaxf(_fabs(ocs.y), _sqrtf(3.0f) * ocs.x) - ocs.y),
103 | ocs.z - _sqrtf(3.0f / 2.0f) * (_fmaxf(_fabs(ocs.y), _sqrtf(3.0f) * ocs.x) + ocs.y)};
104 | return rgb;
105 | }
106 |
107 | __DEVICE__ float3 cylindrical_to_rgb(float3 hsv) {
108 | // Adapted from Juan Pablo Zambrano's code
109 | float3 lsh = make_float3(hsv.z, hsv.y * 3.0, mod(hsv.x, 1.0) * 2.0 * PI);
110 |
111 | float ctr = lsh.x * lsh.y * _cosf(lsh.z);
112 | float ctg = lsh.x;
113 | float ctb = lsh.x * lsh.y * _sinf(lsh.z);
114 | float3 c = make_float3(ctr, ctg, ctb);
115 |
116 | float mat[3][3] = {
117 | {2.0 / 3.0, 1.0, 0.0},
118 | {-1.0 / 3.0, 1.0, _sqrtf(3.0) / 3.0},
119 | {-1.0 / 3.0, 1.0, -_sqrtf(3.0) / 3.0},
120 | };
121 |
122 | return mv_33_3(mat, c);
123 | }
124 |
125 | __DEVICE__ float3 rgb_to_cylindrical(float3 x) {
126 |
127 | // Matrix aligns and scales achromatic white (1, 1, 1) with (0, 1, 0)
128 | // Also rotates input (1, 0, 0) above the red axis and ensures that
129 | // (1, 0, 0) input ends up having a red channel code value of (1).
130 | float mat[3][3] = {
131 | {1.0, -1.0 / 2.0, -1.0 / 2.0},
132 | {1.0 / 3.0, 1.0 / 3.0, 1.0 / 3.0},
133 | {0.0, _sqrtf(3.0) / 2.0, -_sqrtf(3.0) / 2.0},
134 | };
135 |
136 | float3 rotated_color = mv_33_3(mat, x);
137 | float l = rotated_color.y;
138 | float3 hsl = make_float3(0.0, 0.0, 0.0);
139 |
140 | float3 normalized_color = rotated_color / l;
141 | if (l == 0.0) {
142 | hsl = make_float3(0.0, 0.0, l);
143 | } else {
144 | float theta = _atan2f(normalized_color.z, normalized_color.x);
145 | hsl.x = mod(theta, 2.0 * PI) / (2.0 * PI);
146 | hsl.y = _hypotf(normalized_color.x, normalized_color.z) / 3.0;
147 | hsl.z = l;
148 | }
149 | return hsl;
150 | }
151 |
152 | __DEVICE__ float3 RGB_to_HSV(float3 RGB) {
153 | float3 HSV;
154 | float min = _fminf(_fminf(RGB.x, RGB.y), RGB.z);
155 | float max = _fmaxf(_fmaxf(RGB.x, RGB.y), RGB.z);
156 | HSV.z = max;
157 | float delta = max - min;
158 | if (max != 0.0f) {
159 | HSV.y = delta / max;
160 | } else {
161 | HSV.y = 0.0f;
162 | HSV.x = 0.0f;
163 | return HSV;
164 | }
165 | if (delta == 0.0f) {
166 | HSV.x = 0.0f;
167 | } else if (RGB.x == max) {
168 | HSV.x = (RGB.y - RGB.z) / delta;
169 | } else if (RGB.y == max) {
170 | HSV.x = 2.0f + (RGB.z - RGB.x) / delta;
171 | } else {
172 | HSV.x = 4.0f + (RGB.x - RGB.y) / delta;
173 | }
174 | HSV.x *= 1.0f / 6.0f;
175 | if (HSV.x < 0.0f)
176 | HSV.x += 1.0f;
177 | return HSV;
178 | } //Convert to HSV
179 |
180 | __DEVICE__ float3 HSV_to_RGB(float3 HSV) {
181 | float3 RGB;
182 | if (HSV.y == 0.0f) {
183 | RGB.x = RGB.y = RGB.z = HSV.z;
184 | } else {
185 | HSV.x *= 6.0f;
186 | int i = floor(HSV.x);
187 | float f = HSV.x - i;
188 | i = (i >= 0) ? (i % 6) : (i % 6) + 6;
189 | float p = HSV.z * (1.0f - HSV.y);
190 | float q = HSV.z * (1.0f - HSV.y * f);
191 | float t = HSV.z * (1.0f - HSV.y * (1.0f - f));
192 | RGB.x = i == 0 ? HSV.z : i == 1 ? q : i == 2 ? p : i == 3 ? p : i == 4 ? t : HSV.z;
193 | RGB.y = i == 0 ? t : i == 1 ? HSV.z : i == 2 ? HSV.z : i == 3 ? q : i == 4 ? p : p;
194 | RGB.z = i == 0 ? p : i == 1 ? p : i == 2 ? t : i == 3 ? HSV.z : i == 4 ? HSV.z : q;
195 | }
196 | return RGB;
197 | } //Convert from HSV to RGB
198 |
199 |
200 |
201 |
202 | __DEVICE__ float3 ColorModel(float3 in, int colorModel, bool direction) {
203 |
204 | float3 out;
205 | out = in;
206 |
207 | //==============================
208 | //color model convert functions
209 | //===============================
210 |
211 | if (colorModel == 0 && direction == 1) {out = RGBtoCHEN(out);}
212 | if (colorModel == 0 && direction == 0) {out = CHENtoRGB(out);}
213 |
214 | if (colorModel == 1 && direction == 1) {out = RGB_to_HSV(out);}
215 | if (colorModel == 1 && direction == 0) {out = HSV_to_RGB(out);}
216 | if (colorModel == 2&& direction == 1) {out = rgb_to_reuleaux(out);}
217 | if (colorModel == 2&& direction == 0) {out = reuleaux_to_rgb(out);}
218 | if (colorModel == 3&& direction == 1) {out = rgb_to_cylindrical(out);}
219 | if (colorModel == 3&& direction == 0) {out = cylindrical_to_rgb(out);}
220 |
221 | //else { out = make_float3(1,0,0);} //red on error
222 |
223 | return out;
224 |
225 | }
226 |
227 |
228 |
229 | DEFINE_UI_PARAMS(RED, Red 🟥, DCTLUI_SLIDER_FLOAT, 0.0, -1.0, 1.0, 0.001)
230 | DEFINE_UI_PARAMS(SKIN, Skin 👩🏻🦲, DCTLUI_SLIDER_FLOAT, 0.0, -.5, .5, 0.001)
231 | DEFINE_UI_PARAMS(YEL, Yellow 🟨, DCTLUI_SLIDER_FLOAT, 0.0, -1.0, 1.0, 0.001)
232 | DEFINE_UI_PARAMS(GRN, Green 🟩, DCTLUI_SLIDER_FLOAT, 0.0, -1.0, 1.0, 0.001)
233 | DEFINE_UI_PARAMS(CYN, Cyan ⬜️, DCTLUI_SLIDER_FLOAT, 0.0, -1.0, 1.0, 0.001)
234 | DEFINE_UI_PARAMS(BLU, Blue 🟦, DCTLUI_SLIDER_FLOAT, 0.0, -1.0, 1.0, 0.001)
235 | DEFINE_UI_PARAMS(MAG, Magenta 🟪, DCTLUI_SLIDER_FLOAT, 0.0, -1.0, 1.0, 0.001)
236 |
237 | DEFINE_UI_PARAMS(bypass, 🚫 Bypass, DCTLUI_CHECK_BOX, 0)
238 |
239 | DEFINE_UI_PARAMS(Preservation, Preservation model, DCTLUI_COMBO_BOX, 1, {rL,hsvSrL ,rSL, hsvSL, cylinSL, cylinLhsvS,none}, {Reuleaux L,HSV S Reuleaux L, Reuleaux S+L, HSV S+L, Cylindrical S+L,Cylindrical L HSV S, None})
240 |
241 |
242 |
243 |
244 |
245 | __DEVICE__ float3 transform(int p_Width, int p_Height, int p_X, int p_Y, float p_R, float p_G, float p_B) {
246 |
247 | float3 rgb;
248 |
249 | int mixback;
250 | int color_model;
251 |
252 | //numbers below are based on the folowing order
253 | //mixback:0 none, 1 sat, 2 luma, 3 both
254 | //color_model: 0 Chen, 1 HSV, 2 Reuleaux, 3 Cylindrical
255 |
256 | if (Preservation == 0) {mixback = 2; color_model = 2;}
257 | if (Preservation == 1) {mixback = 2; color_model = 2;}
258 | if (Preservation == 2) {mixback = 3; color_model = 2;}
259 | if (Preservation == 3) {mixback = 3; color_model = 1;}
260 | if (Preservation == 4) {mixback = 3; color_model = 3;}
261 | if (Preservation == 5) {mixback = 3; color_model = 3;}
262 | if (Preservation == 6) {mixback = 0; color_model = 2;}
263 |
264 |
265 | float3 in_rgb = make_float3(p_R, p_G, p_B);
266 | float3 HSV_sat_3 = ColorModel(in_rgb,1,1);
267 | float HSV_sat = HSV_sat_3.y;
268 |
269 | //bypass all check box
270 | if (bypass) {return in_rgb;}
271 |
272 |
273 | //start the code here
274 | //--------------------
275 |
276 | //float BLK_RGB = 0;
277 | //float WHT_RGB = 1;
278 |
279 | typedef struct {
280 | float r_hue,r_sat,r_val;
281 | float g_hue,g_sat,g_val;
282 | float b_hue,b_sat,b_val;
283 | float c_hue,c_sat,c_val;
284 | float m_hue,m_sat,m_val;
285 | float y_hue,y_sat,y_val;
286 |
287 | } params_t;
288 |
289 | params_t tetraP;
290 |
291 | // setup the tetra hsv parameters to only modify hues
292 | tetraP.r_hue = RED;
293 | tetraP.r_sat = _fminf(0,tetraP.r_hue);
294 | tetraP.r_val = 0;
295 | tetraP.g_hue = GRN;
296 | tetraP.g_sat = _fminf(0,tetraP.g_hue);
297 | tetraP.g_val = 0;
298 | tetraP.b_hue = BLU;
299 | tetraP.b_sat = _fminf(0,tetraP.b_hue);
300 | tetraP.b_val = 0;
301 | tetraP.c_hue = CYN;
302 | tetraP.c_sat = tetraP.c_hue>0 ? tetraP.c_hue*-1 : 0;
303 | tetraP.c_val = tetraP.c_hue>0 ? tetraP.c_hue*-1 : 0;
304 | tetraP.m_hue = MAG;
305 | tetraP.m_sat = tetraP.m_hue>0 ? tetraP.m_hue*-1 : 0;
306 | tetraP.m_val = tetraP.m_hue>0 ? tetraP.m_hue*-1 : 0;
307 | tetraP.y_hue = YEL;
308 | tetraP.y_sat = tetraP.y_hue>0 ? tetraP.y_hue*-1 : 0;
309 | tetraP.y_val = tetraP.y_hue>0 ? tetraP.y_hue*-1 : 0;
310 |
311 | // implementation of the tetra HSV
312 |
313 | float RED_HUE = tetraP.r_val + 1.0f;
314 | float RED_SAT = tetraP.r_val - tetraP.r_sat;
315 | float RED_VAL = tetraP.r_val + tetraP.r_hue - tetraP.r_sat;
316 |
317 | float GRN_HUE = tetraP.g_val - tetraP.g_sat;
318 | float GRN_SAT = tetraP.g_val + 1.0f;
319 | float GRN_VAL = tetraP.g_val + tetraP.g_hue - tetraP.g_sat;
320 |
321 | float BLU_HUE = tetraP.b_val + tetraP.b_hue - tetraP.b_sat;
322 | float BLU_SAT = tetraP.b_val - tetraP.b_sat;
323 | float BLU_VAL = tetraP.b_val + 1.0f;
324 |
325 | float CYN_HUE = tetraP.c_val - tetraP.c_sat;
326 | float CYN_SAT = tetraP.c_val + 1.0f + tetraP.c_hue;
327 | float CYN_VAL = tetraP.c_val + 1.0f;
328 |
329 | float MAG_HUE = tetraP.m_val + 1.0f;
330 | float MAG_SAT = tetraP.m_val - tetraP.m_sat;
331 | float MAG_VAL = tetraP.m_val + 1.0f + tetraP.m_hue;
332 |
333 | float YEL_HUE = tetraP.y_val + 1.0f + tetraP.y_hue;
334 | float YEL_SAT = tetraP.y_val + 1.0f;
335 | float YEL_VAL = tetraP.y_val - tetraP.y_sat;
336 |
337 | float3 blk = make_float3(0, 0, 0);
338 | float3 wht = make_float3(1, 1, 1);
339 | float3 red = make_float3(RED_HUE, RED_SAT, RED_VAL);
340 | float3 grn = make_float3(GRN_HUE, GRN_SAT, GRN_VAL);
341 | float3 blu = make_float3(BLU_HUE, BLU_SAT, BLU_VAL);
342 | float3 cyn = make_float3(CYN_HUE, CYN_SAT, CYN_VAL);
343 | float3 mag = make_float3(MAG_HUE, MAG_SAT, MAG_VAL);
344 | float3 yel = make_float3(YEL_HUE, YEL_SAT, YEL_VAL);
345 |
346 |
347 | if (p_R > p_G) {
348 | if (p_G > p_B) {
349 | rgb = p_R * (red - blk) + blk + p_G * (yel - red) + p_B * (wht - yel);
350 | } else if (p_R > p_B) {
351 | rgb = p_R * (red - blk) + blk + p_G * (wht - mag) + p_B * (mag - red);
352 | } else {
353 | rgb = p_R * (mag - blu) + p_G * (wht - mag) + p_B * (blu - blk) + blk;
354 | }
355 | } else {
356 | if (p_B > p_G) {
357 | rgb = p_R * (wht - cyn) + p_G * (cyn - blu) + p_B * (blu - blk) + blk;
358 | } else if (p_B > p_R) {
359 | rgb = p_R * (wht - cyn) + p_G * (grn - blk) + blk + p_B * (cyn - grn);
360 | } else {
361 | rgb = p_R * (yel - grn) + p_G * (grn - blk) + blk + p_B * (wht - yel);
362 | }
363 | }
364 |
365 |
366 | // transform to different color models to separate luminance and saturation for mixing it back afterwards
367 |
368 | in_rgb = ColorModel(in_rgb,color_model,1);
369 | float3 output = ColorModel(rgb, color_model,1);
370 |
371 |
372 | float mixsat= 0;
373 | float mixlum = 0;
374 | if (mixback ==1 || mixback == 3) { mixsat = 1;}
375 | if (mixback ==2 || mixback == 3) { mixlum = 1;}
376 |
377 |
378 | output.y = output.y*(1-mixsat)+in_rgb.y*mixsat;
379 | output.z = output.z*(1-mixlum)+in_rgb.z*mixlum;
380 |
381 | //transform back to rgb after mixing original saturation or luminance
382 | output = ColorModel(output, color_model,0);
383 |
384 |
385 | //a branch running in parallel to adjust the skin slider
386 |
387 | float3 skin;
388 |
389 | in_rgb = make_float3(p_R, p_G, p_B);
390 |
391 |
392 |
393 | params_t skin_t_P = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
394 | skin_t_P.r_hue = SKIN*.6;
395 | skin_t_P.r_sat = _fminf(0,skin_t_P.r_hue);
396 | skin_t_P.y_hue = SKIN*1.1;
397 | skin_t_P.y_sat = skin_t_P.y_hue>0 ? skin_t_P.y_hue*-1 : 0;
398 | skin_t_P.y_val = skin_t_P.y_hue>0 ? skin_t_P.y_hue*-1 : 0;
399 |
400 |
401 | float s_RED_HUE = 1.0f;
402 | float s_RED_SAT = skin_t_P.r_val - skin_t_P.r_sat;
403 | float s_RED_VAL = skin_t_P.r_val + skin_t_P.r_hue - skin_t_P.r_sat;
404 |
405 |
406 | float s_YEL_HUE = skin_t_P.y_val + 1.0f + skin_t_P.y_hue;
407 | float s_YEL_SAT = skin_t_P.y_val + 1.0f;
408 | float s_YEL_VAL = skin_t_P.y_val - skin_t_P.y_sat;
409 |
410 |
411 | float3 s_red = make_float3(s_RED_HUE, s_RED_SAT, s_RED_VAL);
412 | float3 s_grn = make_float3(0, 1, 0);
413 | float3 s_blu = make_float3(0, 0, 1);
414 | float3 s_cyn = make_float3(0, 1, 1);
415 | float3 s_mag = make_float3(1, 0, 1);
416 | float3 s_yel = make_float3(s_YEL_HUE, s_YEL_SAT, s_YEL_VAL);
417 |
418 |
419 | if (p_R > p_G) {
420 | if (p_G > p_B) {
421 | skin = p_R * (s_red - blk) + blk + p_G * (s_yel - s_red) + p_B * (wht - s_yel);
422 | } else if (p_R > p_B) {
423 | skin = p_R * (s_red - blk) + blk + p_G * (wht - s_mag) + p_B * (s_mag - s_red);
424 | } else {
425 | skin = p_R * (s_mag - s_blu) + p_G * (wht - s_mag) + p_B * (s_blu - blk) + blk;
426 | }
427 | } else {
428 | if (p_B > p_G) {
429 | skin = p_R * (wht - s_cyn) + p_G * (s_cyn - s_blu) + p_B * (s_blu - blk) + blk;
430 | } else if (p_B > p_R) {
431 | skin = p_R * (wht - s_cyn) + p_G * (s_grn - blk) + blk + p_B * (s_cyn - s_grn);
432 | } else {
433 | skin = p_R * (s_yel - s_grn) + p_G * (s_grn - blk) + blk + p_B * (wht - s_yel);
434 | }
435 | }
436 |
437 |
438 |
439 | in_rgb = ColorModel(in_rgb,color_model,1);
440 | skin = ColorModel(skin, color_model,1);
441 |
442 |
443 |
444 | if (mixback ==1 || mixback == 3) { mixsat = 1;}
445 | if (mixback ==2 || mixback == 3) { mixlum = 1;}
446 |
447 | skin.y = skin.y*(1-mixsat)+in_rgb.y*mixsat;
448 | skin.z = skin.z*(1-mixlum)+in_rgb.z*mixlum;
449 |
450 | skin = ColorModel(skin, color_model,0);
451 | in_rgb = ColorModel(in_rgb,color_model,0);
452 |
453 | //-----------------
454 | float3 out = in_rgb + (output- in_rgb) + (skin - in_rgb);
455 |
456 | if (Preservation == 1 || Preservation == 5) {
457 | out=ColorModel(out,1,1);
458 | float mixfactor = 1;
459 | HSV_sat = out.y*(1-mixfactor)+HSV_sat*mixfactor;
460 | out = make_float3(out.x,HSV_sat,out.z);
461 | out=ColorModel(out,1,0);
462 | }
463 |
464 | return out;
465 |
466 | }
467 |
--------------------------------------------------------------------------------
/ME_Color Models v1.0.dctl:
--------------------------------------------------------------------------------
1 | #line 2
2 | /*
3 | "ME_Color Models"
4 | version : 1.0.0
5 | by Moaz Elgabry
6 |
7 | This DCTL converts between a set of color models originally made for testing and experimenting purposes
8 | either in the color page of Resolve or in fusion.
9 | a basic setup is to make a sandwitch where you go into one of the color models in one nose
10 | and apply the inverse conversion in the second node and apply any adjustments inbetween.
11 |
12 | */
13 |
14 | //helper functions
15 |
16 | #define PI 3.1415926535897932384626
17 | __DEVICE__ float fmod(float x, float y) {
18 | if (x < 0) {
19 | return y + _fmod(x, y);
20 | } else {
21 | return _fmod(x, y);
22 | }
23 | }
24 |
25 |
26 | __DEVICE__ float3 cross_product(float3 a, float3 b) {
27 | float3 out = make_float3(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x);
28 | return out;
29 | }
30 |
31 | __DEVICE__ inline float pow2f(float base) {
32 | return base * base;
33 | }
34 |
35 | __DEVICE__ float dot_product(float3 a, float3 b) {
36 | return a.x * b.x + a.y * b.y + a.z * b.z;
37 | }
38 |
39 | __DEVICE__ float norm_f3(float3 a) {
40 | return _sqrtf(pow2f(a.x) + pow2f(a.y) + pow2f(a.z));
41 | }
42 |
43 | __DEVICE__ float3 unit_vec(float3 a) {
44 | float norm = norm_f3(a);
45 | float3 out = make_float3(a.x / norm, a.y / norm, a.z / norm);
46 | return out;
47 | }
48 |
49 | __DEVICE__ float3 mv_33_3(float mat[3][3], float3 v) {
50 | float3 out = make_float3(mat[0][0] * v.x + mat[0][1] * v.y + mat[0][2] * v.z,
51 | mat[1][0] * v.x + mat[1][1] * v.y + mat[1][2] * v.z,
52 | mat[2][0] * v.x + mat[2][1] * v.y + mat[2][2] * v.z);
53 | return out;
54 | }
55 |
56 | __DEVICE__ void make_rotation_mat_axis_angle(float mat[3][3], float3 axis, float angle) {
57 | // Axis assumed to be unit vector, angle assuemd to be in radians
58 | float c = _cosf(angle);
59 | float s = _sinf(angle);
60 |
61 | mat[0][0] = c + pow2f(axis.x) * (1.0 - c);
62 | mat[0][1] = axis.x * axis.y * (1.0 - c) - axis.z * s;
63 | mat[0][2] = axis.x * axis.z * (1.0 - c) + axis.y * s;
64 | mat[1][0] = axis.x * axis.y * (1.0 - c) + axis.z * s;
65 | mat[1][1] = c + pow2f(axis.y) * (1.0 - c);
66 | mat[1][2] = axis.y * axis.z * (1.0 - c) - axis.x * s;
67 | mat[2][0] = axis.z * axis.x * (1.0 - c) - axis.y * s;
68 | mat[2][1] = axis.z * axis.y * (1.0 - c) + axis.x * s;
69 | mat[2][2] = c + pow2f(axis.z) * (1.0 - c);
70 | }
71 |
72 |
73 |
74 | //color models
75 | __DEVICE__ float3 RGB_to_HSL(float3 RGB) {
76 | float R = RGB.x;
77 | float G = RGB.y;
78 | float B = RGB.z;
79 |
80 | float maxVal = max(R, max(G, B));
81 | float minVal = min(R, min(G, B));
82 | float delta = maxVal - minVal;
83 |
84 | float H = 0.0, S = 0.0, L = (maxVal + minVal) / 2.0;
85 |
86 | if (delta != 0.0) {
87 | S = (L > 0.5) ? delta / (2.0 - maxVal - minVal) : delta / (maxVal + minVal);
88 |
89 | if (maxVal == R) {
90 | H = fmod(((G - B) / delta), 6.0);
91 | } else if (maxVal == G) {
92 | H = ((B - R) / delta) + 2.0;
93 | } else {
94 | H = ((R - G) / delta) + 4.0;
95 | }
96 | H /= 6.0;
97 | }
98 |
99 | return make_float3(H, S, L);
100 | } //Convert to HSL
101 |
102 | __DEVICE__ float3 HSL_to_RGB(float3 HSL) {
103 | float3 RGB;
104 | float H = HSL.x * 6.0; // Scale hue to [0, 6]
105 | float S = HSL.y;
106 | float L = HSL.z;
107 |
108 | float C = (1 - _fabs(2 * L - 1)) * S; // Chroma
109 | float X = C * (1 - _fabs(fmod(H, 2.0) - 1.0)); // Second largest component
110 | float m = L - C / 2.0;
111 |
112 |
113 | if (H < 1.0) RGB = make_float3(C, X, 0);
114 | else if (H < 2.0) RGB = make_float3(X, C, 0);
115 | else if (H < 3.0) RGB = make_float3(0, C, X);
116 | else if (H < 4.0) RGB = make_float3(0, X, C);
117 | else if (H < 5.0) RGB = make_float3(X, 0, C);
118 | else RGB = make_float3(C, 0, X);
119 |
120 | return RGB + m; // Adjust with lightness
121 | } //Convert from HSL to RGB
122 |
123 | __DEVICE__ float3 RGB_to_HSV(float3 RGB) {
124 | float R = RGB.x, G = RGB.y, B = RGB.z;
125 | float maxVal = max(R, max(G, B));
126 | float minVal = min(R, min(G, B));
127 | float delta = maxVal - minVal;
128 |
129 | float H = 0.0, S = (maxVal == 0.0) ? 0.0 : delta / maxVal;
130 | float V = maxVal;
131 |
132 | if (delta != 0.0) {
133 | if (maxVal == R) {
134 | H = fmod(((G - B) / delta), 6.0);
135 | } else if (maxVal == G) {
136 | H = ((B - R) / delta) + 2.0;
137 | } else {
138 | H = ((R - G) / delta) + 4.0;
139 | }
140 | H /= 6.0;
141 | if (H < 0.0) H += 1.0;
142 | }
143 |
144 | return make_float3(H, S, V);
145 | } //Convert to HSV
146 |
147 | __DEVICE__ float3 HSV_to_RGB(float3 HSV) {
148 | float H = HSV.x * 6.0; // Scale hue to [0, 6]
149 | float S = HSV.y;
150 | float V = HSV.z;
151 |
152 | float C = V * S; // Chroma
153 | float X = C * (1.0 - _fabs(fmod(H, 2.0) - 1.0)); // Second largest component
154 | float m = V - C;
155 |
156 | float3 RGB;
157 | if (H < 1.0) RGB = make_float3(C, X, 0);
158 | else if (H < 2.0) RGB = make_float3(X, C, 0);
159 | else if (H < 3.0) RGB = make_float3(0, C, X);
160 | else if (H < 4.0) RGB = make_float3(0, X, C);
161 | else if (H < 5.0) RGB = make_float3(X, 0, C);
162 | else RGB = make_float3(C, 0, X);
163 |
164 | return RGB + m;
165 | } //Convert from HSV to RGB
166 |
167 | __DEVICE__ float3 rgb_to_cone(float3 rgb) {
168 | const float pi= 3.14159265359f;
169 | const float rtr = rgb.x * 0.81649658f + rgb.y * -0.40824829f + rgb.z * -0.40824829f;
170 | const float rtg = rgb.x * 0.0f + rgb.y * 0.70710678f + rgb.z * -0.70710678f;
171 | const float rtb = rgb.x * 0.57735027f + rgb.y * 0.57735027f + rgb.z * 0.57735027f;
172 |
173 | const float art = _atan2f(rtg, rtr);
174 |
175 | const float sphr = _sqrtf(rtr*rtr + rtg*rtg + rtb*rtb);
176 | const float spht = art < 0.0f ? art + 2.0f * 3.141592653589f : art;
177 | const float sphp = _atan2f(_sqrtf(rtr*rtr + rtg*rtg), rtb);
178 |
179 | //This is to modify the lum component which is the main reason why the saturation component has a different behavior
180 | const float huecoef1= 1.0f/(2.0f-(0.78539816f/0.61547971f));
181 | const float huecoef2 = 2.0f*sphp*_sinf((2.0f*pi/3.0f)-_fmod(spht,(pi/3.0f)))/1.7320508075688f;
182 | const float huemag =((_acosf(_cosf(3.0f*spht+pi)))/(pi*huecoef1)+(((0.78539816f/0.61547971f))-1.0f))*huecoef2;
183 | const float satmag = _sinf(huemag+0.61547971f);
184 |
185 |
186 |
187 | return make_float3(
188 | sphr*satmag,
189 | spht * 0.15915494309189535f,
190 | sphp * 1.0467733744265997f
191 | );
192 | } //Convert to cone cordinates by Juan Pablo Zambrano
193 |
194 | __DEVICE__ float3 cone_to_rgb(float3 sph) {
195 |
196 | const float pi= 3.14159265359f;
197 | sph.y *= 6.283185307179586f;
198 | sph.z *= 0.9553166181245093f;
199 | const float huecoef1= 1.0f/(2.0f-(0.78539816f/0.61547971f));
200 | const float huecoef2 = 2.0f*sph.z*_sinf((2.0f*pi/3.0f)- _fmod(sph.y,(pi/3.0f)))/1.7320508075688f;
201 | const float huemag =((_acosf(_cosf(3.0f*sph.y+pi)))/(pi*huecoef1)+(((0.78539816f/0.61547971f))-1.0f))*huecoef2;
202 | const float satmagsp = _sinf(huemag+0.61547971f);
203 | sph.x *= 1.0f/satmagsp;
204 |
205 | const float ctr = sph.x * _sinf(sph.z) * _cosf(sph.y);
206 | const float ctg = sph.x * _sinf(sph.z) * _sinf(sph.y);
207 | const float ctb = sph.x * _cosf(sph.z);
208 |
209 | return make_float3(
210 | ctr * 0.81649658f + ctg * 0.0f + ctb * 0.57735027f,
211 | ctr * -0.40824829f + ctg * 0.70710678f + ctb * 0.57735027f,
212 | ctr * -0.40824829f + ctg * -0.70710678f + ctb * 0.57735027f
213 | );
214 | } // convert from cone to RGB
215 |
216 |
217 | __DEVICE__ float3 rgb_to_spherical(float3 rgb) {
218 | const float rtr = rgb.x * 0.81649658f + rgb.y * -0.40824829f + rgb.z * -0.40824829f;
219 | const float rtg = rgb.x * 0.0f + rgb.y * 0.70710678f + rgb.z * -0.70710678f;
220 | const float rtb = rgb.x * 0.57735027f + rgb.y * 0.57735027f + rgb.z * 0.57735027f;
221 |
222 | const float art = _atan2f(rtg, rtr);
223 |
224 | const float sphr = _sqrtf(rtr*rtr + rtg*rtg + rtb*rtb);
225 | const float spht = art < 0.0f ? art + 2.0f * 3.141592653589f : art;
226 | const float sphp = _atan2f(_sqrtf(rtr*rtr + rtg*rtg), rtb);
227 |
228 | return make_float3(
229 | sphr * 0.5773502691896258f,
230 | spht * 0.15915494309189535f,
231 | sphp * 1.0467733744265997f
232 | );
233 | }
234 |
235 |
236 | __DEVICE__ float3 spherical_to_rgb(float3 sph) {
237 | sph.x *= 1.7320508075688772f;
238 | sph.y *= 6.283185307179586f;
239 | sph.z *= 0.9553166181245093f;
240 |
241 | const float ctr = sph.x * _sinf(sph.z) * _cosf(sph.y);
242 | const float ctg = sph.x * _sinf(sph.z) * _sinf(sph.y);
243 | const float ctb = sph.x * _cosf(sph.z);
244 |
245 | return make_float3(
246 | ctr * 0.81649658f + ctg * 0.0f + ctb * 0.57735027f,
247 | ctr * -0.40824829f + ctg * 0.70710678f + ctb * 0.57735027f,
248 | ctr * -0.40824829f + ctg * -0.70710678f + ctb * 0.57735027f
249 | );
250 | }
251 |
252 | __DEVICE__ float3 RGBtoCHEN(float3 in) {
253 | float r = in.x;
254 | float g = in.y;
255 | float b = in.z;
256 |
257 | float h;
258 | float c;
259 | float l;
260 |
261 | const float rtr = r * 0.81649658f + g * -0.40824829f + b * -0.40824829f;
262 | const float rtg = r * 0.0f + g * 0.70710678f + b * -0.70710678f;
263 | const float rtb = r * 0.57735027f + g * 0.57735027f + b * 0.57735027f;
264 |
265 | const float art = _atan2f(rtg, rtr);
266 |
267 | const float sphr = _sqrtf(rtr*rtr + rtg*rtg + rtb*rtb);
268 | const float spht = art < 0.0f ? art + 2.0f * 3.141592653589f : art;
269 | const float sphp = _atan2f(_sqrtf(rtr*rtr + rtg*rtg), rtb);
270 |
271 | l = sphr * 0.5773502691896258f;
272 | h = spht * 0.15915494309189535f;
273 | c = sphp * 1.0467733744265997f;
274 |
275 | return make_float3(h, c, l);
276 | } //by Kaur Hendrikson
277 |
278 | __DEVICE__ float3 CHENtoRGB(float3 in) {
279 | float h = in.x * 6.283185307179586f;
280 | float c = in.y * 0.9553166181245093f;
281 | float l = in.z * 1.7320508075688772f;
282 |
283 | float r = 0;
284 | float g = 0;
285 | float b = 0;
286 |
287 | const float ctr = l * _sinf(c) * _cosf(h);
288 | const float ctg = l * _sinf(c) * _sinf(h);
289 | const float ctb = l * _cosf(c);
290 |
291 | r = ctr * 0.81649658f + ctg * 0.0f + ctb * 0.57735027f;
292 | g = ctr * -0.40824829f + ctg * 0.70710678f + ctb * 0.57735027f;
293 | b = ctr * -0.40824829f + ctg * -0.70710678f + ctb * 0.57735027f;
294 |
295 | return make_float3(r, g, b);
296 | } //by Kaur Hendrikson
297 |
298 |
299 |
300 | __DEVICE__ float3 rgb_to_reuleaux(float3 rgb) {
301 | #define PI 3.1415926535897932384626
302 |
303 | float3 NORM_MULTS = make_float3(2.0f * PI, _sqrtf(2.0f), 1.0f);
304 | float3 rot = { _sqrtf(2.0f) / 6.0f * (2.0f * rgb.x - rgb.y - rgb.z),
305 | (rgb.y - rgb.z) / _sqrtf(6.0f),
306 | (rgb.x + rgb.y + rgb.z) / 3.0f};
307 | float3 rlx = { PI - _atan2f(rot.y, -rot.x),
308 | rot.z == 0.0f ? 0.0f : _hypotf(rot.x, rot.y) / rot.z,
309 | _fmaxf(rgb.x, _fmaxf(rgb.y, rgb.z))};
310 | return rlx / NORM_MULTS;
311 | }
312 |
313 | __DEVICE__ float3 reuleaux_to_rgb(float3 rlx) {
314 | #define PI 3.1415926535897932384626
315 | float3 NORM_MULTS = make_float3(2.0f * PI, _sqrtf(2.0f), 1.0f);
316 | rlx *= NORM_MULTS;
317 | float m = NORM_MULTS.y * _fmaxf(_cosf(rlx.x), _fmaxf(_cosf(rlx.x + NORM_MULTS.x / 3.0f), _cosf(rlx.x - NORM_MULTS.x / 3.0f))) + 1.0f/rlx.y;
318 | float3 ocs = { rlx.z * _cosf(rlx.x) / m,
319 | rlx.z * _sinf(rlx.x) / m,
320 | rlx.z};
321 | float3 rgb = { ocs.z - _sqrtf(3.0f / 2.0f) * _fmaxf(_fabs(ocs.y) - _sqrtf(3.0f) * ocs.x, 0.0f),
322 | ocs.z - _sqrtf(3.0f / 2.0f) * (_fmaxf(_fabs(ocs.y), _sqrtf(3.0f) * ocs.x) - ocs.y),
323 | ocs.z - _sqrtf(3.0f / 2.0f) * (_fmaxf(_fabs(ocs.y), _sqrtf(3.0f) * ocs.x) + ocs.y)};
324 | return rgb;
325 | }
326 |
327 | // Convert HSP (Hue, Saturation, Perceived brightness) to RGB
328 | __DEVICE__ float3 HSPtoRGB(float3 hsp) {
329 | // Constants for the HSP-RGB conversion
330 | const float Pr = 0.299f;
331 | const float Pg = 0.587f;
332 | const float Pb = 0.114f;
333 | float H = hsp.x;
334 | float S = hsp.y;
335 | float P = hsp.z;
336 |
337 | float3 rgb;
338 | float minOverMax = 1.0f - S;
339 | float part;
340 |
341 | if (minOverMax > 0.0f) {
342 | if (H < 1.0f / 6.0f) { // R > G > B
343 | H = 6.0f * H;
344 | part = 1.0f + H * (1.0f / minOverMax - 1.0f);
345 | rgb.z = P / sqrtf(Pr / (minOverMax * minOverMax) + Pg * part * part + Pb);
346 | rgb.x = rgb.z / minOverMax;
347 | rgb.y = rgb.z + H * (rgb.x - rgb.z);
348 | } else if (H < 2.0f / 6.0f) { // G > R > B
349 | H = 6.0f * (2.0f / 6.0f - H);
350 | part = 1.0f + H * (1.0f / minOverMax - 1.0f);
351 | rgb.z = P / sqrtf(Pg / (minOverMax * minOverMax) + Pr * part * part + Pb);
352 | rgb.y = rgb.z / minOverMax;
353 | rgb.x = rgb.z + H * (rgb.y - rgb.z);
354 | } else if (H < 3.0f / 6.0f) { // G > B > R
355 | H = 6.0f * (H - 2.0f / 6.0f);
356 | part = 1.0f + H * (1.0f / minOverMax - 1.0f);
357 | rgb.x = P / sqrtf(Pg / (minOverMax * minOverMax) + Pb * part * part + Pr);
358 | rgb.y = rgb.x / minOverMax;
359 | rgb.z = rgb.x + H * (rgb.y - rgb.x);
360 | } else if (H < 4.0f / 6.0f) { // B > G > R
361 | H = 6.0f * (4.0f / 6.0f - H);
362 | part = 1.0f + H * (1.0f / minOverMax - 1.0f);
363 | rgb.x = P / sqrtf(Pb / (minOverMax * minOverMax) + Pg * part * part + Pr);
364 | rgb.z = rgb.x / minOverMax;
365 | rgb.y = rgb.x + H * (rgb.z - rgb.x);
366 | } else if (H < 5.0f / 6.0f) { // B > R > G
367 | H = 6.0f * (H - 4.0f / 6.0f);
368 | part = 1.0f + H * (1.0f / minOverMax - 1.0f);
369 | rgb.y = P / sqrtf(Pb / (minOverMax * minOverMax) + Pr * part * part + Pg);
370 | rgb.z = rgb.y / minOverMax;
371 | rgb.x = rgb.y + H * (rgb.z - rgb.y);
372 | } else { // R > B > G
373 | H = 6.0f * (6.0f / 6.0f - H);
374 | part = 1.0f + H * (1.0f / minOverMax - 1.0f);
375 | rgb.y = P / sqrtf(Pr / (minOverMax * minOverMax) + Pb * part * part + Pg);
376 | rgb.x = rgb.y / minOverMax;
377 | rgb.z = rgb.y + H * (rgb.x - rgb.y);
378 | }
379 | } else {
380 | // Handle grayscale case when minOverMax == 0
381 | if (H < 1.0f / 6.0f) { // R > G > B
382 | H = 6.0f * H;
383 | rgb.x = sqrtf(P * P / (Pr + Pg * H * H));
384 | rgb.y = rgb.x * H;
385 | rgb.z = 0.0f;
386 | } else if (H < 2.0f / 6.0f) { // G > R > B
387 | H = 6.0f * (2.0f / 6.0f - H);
388 | rgb.y = sqrtf(P * P / (Pg + Pr * H * H));
389 | rgb.x = rgb.y * H;
390 | rgb.z = 0.0f;
391 | } else if (H < 3.0f / 6.0f) { // G > B > R
392 | H = 6.0f * (H - 2.0f / 6.0f);
393 | rgb.y = sqrtf(P * P / (Pg + Pb * H * H));
394 | rgb.z = rgb.y * H;
395 | rgb.x = 0.0f;
396 | } else if (H < 4.0f / 6.0f) { // B > G > R
397 | H = 6.0f * (4.0f / 6.0f - H);
398 | rgb.z = sqrtf(P * P / (Pb + Pg * H * H));
399 | rgb.y = rgb.z * H;
400 | rgb.x = 0.0f;
401 | } else if (H < 5.0f / 6.0f) { // B > R > G
402 | H = 6.0f * (H - 4.0f / 6.0f);
403 | rgb.z = sqrtf(P * P / (Pb + Pr * H * H));
404 | rgb.x = rgb.z * H;
405 | rgb.y = 0.0f;
406 | } else { // R > B > G
407 | H = 6.0f * (6.0f / 6.0f - H);
408 | rgb.x = sqrtf(P * P / (Pr + Pb * H * H));
409 | rgb.z = rgb.x * H;
410 | rgb.y = 0.0f;
411 | }
412 | }
413 |
414 | return rgb;
415 | }
416 |
417 | // Convert RGB to HSP (Perceived Brightness, Hue, Saturation)
418 | __DEVICE__ float3 RGBtoHSP(float3 rgb) {
419 | // Constants for the HSP-RGB conversion
420 | const float Pr = 0.299f;
421 | const float Pg = 0.587f;
422 | const float Pb = 0.114f;
423 | float R = rgb.x;
424 | float G = rgb.y;
425 | float B = rgb.z;
426 |
427 | float3 hsp;
428 | float P = sqrtf(R * R * Pr + G * G * Pg + B * B * Pb); // Perceived brightness
429 | hsp.z = P;
430 |
431 | // Calculate Hue and Saturation
432 | if (R == G && R == B) { // Grayscale, no hue or saturation
433 | hsp.x = 0.0f; // Hue
434 | hsp.y = 0.0f; // Saturation
435 | return hsp;
436 | }
437 |
438 | if (R >= G && R >= B) { // R is largest
439 | if (B >= G) {
440 | hsp.x = 1.0f - (B - G) / (6.0f * (R - G)); // Hue
441 | hsp.y = 1.0f - G / R; // Saturation
442 | } else {
443 | hsp.x = (G - B) / (6.0f * (R - B)); // Hue
444 | hsp.y = 1.0f - B / R; // Saturation
445 | }
446 | } else if (G >= R && G >= B) { // G is largest
447 | if (R >= B) {
448 | hsp.x = (2.0f / 6.0f) - (R - B) / (6.0f * (G - B)); // Hue
449 | hsp.y = 1.0f - B / G; // Saturation
450 | } else {
451 | hsp.x = (2.0f / 6.0f) + (B - R) / (6.0f * (G - R)); // Hue
452 | hsp.y = 1.0f - R / G; // Saturation
453 | }
454 | } else { // B is largest
455 | if (G >= R) {
456 | hsp.x = (4.0f / 6.0f) - (G - R) / (6.0f * (B - R)); // Hue
457 | hsp.y = 1.0f - R / B; // Saturation
458 | } else {
459 | hsp.x = (4.0f / 6.0f) + (R - G) / (6.0f * (B - G)); // Hue
460 | hsp.y = 1.0f - G / B; // Saturation
461 | }
462 | }
463 |
464 | return hsp;
465 | }
466 | __DEVICE__ float3 cylindrical_to_rgb(float3 hsv) {
467 | // Adapted from Juan Pablo Zambrano's code
468 | float3 lsh = make_float3(hsv.z, hsv.y * 3.0, fmod(hsv.x, 1.0) * 2.0 * PI);
469 |
470 | float ctr = lsh.x * lsh.y * _cosf(lsh.z);
471 | float ctg = lsh.x;
472 | float ctb = lsh.x * lsh.y * _sinf(lsh.z);
473 | float3 c = make_float3(ctr, ctg, ctb);
474 |
475 | float mat[3][3] = {
476 | {2.0 / 3.0, 1.0, 0.0},
477 | {-1.0 / 3.0, 1.0, _sqrtf(3.0) / 3.0},
478 | {-1.0 / 3.0, 1.0, -_sqrtf(3.0) / 3.0},
479 | };
480 |
481 | return mv_33_3(mat, c);
482 | }
483 |
484 | __DEVICE__ float3 rgb_to_cylindrical(float3 x) {
485 |
486 | // Matrix aligns and scales achromatic white (1, 1, 1) with (0, 1, 0)
487 | // Also rotates input (1, 0, 0) above the red axis and ensures that
488 | // (1, 0, 0) input ends up having a red channel code value of (1).
489 | float mat[3][3] = {
490 | {1.0, -1.0 / 2.0, -1.0 / 2.0},
491 | {1.0 / 3.0, 1.0 / 3.0, 1.0 / 3.0},
492 | {0.0, _sqrtf(3.0) / 2.0, -_sqrtf(3.0) / 2.0},
493 | };
494 |
495 | float3 rotated_color = mv_33_3(mat, x);
496 | float l = rotated_color.y;
497 | float3 hsl = make_float3(0.0, 0.0, 0.0);
498 |
499 | float3 normalized_color = rotated_color / l;
500 | if (l == 0.0) {
501 | hsl = make_float3(0.0, 0.0, l);
502 | } else {
503 | float theta = _atan2f(normalized_color.z, normalized_color.x);
504 | hsl.x = fmod(theta, 2.0 * PI) / (2.0 * PI);
505 | hsl.y = _hypotf(normalized_color.x, normalized_color.z) / 3.0;
506 | hsl.z = l;
507 | }
508 | return hsl;
509 | }
510 |
511 |
512 |
513 |
514 | DEFINE_UI_PARAMS(p_model, Color model, DCTLUI_COMBO_BOX, 0, { hsl, hsv, cone, spherical,Chen,Reul,hsp, cylindrical}, { HSL, HSV, Cone, Spherical,Chen,Reuleaux,HSP,Cylindrical})
515 | DEFINE_UI_PARAMS(p_inverse, Inverse, DCTLUI_CHECK_BOX, 0)
516 |
517 | //DEFINE_UI_PARAMS(p_dir, Direction, DCTLUI_COMBO_BOX, 0, { p_forward, p_inverse }, { Forward, Inverse })
518 |
519 | __DEVICE__ float3 transform(int p_Width, int p_Height, int p_X, int p_Y, float p_R, float p_G, float p_B) {
520 | float3 RGB = make_float3(p_R, p_G, p_B);
521 | float3 output;
522 | //float PI = 3.1415926535897932384626;
523 | if (p_model == 0) { if (p_inverse == 0) {output = RGB_to_HSL(RGB);} else { output = HSL_to_RGB(RGB);}}
524 | else if (p_model == 1) { if (p_inverse == 0) {output = RGB_to_HSV(RGB);} else { output = HSV_to_RGB(RGB);}}
525 | else if (p_model == 2) { if (p_inverse == 0) {output = rgb_to_cone(RGB);} else { output = cone_to_rgb(RGB);}}
526 | else if (p_model == 3) { if (p_inverse == 0) {output = rgb_to_spherical(RGB);} else { output = spherical_to_rgb(RGB);}}
527 | else if (p_model == 4) { if (p_inverse == 0) {output = RGBtoCHEN(RGB);} else { output = CHENtoRGB(RGB);}}
528 | else if (p_model == 5) { if (p_inverse == 0) {output = rgb_to_reuleaux(RGB);} else { output = reuleaux_to_rgb(RGB);}}
529 | else if (p_model == 6) { if (p_inverse == 0) {output = RGBtoHSP(RGB);} else { output = HSPtoRGB(RGB);}}
530 | else if (p_model == 7) { if (p_inverse == 0) {output = rgb_to_cylindrical(RGB);} else { output = cylindrical_to_rgb(RGB);}}
531 |
532 | return output;
533 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 | Preamble
9 |
10 | The GNU General Public License is a free, copyleft license for
11 | software and other kinds of works.
12 |
13 | The licenses for most software and other practical works are designed
14 | to take away your freedom to share and change the works. By contrast,
15 | the GNU General Public License is intended to guarantee your freedom to
16 | share and change all versions of a program--to make sure it remains free
17 | software for all its users. We, the Free Software Foundation, use the
18 | GNU General Public License for most of our software; it applies also to
19 | any other work released this way by its authors. You can apply it to
20 | your programs, too.
21 |
22 | When we speak of free software, we are referring to freedom, not
23 | price. Our General Public Licenses are designed to make sure that you
24 | have the freedom to distribute copies of free software (and charge for
25 | them if you wish), that you receive source code or can get it if you
26 | want it, that you can change the software or use pieces of it in new
27 | free programs, and that you know you can do these things.
28 |
29 | To protect your rights, we need to prevent others from denying you
30 | these rights or asking you to surrender the rights. Therefore, you have
31 | certain responsibilities if you distribute copies of the software, or if
32 | you modify it: responsibilities to respect the freedom of others.
33 |
34 | For example, if you distribute copies of such a program, whether
35 | gratis or for a fee, you must pass on to the recipients the same
36 | freedoms that you received. You must make sure that they, too, receive
37 | or can get the source code. And you must show them these terms so they
38 | know their rights.
39 |
40 | Developers that use the GNU GPL protect your rights with two steps:
41 | (1) assert copyright on the software, and (2) offer you this License
42 | giving you legal permission to copy, distribute and/or modify it.
43 |
44 | For the developers' and authors' protection, the GPL clearly explains
45 | that there is no warranty for this free software. For both users' and
46 | authors' sake, the GPL requires that modified versions be marked as
47 | changed, so that their problems will not be attributed erroneously to
48 | authors of previous versions.
49 |
50 | Some devices are designed to deny users access to install or run
51 | modified versions of the software inside them, although the manufacturer
52 | can do so. This is fundamentally incompatible with the aim of
53 | protecting users' freedom to change the software. The systematic
54 | pattern of such abuse occurs in the area of products for individuals to
55 | use, which is precisely where it is most unacceptable. Therefore, we
56 | have designed this version of the GPL to prohibit the practice for those
57 | products. If such problems arise substantially in other domains, we
58 | stand ready to extend this provision to those domains in future versions
59 | of the GPL, as needed to protect the freedom of users.
60 |
61 | Finally, every program is threatened constantly by software patents.
62 | States should not allow patents to restrict development and use of
63 | software on general-purpose computers, but in those that do, we wish to
64 | avoid the special danger that patents applied to a free program could
65 | make it effectively proprietary. To prevent this, the GPL assures that
66 | patents cannot be used to render the program non-free.
67 |
68 | The precise terms and conditions for copying, distribution and
69 | modification follow.
70 |
71 | TERMS AND CONDITIONS
72 |
73 | 0. Definitions.
74 |
75 | "This License" refers to version 3 of the GNU General Public License.
76 |
77 | "Copyright" also means copyright-like laws that apply to other kinds of
78 | works, such as semiconductor masks.
79 |
80 | "The Program" refers to any copyrightable work licensed under this
81 | License. Each licensee is addressed as "you". "Licensees" and
82 | "recipients" may be individuals or organizations.
83 |
84 | To "modify" a work means to copy from or adapt all or part of the work
85 | in a fashion requiring copyright permission, other than the making of an
86 | exact copy. The resulting work is called a "modified version" of the
87 | earlier work or a work "based on" the earlier work.
88 |
89 | A "covered work" means either the unmodified Program or a work based
90 | on the Program.
91 |
92 | To "propagate" a work means to do anything with it that, without
93 | permission, would make you directly or secondarily liable for
94 | infringement under applicable copyright law, except executing it on a
95 | computer or modifying a private copy. Propagation includes copying,
96 | distribution (with or without modification), making available to the
97 | public, and in some countries other activities as well.
98 |
99 | To "convey" a work means any kind of propagation that enables other
100 | parties to make or receive copies. Mere interaction with a user through
101 | a computer network, with no transfer of a copy, is not conveying.
102 |
103 | An interactive user interface displays "Appropriate Legal Notices"
104 | to the extent that it includes a convenient and prominently visible
105 | feature that (1) displays an appropriate copyright notice, and (2)
106 | tells the user that there is no warranty for the work (except to the
107 | extent that warranties are provided), that licensees may convey the
108 | work under this License, and how to view a copy of this License. If
109 | the interface presents a list of user commands or options, such as a
110 | menu, a prominent item in the list meets this criterion.
111 |
112 | 1. Source Code.
113 |
114 | The "source code" for a work means the preferred form of the work
115 | for making modifications to it. "Object code" means any non-source
116 | form of a work.
117 |
118 | A "Standard Interface" means an interface that either is an official
119 | standard defined by a recognized standards body, or, in the case of
120 | interfaces specified for a particular programming language, one that
121 | is widely used among developers working in that language.
122 |
123 | The "System Libraries" of an executable work include anything, other
124 | than the work as a whole, that (a) is included in the normal form of
125 | packaging a Major Component, but which is not part of that Major
126 | Component, and (b) serves only to enable use of the work with that
127 | Major Component, or to implement a Standard Interface for which an
128 | implementation is available to the public in source code form. A
129 | "Major Component", in this context, means a major essential component
130 | (kernel, window system, and so on) of the specific operating system
131 | (if any) on which the executable work runs, or a compiler used to
132 | produce the work, or an object code interpreter used to run it.
133 |
134 | The "Corresponding Source" for a work in object code form means all
135 | the source code needed to generate, install, and (for an executable
136 | work) run the object code and to modify the work, including scripts to
137 | control those activities. However, it does not include the work's
138 | System Libraries, or general-purpose tools or generally available free
139 | programs which are used unmodified in performing those activities but
140 | which are not part of the work. For example, Corresponding Source
141 | includes interface definition files associated with source files for
142 | the work, and the source code for shared libraries and dynamically
143 | linked subprograms that the work is specifically designed to require,
144 | such as by intimate data communication or control flow between those
145 | subprograms and other parts of the work.
146 |
147 | The Corresponding Source need not include anything that users
148 | can regenerate automatically from other parts of the Corresponding
149 | Source.
150 |
151 | The Corresponding Source for a work in source code form is that
152 | same work.
153 |
154 | 2. Basic Permissions.
155 |
156 | All rights granted under this License are granted for the term of
157 | copyright on the Program, and are irrevocable provided the stated
158 | conditions are met. This License explicitly affirms your unlimited
159 | permission to run the unmodified Program. The output from running a
160 | covered work is covered by this License only if the output, given its
161 | content, constitutes a covered work. This License acknowledges your
162 | rights of fair use or other equivalent, as provided by copyright law.
163 |
164 | You may make, run and propagate covered works that you do not
165 | convey, without conditions so long as your license otherwise remains
166 | in force. You may convey covered works to others for the sole purpose
167 | of having them make modifications exclusively for you, or provide you
168 | with facilities for running those works, provided that you comply with
169 | the terms of this License in conveying all material for which you do
170 | not control copyright. Those thus making or running the covered works
171 | for you must do so exclusively on your behalf, under your direction
172 | and control, on terms that prohibit them from making any copies of
173 | your copyrighted material outside their relationship with you.
174 |
175 | Conveying under any other circumstances is permitted solely under
176 | the conditions stated below. Sublicensing is not allowed; section 10
177 | makes it unnecessary.
178 |
179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
180 |
181 | No covered work shall be deemed part of an effective technological
182 | measure under any applicable law fulfilling obligations under article
183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or
184 | similar laws prohibiting or restricting circumvention of such
185 | measures.
186 |
187 | When you convey a covered work, you waive any legal power to forbid
188 | circumvention of technological measures to the extent such circumvention
189 | is effected by exercising rights under this License with respect to
190 | the covered work, and you disclaim any intention to limit operation or
191 | modification of the work as a means of enforcing, against the work's
192 | users, your or third parties' legal rights to forbid circumvention of
193 | technological measures.
194 |
195 | 4. Conveying Verbatim Copies.
196 |
197 | You may convey verbatim copies of the Program's source code as you
198 | receive it, in any medium, provided that you conspicuously and
199 | appropriately publish on each copy an appropriate copyright notice;
200 | keep intact all notices stating that this License and any
201 | non-permissive terms added in accord with section 7 apply to the code;
202 | keep intact all notices of the absence of any warranty; and give all
203 | recipients a copy of this License along with the Program.
204 |
205 | You may charge any price or no price for each copy that you convey,
206 | and you may offer support or warranty protection for a fee.
207 |
208 | 5. Conveying Modified Source Versions.
209 |
210 | You may convey a work based on the Program, or the modifications to
211 | produce it from the Program, in the form of source code under the
212 | terms of section 4, provided that you also meet all of these conditions:
213 |
214 | a) The work must carry prominent notices stating that you modified
215 | it, and giving a relevant date.
216 |
217 | b) The work must carry prominent notices stating that it is
218 | released under this License and any conditions added under section
219 | 7. This requirement modifies the requirement in section 4 to
220 | "keep intact all notices".
221 |
222 | c) You must license the entire work, as a whole, under this
223 | License to anyone who comes into possession of a copy. This
224 | License will therefore apply, along with any applicable section 7
225 | additional terms, to the whole of the work, and all its parts,
226 | regardless of how they are packaged. This License gives no
227 | permission to license the work in any other way, but it does not
228 | invalidate such permission if you have separately received it.
229 |
230 | d) If the work has interactive user interfaces, each must display
231 | Appropriate Legal Notices; however, if the Program has interactive
232 | interfaces that do not display Appropriate Legal Notices, your
233 | work need not make them do so.
234 |
235 | A compilation of a covered work with other separate and independent
236 | works, which are not by their nature extensions of the covered work,
237 | and which are not combined with it such as to form a larger program,
238 | in or on a volume of a storage or distribution medium, is called an
239 | "aggregate" if the compilation and its resulting copyright are not
240 | used to limit the access or legal rights of the compilation's users
241 | beyond what the individual works permit. Inclusion of a covered work
242 | in an aggregate does not cause this License to apply to the other
243 | parts of the aggregate.
244 |
245 | 6. Conveying Non-Source Forms.
246 |
247 | You may convey a covered work in object code form under the terms
248 | of sections 4 and 5, provided that you also convey the
249 | machine-readable Corresponding Source under the terms of this License,
250 | in one of these ways:
251 |
252 | a) Convey the object code in, or embodied in, a physical product
253 | (including a physical distribution medium), accompanied by the
254 | Corresponding Source fixed on a durable physical medium
255 | customarily used for software interchange.
256 |
257 | b) Convey the object code in, or embodied in, a physical product
258 | (including a physical distribution medium), accompanied by a
259 | written offer, valid for at least three years and valid for as
260 | long as you offer spare parts or customer support for that product
261 | model, to give anyone who possesses the object code either (1) a
262 | copy of the Corresponding Source for all the software in the
263 | product that is covered by this License, on a durable physical
264 | medium customarily used for software interchange, for a price no
265 | more than your reasonable cost of physically performing this
266 | conveying of source, or (2) access to copy the
267 | Corresponding Source from a network server at no charge.
268 |
269 | c) Convey individual copies of the object code with a copy of the
270 | written offer to provide the Corresponding Source. This
271 | alternative is allowed only occasionally and noncommercially, and
272 | only if you received the object code with such an offer, in accord
273 | with subsection 6b.
274 |
275 | d) Convey the object code by offering access from a designated
276 | place (gratis or for a charge), and offer equivalent access to the
277 | Corresponding Source in the same way through the same place at no
278 | further charge. You need not require recipients to copy the
279 | Corresponding Source along with the object code. If the place to
280 | copy the object code is a network server, the Corresponding Source
281 | may be on a different server (operated by you or a third party)
282 | that supports equivalent copying facilities, provided you maintain
283 | clear directions next to the object code saying where to find the
284 | Corresponding Source. Regardless of what server hosts the
285 | Corresponding Source, you remain obligated to ensure that it is
286 | available for as long as needed to satisfy these requirements.
287 |
288 | e) Convey the object code using peer-to-peer transmission, provided
289 | you inform other peers where the object code and Corresponding
290 | Source of the work are being offered to the general public at no
291 | charge under subsection 6d.
292 |
293 | A separable portion of the object code, whose source code is excluded
294 | from the Corresponding Source as a System Library, need not be
295 | included in conveying the object code work.
296 |
297 | A "User Product" is either (1) a "consumer product", which means any
298 | tangible personal property which is normally used for personal, family,
299 | or household purposes, or (2) anything designed or sold for incorporation
300 | into a dwelling. In determining whether a product is a consumer product,
301 | doubtful cases shall be resolved in favor of coverage. For a particular
302 | product received by a particular user, "normally used" refers to a
303 | typical or common use of that class of product, regardless of the status
304 | of the particular user or of the way in which the particular user
305 | actually uses, or expects or is expected to use, the product. A product
306 | is a consumer product regardless of whether the product has substantial
307 | commercial, industrial or non-consumer uses, unless such uses represent
308 | the only significant mode of use of the product.
309 |
310 | "Installation Information" for a User Product means any methods,
311 | procedures, authorization keys, or other information required to install
312 | and execute modified versions of a covered work in that User Product from
313 | a modified version of its Corresponding Source. The information must
314 | suffice to ensure that the continued functioning of the modified object
315 | code is in no case prevented or interfered with solely because
316 | modification has been made.
317 |
318 | If you convey an object code work under this section in, or with, or
319 | specifically for use in, a User Product, and the conveying occurs as
320 | part of a transaction in which the right of possession and use of the
321 | User Product is transferred to the recipient in perpetuity or for a
322 | fixed term (regardless of how the transaction is characterized), the
323 | Corresponding Source conveyed under this section must be accompanied
324 | by the Installation Information. But this requirement does not apply
325 | if neither you nor any third party retains the ability to install
326 | modified object code on the User Product (for example, the work has
327 | been installed in ROM).
328 |
329 | The requirement to provide Installation Information does not include a
330 | requirement to continue to provide support service, warranty, or updates
331 | for a work that has been modified or installed by the recipient, or for
332 | the User Product in which it has been modified or installed. Access to a
333 | network may be denied when the modification itself materially and
334 | adversely affects the operation of the network or violates the rules and
335 | protocols for communication across the network.
336 |
337 | Corresponding Source conveyed, and Installation Information provided,
338 | in accord with this section must be in a format that is publicly
339 | documented (and with an implementation available to the public in
340 | source code form), and must require no special password or key for
341 | unpacking, reading or copying.
342 |
343 | 7. Additional Terms.
344 |
345 | "Additional permissions" are terms that supplement the terms of this
346 | License by making exceptions from one or more of its conditions.
347 | Additional permissions that are applicable to the entire Program shall
348 | be treated as though they were included in this License, to the extent
349 | that they are valid under applicable law. If additional permissions
350 | apply only to part of the Program, that part may be used separately
351 | under those permissions, but the entire Program remains governed by
352 | this License without regard to the additional permissions.
353 |
354 | When you convey a copy of a covered work, you may at your option
355 | remove any additional permissions from that copy, or from any part of
356 | it. (Additional permissions may be written to require their own
357 | removal in certain cases when you modify the work.) You may place
358 | additional permissions on material, added by you to a covered work,
359 | for which you have or can give appropriate copyright permission.
360 |
361 | Notwithstanding any other provision of this License, for material you
362 | add to a covered work, you may (if authorized by the copyright holders of
363 | that material) supplement the terms of this License with terms:
364 |
365 | a) Disclaiming warranty or limiting liability differently from the
366 | terms of sections 15 and 16 of this License; or
367 |
368 | b) Requiring preservation of specified reasonable legal notices or
369 | author attributions in that material or in the Appropriate Legal
370 | Notices displayed by works containing it; or
371 |
372 | c) Prohibiting misrepresentation of the origin of that material, or
373 | requiring that modified versions of such material be marked in
374 | reasonable ways as different from the original version; or
375 |
376 | d) Limiting the use for publicity purposes of names of licensors or
377 | authors of the material; or
378 |
379 | e) Declining to grant rights under trademark law for use of some
380 | trade names, trademarks, or service marks; or
381 |
382 | f) Requiring indemnification of licensors and authors of that
383 | material by anyone who conveys the material (or modified versions of
384 | it) with contractual assumptions of liability to the recipient, for
385 | any liability that these contractual assumptions directly impose on
386 | those licensors and authors.
387 |
388 | All other non-permissive additional terms are considered "further
389 | restrictions" within the meaning of section 10. If the Program as you
390 | received it, or any part of it, contains a notice stating that it is
391 | governed by this License along with a term that is a further
392 | restriction, you may remove that term. If a license document contains
393 | a further restriction but permits relicensing or conveying under this
394 | License, you may add to a covered work material governed by the terms
395 | of that license document, provided that the further restriction does
396 | not survive such relicensing or conveying.
397 |
398 | If you add terms to a covered work in accord with this section, you
399 | must place, in the relevant source files, a statement of the
400 | additional terms that apply to those files, or a notice indicating
401 | where to find the applicable terms.
402 |
403 | Additional terms, permissive or non-permissive, may be stated in the
404 | form of a separately written license, or stated as exceptions;
405 | the above requirements apply either way.
406 |
407 | 8. Termination.
408 |
409 | You may not propagate or modify a covered work except as expressly
410 | provided under this License. Any attempt otherwise to propagate or
411 | modify it is void, and will automatically terminate your rights under
412 | this License (including any patent licenses granted under the third
413 | paragraph of section 11).
414 |
415 | However, if you cease all violation of this License, then your
416 | license from a particular copyright holder is reinstated (a)
417 | provisionally, unless and until the copyright holder explicitly and
418 | finally terminates your license, and (b) permanently, if the copyright
419 | holder fails to notify you of the violation by some reasonable means
420 | prior to 60 days after the cessation.
421 |
422 | Moreover, your license from a particular copyright holder is
423 | reinstated permanently if the copyright holder notifies you of the
424 | violation by some reasonable means, this is the first time you have
425 | received notice of violation of this License (for any work) from that
426 | copyright holder, and you cure the violation prior to 30 days after
427 | your receipt of the notice.
428 |
429 | Termination of your rights under this section does not terminate the
430 | licenses of parties who have received copies or rights from you under
431 | this License. If your rights have been terminated and not permanently
432 | reinstated, you do not qualify to receive new licenses for the same
433 | material under section 10.
434 |
435 | 9. Acceptance Not Required for Having Copies.
436 |
437 | You are not required to accept this License in order to receive or
438 | run a copy of the Program. Ancillary propagation of a covered work
439 | occurring solely as a consequence of using peer-to-peer transmission
440 | to receive a copy likewise does not require acceptance. However,
441 | nothing other than this License grants you permission to propagate or
442 | modify any covered work. These actions infringe copyright if you do
443 | not accept this License. Therefore, by modifying or propagating a
444 | covered work, you indicate your acceptance of this License to do so.
445 |
446 | 10. Automatic Licensing of Downstream Recipients.
447 |
448 | Each time you convey a covered work, the recipient automatically
449 | receives a license from the original licensors, to run, modify and
450 | propagate that work, subject to this License. You are not responsible
451 | for enforcing compliance by third parties with this License.
452 |
453 | An "entity transaction" is a transaction transferring control of an
454 | organization, or substantially all assets of one, or subdividing an
455 | organization, or merging organizations. If propagation of a covered
456 | work results from an entity transaction, each party to that
457 | transaction who receives a copy of the work also receives whatever
458 | licenses to the work the party's predecessor in interest had or could
459 | give under the previous paragraph, plus a right to possession of the
460 | Corresponding Source of the work from the predecessor in interest, if
461 | the predecessor has it or can get it with reasonable efforts.
462 |
463 | You may not impose any further restrictions on the exercise of the
464 | rights granted or affirmed under this License. For example, you may
465 | not impose a license fee, royalty, or other charge for exercise of
466 | rights granted under this License, and you may not initiate litigation
467 | (including a cross-claim or counterclaim in a lawsuit) alleging that
468 | any patent claim is infringed by making, using, selling, offering for
469 | sale, or importing the Program or any portion of it.
470 |
471 | 11. Patents.
472 |
473 | A "contributor" is a copyright holder who authorizes use under this
474 | License of the Program or a work on which the Program is based. The
475 | work thus licensed is called the contributor's "contributor version".
476 |
477 | A contributor's "essential patent claims" are all patent claims
478 | owned or controlled by the contributor, whether already acquired or
479 | hereafter acquired, that would be infringed by some manner, permitted
480 | by this License, of making, using, or selling its contributor version,
481 | but do not include claims that would be infringed only as a
482 | consequence of further modification of the contributor version. For
483 | purposes of this definition, "control" includes the right to grant
484 | patent sublicenses in a manner consistent with the requirements of
485 | this License.
486 |
487 | Each contributor grants you a non-exclusive, worldwide, royalty-free
488 | patent license under the contributor's essential patent claims, to
489 | make, use, sell, offer for sale, import and otherwise run, modify and
490 | propagate the contents of its contributor version.
491 |
492 | In the following three paragraphs, a "patent license" is any express
493 | agreement or commitment, however denominated, not to enforce a patent
494 | (such as an express permission to practice a patent or covenant not to
495 | sue for patent infringement). To "grant" such a patent license to a
496 | party means to make such an agreement or commitment not to enforce a
497 | patent against the party.
498 |
499 | If you convey a covered work, knowingly relying on a patent license,
500 | and the Corresponding Source of the work is not available for anyone
501 | to copy, free of charge and under the terms of this License, through a
502 | publicly available network server or other readily accessible means,
503 | then you must either (1) cause the Corresponding Source to be so
504 | available, or (2) arrange to deprive yourself of the benefit of the
505 | patent license for this particular work, or (3) arrange, in a manner
506 | consistent with the requirements of this License, to extend the patent
507 | license to downstream recipients. "Knowingly relying" means you have
508 | actual knowledge that, but for the patent license, your conveying the
509 | covered work in a country, or your recipient's use of the covered work
510 | in a country, would infringe one or more identifiable patents in that
511 | country that you have reason to believe are valid.
512 |
513 | If, pursuant to or in connection with a single transaction or
514 | arrangement, you convey, or propagate by procuring conveyance of, a
515 | covered work, and grant a patent license to some of the parties
516 | receiving the covered work authorizing them to use, propagate, modify
517 | or convey a specific copy of the covered work, then the patent license
518 | you grant is automatically extended to all recipients of the covered
519 | work and works based on it.
520 |
521 | A patent license is "discriminatory" if it does not include within
522 | the scope of its coverage, prohibits the exercise of, or is
523 | conditioned on the non-exercise of one or more of the rights that are
524 | specifically granted under this License. You may not convey a covered
525 | work if you are a party to an arrangement with a third party that is
526 | in the business of distributing software, under which you make payment
527 | to the third party based on the extent of your activity of conveying
528 | the work, and under which the third party grants, to any of the
529 | parties who would receive the covered work from you, a discriminatory
530 | patent license (a) in connection with copies of the covered work
531 | conveyed by you (or copies made from those copies), or (b) primarily
532 | for and in connection with specific products or compilations that
533 | contain the covered work, unless you entered into that arrangement,
534 | or that patent license was granted, prior to 28 March 2007.
535 |
536 | Nothing in this License shall be construed as excluding or limiting
537 | any implied license or other defenses to infringement that may
538 | otherwise be available to you under applicable patent law.
539 |
540 | 12. No Surrender of Others' Freedom.
541 |
542 | If conditions are imposed on you (whether by court order, agreement or
543 | otherwise) that contradict the conditions of this License, they do not
544 | excuse you from the conditions of this License. If you cannot convey a
545 | covered work so as to satisfy simultaneously your obligations under this
546 | License and any other pertinent obligations, then as a consequence you may
547 | not convey it at all. For example, if you agree to terms that obligate you
548 | to collect a royalty for further conveying from those to whom you convey
549 | the Program, the only way you could satisfy both those terms and this
550 | License would be to refrain entirely from conveying the Program.
551 |
552 | 13. Use with the GNU Affero General Public License.
553 |
554 | Notwithstanding any other provision of this License, you have
555 | permission to link or combine any covered work with a work licensed
556 | under version 3 of the GNU Affero General Public License into a single
557 | combined work, and to convey the resulting work. The terms of this
558 | License will continue to apply to the part which is the covered work,
559 | but the special requirements of the GNU Affero General Public License,
560 | section 13, concerning interaction through a network will apply to the
561 | combination as such.
562 |
563 | 14. Revised Versions of this License.
564 |
565 | The Free Software Foundation may publish revised and/or new versions of
566 | the GNU General Public License from time to time. Such new versions will
567 | be similar in spirit to the present version, but may differ in detail to
568 | address new problems or concerns.
569 |
570 | Each version is given a distinguishing version number. If the
571 | Program specifies that a certain numbered version of the GNU General
572 | Public License "or any later version" applies to it, you have the
573 | option of following the terms and conditions either of that numbered
574 | version or of any later version published by the Free Software
575 | Foundation. If the Program does not specify a version number of the
576 | GNU General Public License, you may choose any version ever published
577 | by the Free Software Foundation.
578 |
579 | If the Program specifies that a proxy can decide which future
580 | versions of the GNU General Public License can be used, that proxy's
581 | public statement of acceptance of a version permanently authorizes you
582 | to choose that version for the Program.
583 |
584 | Later license versions may give you additional or different
585 | permissions. However, no additional obligations are imposed on any
586 | author or copyright holder as a result of your choosing to follow a
587 | later version.
588 |
589 | 15. Disclaimer of Warranty.
590 |
591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
599 |
600 | 16. Limitation of Liability.
601 |
602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
610 | SUCH DAMAGES.
611 |
612 | 17. Interpretation of Sections 15 and 16.
613 |
614 | If the disclaimer of warranty and limitation of liability provided
615 | above cannot be given local legal effect according to their terms,
616 | reviewing courts shall apply local law that most closely approximates
617 | an absolute waiver of all civil liability in connection with the
618 | Program, unless a warranty or assumption of liability accompanies a
619 | copy of the Program in return for a fee.
620 |
621 | END OF TERMS AND CONDITIONS
622 |
623 | How to Apply These Terms to Your New Programs
624 |
625 | If you develop a new program, and you want it to be of the greatest
626 | possible use to the public, the best way to achieve this is to make it
627 | free software which everyone can redistribute and change under these terms.
628 |
629 | To do so, attach the following notices to the program. It is safest
630 | to attach them to the start of each source file to most effectively
631 | state the exclusion of warranty; and each file should have at least
632 | the "copyright" line and a pointer to where the full notice is found.
633 |
634 |
635 | Copyright (C)
636 |
637 | This program is free software: you can redistribute it and/or modify
638 | it under the terms of the GNU General Public License as published by
639 | the Free Software Foundation, either version 3 of the License, or
640 | (at your option) any later version.
641 |
642 | This program is distributed in the hope that it will be useful,
643 | but WITHOUT ANY WARRANTY; without even the implied warranty of
644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
645 | GNU General Public License for more details.
646 |
647 | You should have received a copy of the GNU General Public License
648 | along with this program. If not, see .
649 |
650 | Also add information on how to contact you by electronic and paper mail.
651 |
652 | If the program does terminal interaction, make it output a short
653 | notice like this when it starts in an interactive mode:
654 |
655 | Copyright (C)
656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
657 | This is free software, and you are welcome to redistribute it
658 | under certain conditions; type `show c' for details.
659 |
660 | The hypothetical commands `show w' and `show c' should show the appropriate
661 | parts of the General Public License. Of course, your program's commands
662 | might be different; for a GUI interface, you would use an "about box".
663 |
664 | You should also get your employer (if you work as a programmer) or school,
665 | if any, to sign a "copyright disclaimer" for the program, if necessary.
666 | For more information on this, and how to apply and follow the GNU GPL, see
667 | .
668 |
669 | The GNU General Public License does not permit incorporating your program
670 | into proprietary programs. If your program is a subroutine library, you
671 | may consider it more useful to permit linking proprietary applications with
672 | the library. If this is what you want to do, use the GNU Lesser General
673 | Public License instead of this License. But first, please read
674 | .
675 | Explain
676 |
--------------------------------------------------------------------------------
/ME_Ratio Shaper v1.2.dctl:
--------------------------------------------------------------------------------
1 | #line 2
2 | /* ME_Ratio Shaper ver 1.2
3 | written by Moaz Elgabry, moazelgabry.com
4 | the code for some key functionalities here is thanks to Jed Smith and Thatcher Freeman is heavily used in making this tool.
5 | */
6 |
7 |
8 |
9 | //functions for Transfer function conversion
10 | __DEVICE__ float3 LinToLogC3 (float3 in) {
11 | float3 out;
12 |
13 | float cut = 0.010591;
14 | float a = 5.555556;
15 | float b = 0.052272;
16 | float c = 0.247190;
17 | float d = 0.385537;
18 | float e = 5.367655;
19 | float f = 0.092809;
20 |
21 | out.x = (in.x > cut) ? c * log10(a * in.x + b) + d: e * in.x + f;
22 | out.y = (in.y > cut) ? c * log10(a * in.y + b) + d: e * in.y + f;
23 | out.z = (in.z > cut) ? c * log10(a * in.z + b) + d: e * in.z + f;
24 |
25 | return out;
26 | }
27 |
28 | __DEVICE__ float3 LogC3ToLin (float3 in) {
29 | float3 out;
30 |
31 | float cut = 0.010591;
32 | float a = 5.555556;
33 | float b = 0.052272;
34 | float c = 0.247190;
35 | float d = 0.385537;
36 | float e = 5.367655;
37 | float f = 0.092809;
38 |
39 | out.x = (in.x > e * cut + f) ? (_powf(10, (in.x - d) / c) - b) / a : (in.x - f) / e;
40 | out.y = (in.y > e * cut + f) ? (_powf(10, (in.y - d) / c) - b) / a : (in.y - f) / e;
41 | out.z = (in.z > e * cut + f) ? (_powf(10, (in.z - d) / c) - b) / a : (in.z - f) / e;
42 |
43 | return out;
44 | }//0
45 |
46 | __DEVICE__ float3 LinToDI (float3 in) {
47 | float3 out;
48 |
49 | float a = 0.0075;
50 | float b = 7.0;
51 | float c = 0.07329248;
52 | float m = 10.44426855;
53 | float lin_cut = 0.00262409;
54 |
55 | out.x = in.x > lin_cut ? (_log2f(in.x + a) + b) * c : in.x * m;
56 | out.y = in.y > lin_cut ? (_log2f(in.y + a) + b) * c : in.y * m;
57 | out.z = in.z > lin_cut ? (_log2f(in.z + a) + b) * c : in.z * m;
58 |
59 | return out;
60 | }
61 |
62 | __DEVICE__ float3 DItoLin (float3 in) {
63 | float3 out;
64 |
65 | float a = 0.0075;
66 | float b = 7.0;
67 | float c = 0.07329248;
68 | float m = 10.44426855;
69 | float log_cut = 0.02740668;
70 |
71 | out.x = in.x > log_cut ? _powf(2.f, (in.x / c) - b) - a : in.x / m;
72 | out.y = in.y > log_cut ? _powf(2.f, (in.y / c) - b) - a : in.y / m;
73 | out.z = in.z > log_cut ? _powf(2.f, (in.z / c) - b) - a : in.z / m;
74 |
75 | return out;
76 | }//2
77 |
78 | __DEVICE__ float3 LinToACEScct (float3 in) {
79 | float3 out;
80 |
81 | float a = 10.5402377416545;
82 | float b = 0.0729055341958355;
83 | float c = 9.72;
84 | float d = 17.52;
85 | float e = 0.0078125;
86 |
87 | out.x = in.x <= e ? a * in.x + b : (_log2f(in.x) + c) / d;
88 | out.y = in.y <= e ? a * in.y + b : (_log2f(in.y) + c) / d;
89 | out.z = in.z <= e ? a * in.z + b : (_log2f(in.z) + c) / d;
90 |
91 | return out;
92 | }
93 |
94 | __DEVICE__ float3 ACEScctToLin (float3 in) {
95 | float3 out;
96 |
97 | float a = 10.5402377416545;
98 | float b = 0.0729055341958355;
99 | float c = 9.72;
100 | float d = 17.52;
101 | float e = _log2f(65504);
102 | float lin_cut = 0.155251141552511;
103 |
104 | out.x = in.x <= lin_cut ? (in.x - b) / a : in.x < (e + c) / d ? _powf(2, in.x*d-c) : 65504;
105 | out.y = in.y <= lin_cut ? (in.y - b) / a : in.y < (e + c) / d ? _powf(2, in.y*d-c) : 65504;
106 | out.z = in.z <= lin_cut ? (in.z - b) / a : in.z < (e + c) / d ? _powf(2, in.z*d-c) : 65504;
107 |
108 | return out;
109 | }//3
110 |
111 | __DEVICE__ float3 LinToLogC4 (float3 in) {
112 | float3 out;
113 |
114 | float a = (_powf(2.0, 18.0) - 16.0) / 117.45;
115 | float b = (1023.0 - 95.0) / 1023.0;
116 | float c = 95.0 / 1023.0;
117 | float s = (7 * _logf(2) * _powf(2.0, 7 - 14 * c / b)) / (a * b);
118 | float t = (_powf(2.0, 14.0 * (-c / b) + 6.0) - 64.0) / a;
119 |
120 | out.x = in.x < t ? (in.x - t) / s : (_log2f( a * in.x + 64.0) - 6.0) / 14.0 * b + c;
121 | out.y = in.y < t ? (in.y - t) / s : (_log2f( a * in.y + 64.0) - 6.0) / 14.0 * b + c;
122 | out.z = in.z < t ? (in.z - t) / s : (_log2f( a * in.z + 64.0) - 6.0) / 14.0 * b + c;
123 |
124 | return out;
125 | }
126 |
127 | __DEVICE__ float3 LogC4ToLin (float3 in) {
128 | float3 out;
129 |
130 | float a = (_powf(2.0, 18.0) - 16.0) / 117.45;
131 | float b = (1023.0 - 95.0) / 1023.0;
132 | float c = 95.0 / 1023.0;
133 | float s = (7 * _logf(2) * _powf(2.0, 7 - 14 * c / b)) / (a * b);
134 | float t = (_powf(2.0, 14.0 * (-c / b) + 6.0) - 64.0) / a;
135 |
136 | out.x = in.x < 0.0 ? in.x * s + t : (_powf(2.0, 14.0 * (in.x - c) / b + 6.0) - 64.0) / a;
137 | out.y = in.y < 0.0 ? in.y * s + t : (_powf(2.0, 14.0 * (in.y - c) / b + 6.0) - 64.0) / a;
138 | out.z = in.z < 0.0 ? in.z * s + t : (_powf(2.0, 14.0 * (in.z - c) / b + 6.0) - 64.0) / a;
139 |
140 | return out;
141 | }//1
142 |
143 | __DEVICE__ float3 LinToDLog (float3 in) {
144 | float3 out;
145 |
146 | out.x = in.x <= 0.0078 ? 6.025 * in.x + 0.0929 : (_log10f(in.x * 0.9892 + 0.0108)) * 0.256663 + 0.584555;
147 | out.y = in.y <= 0.0078 ? 6.025 * in.y + 0.0929 : (_log10f(in.y * 0.9892 + 0.0108)) * 0.256663 + 0.584555;
148 | out.z = in.z <= 0.0078 ? 6.025 * in.z + 0.0929 : (_log10f(in.z * 0.9892 + 0.0108)) * 0.256663 + 0.584555;
149 |
150 | return out;
151 | }
152 |
153 | __DEVICE__ float3 DLogToLin (float3 in) {
154 | float3 out;
155 |
156 | out.x = in.x <= 0.14 ? (in.x - 0.0929) / 6.025 : (_powf(10, 3.89616 * in.x - 2.27752) - 0.0108) / 0.9892;
157 | out.y = in.y <= 0.14 ? (in.y - 0.0929) / 6.025 : (_powf(10, 3.89616 * in.y - 2.27752) - 0.0108) / 0.9892;
158 | out.z = in.z <= 0.14 ? (in.z - 0.0929) / 6.025 : (_powf(10, 3.89616 * in.z - 2.27752) - 0.0108) / 0.9892;
159 |
160 | return out;
161 | }
162 |
163 | __DEVICE__ float3 LinToFLog (float3 in) {
164 | float3 out;
165 |
166 | float a = 0.555556;
167 | float b = 0.009468;
168 | float c = 0.344676;
169 | float d = 0.790453;
170 | float e = 8.735631;
171 | float f = 0.092864;
172 | float cut = 0.00089;
173 |
174 | out.x = in.x >= cut ? c * _log10f(a * in.x + b) + d : e * in.x + f;
175 | out.y = in.y >= cut ? c * _log10f(a * in.y + b) + d : e * in.y + f;
176 | out.z = in.z >= cut ? c * _log10f(a * in.z + b) + d : e * in.z + f;
177 |
178 | return out;
179 | }
180 |
181 | __DEVICE__ float3 FLogToLin (float3 in) {
182 | float3 out;
183 |
184 | float a = 0.555556;
185 | float b = 0.009468;
186 | float c = 0.344676;
187 | float d = 0.790453;
188 | float e = 8.735631;
189 | float f = 0.092864;
190 | float cut = 0.100537775223865;
191 |
192 | out.x = in.x >= cut ? _powf(10, ((in.x - d) / c)) / a - b / a : (in.x - f) / e;
193 | out.y = in.y >= cut ? _powf(10, ((in.y - d) / c)) / a - b / a : (in.y - f) / e;
194 | out.z = in.z >= cut ? _powf(10, ((in.z - d) / c)) / a - b / a : (in.z - f) / e;
195 |
196 | return out;
197 | }
198 |
199 | __DEVICE__ float3 LinToFLog2 (float3 in) {
200 | float3 out;
201 |
202 | float a = 5.555556;
203 | float b = 0.064829;
204 | float c = 0.245281;
205 | float d = 0.384316;
206 | float e = 8.799461;
207 | float f = 0.092864;
208 | float cut = 0.000889;
209 |
210 | out.x = in.x >= cut ? c * _log10f(a * in.x + b) + d : e * in.x + f;
211 | out.y = in.y >= cut ? c * _log10f(a * in.y + b) + d : e * in.y + f;
212 | out.z = in.z >= cut ? c * _log10f(a * in.z + b) + d : e * in.z + f;
213 |
214 | return out;
215 | }
216 |
217 | __DEVICE__ float3 FLog2ToLin (float3 in) {
218 | float3 out;
219 |
220 | float a = 5.555556;
221 | float b = 0.064829;
222 | float c = 0.245281;
223 | float d = 0.384316;
224 | float e = 8.799461;
225 | float f = 0.092864;
226 | float cut = 0.100686685370811;
227 |
228 | out.x = in.x >= cut ? _powf(10, ((in.x - d) / c)) / a - b / a : (in.x - f) / e;
229 | out.y = in.y >= cut ? _powf(10, ((in.y - d) / c)) / a - b / a : (in.y - f) / e;
230 | out.z = in.z >= cut ? _powf(10, ((in.z - d) / c)) / a - b / a : (in.z - f) / e;
231 |
232 | return out;
233 | }
234 |
235 | __DEVICE__ float3 LinToVLog (float3 in) {
236 | float3 out;
237 |
238 | float cut = 0.01;
239 | float b = 0.00873;
240 | float c = 0.241514;
241 | float d = 0.598206;
242 |
243 | out.x = in.x < cut ? 5.6 * in.x + 0.125 : c * _log10f(in.x + b) + d;
244 | out.y = in.y < cut ? 5.6 * in.y + 0.125 : c * _log10f(in.y + b) + d;
245 | out.z = in.z < cut ? 5.6 * in.z + 0.125 : c * _log10f(in.z + b) + d;
246 |
247 | return out;
248 | }
249 |
250 | __DEVICE__ float3 VLogToLin (float3 in) {
251 | float3 out;
252 |
253 | float cut = 0.181;
254 | float b = 0.00873;
255 | float c = 0.241514;
256 | float d = 0.598206;
257 |
258 | out.x = in.x < cut ? (in.x - 0.125) / 5.6 : _powf(10.0, ((in.x - d) / c)) - b;
259 | out.y = in.y < cut ? (in.y - 0.125) / 5.6 : _powf(10.0, ((in.y - d) / c)) - b;
260 | out.z = in.z < cut ? (in.z - 0.125) / 5.6 : _powf(10.0, ((in.z - d) / c)) - b;
261 |
262 | return out;
263 | }
264 |
265 | __DEVICE__ float3 LinToLog3G10 (float3 in) {
266 | float3 out;
267 |
268 | float a = 0.224282f;
269 | float b = 155.975327f;
270 | float c = 0.01f;
271 | float g = 15.1927f;
272 |
273 | in.x += c;
274 | in.y += c;
275 | in.z += c;
276 |
277 | out.x = in.x < 0.0f ? in.x * g : a * _log10f((in.x * b) + 1.0f);
278 | out.y = in.y < 0.0f ? in.y * g : a * _log10f((in.y * b) + 1.0f);
279 | out.z = in.z < 0.0f ? in.z * g : a * _log10f((in.z * b) + 1.0f);
280 |
281 | return out;
282 | }
283 |
284 | __DEVICE__ float3 Log3G10toLin (float3 in) {
285 | float3 out;
286 |
287 | float a = 0.224282f;
288 | float b = 155.975327f;
289 | float c = 0.01f;
290 | float g = 15.1927f;
291 |
292 | out.x = in.x < 0.0f ? (in.x / g) - c : (_powf(10.0f, in.x / a) - 1.0f) / b;
293 | out.y = in.y < 0.0f ? (in.y / g) - c : (_powf(10.0f, in.y / a) - 1.0f) / b;
294 | out.z = in.z < 0.0f ? (in.z / g) - c : (_powf(10.0f, in.z / a) - 1.0f) / b;
295 |
296 | out.x -= c;
297 | out.y -= c;
298 | out.z -= c;
299 |
300 | return out;
301 | }
302 |
303 | __DEVICE__ float3 LinToSLog3 (float3 in) {
304 | float3 out;
305 |
306 | out.x = in.x >= 0.01125000 ? (420.0 + _log10f((in.x + 0.01) / (0.18 + 0.01)) * 261.5) / 1023.0 : (in.x * (171.2102946929 - 95.0)/0.01125000 + 95.0) / 1023.0;
307 | out.y = in.y >= 0.01125000 ? (420.0 + _log10f((in.y + 0.01) / (0.18 + 0.01)) * 261.5) / 1023.0 : (in.y * (171.2102946929 - 95.0)/0.01125000 + 95.0) / 1023.0;
308 | out.z = in.z >= 0.01125000 ? (420.0 + _log10f((in.z + 0.01) / (0.18 + 0.01)) * 261.5) / 1023.0 : (in.z * (171.2102946929 - 95.0)/0.01125000 + 95.0) / 1023.0;
309 |
310 | return out;
311 | }
312 |
313 | __DEVICE__ float3 SLog3ToLin (float3 in) {
314 | float3 out;
315 |
316 | out.x = in.x >= 171.2102946929 / 1023.0 ? (_powf(10.0, ((in.x * 1023.0 - 420.0) / 261.5))) * (0.18 + 0.01) - 0.01 : (in.x * 1023.0 - 95.0) * 0.01125000 / (171.2102946929 - 95.0);
317 | out.y = in.y >= 171.2102946929 / 1023.0 ? (_powf(10.0, ((in.y * 1023.0 - 420.0) / 261.5))) * (0.18 + 0.01) - 0.01 : (in.y * 1023.0 - 95.0) * 0.01125000 / (171.2102946929 - 95.0);
318 | out.z = in.z >= 171.2102946929 / 1023.0 ? (_powf(10.0, ((in.z * 1023.0 - 420.0) / 261.5))) * (0.18 + 0.01) - 0.01 : (in.z * 1023.0 - 95.0) * 0.01125000 / (171.2102946929 - 95.0);
319 |
320 | return out;
321 | }
322 |
323 | __DEVICE__ float3 LinToBMDFilmGen5(float3 in) {
324 | float3 out;
325 |
326 | float a = 8.283605932402494f;
327 | float b = 0.09246575342465753f;
328 | float c = 0.5300133392291939f;
329 | float d = 0.08692876065491224f;
330 | float e = 0.005494072432257808f;
331 | float cut = 0.005f;
332 |
333 | out.x = in.x < cut ? a * in.x + b : d * _logf(in.x + e) + c;
334 | out.y = in.y < cut ? a * in.y + b : d * _logf(in.y + e) + c;
335 | out.z = in.z < cut ? a * in.z + b : d * _logf(in.z + e) + c;
336 |
337 | return out;
338 | }
339 |
340 | __DEVICE__ float3 BMDFilmGen5ToLin(float3 in) {
341 | float3 out;
342 |
343 | float a = 8.283605932402494f;
344 | float b = 0.09246575342465753f;
345 | float c = 0.5300133392291939f;
346 | float d = 0.08692876065491224f;
347 | float e = 0.005494072432257808f;
348 | float cut = a * 0.005f + b;
349 |
350 | out.x = in.x < (a * 0.005f + b) ? (in.x - b) / a : _expf((in.x - c) / d) - e;
351 | out.y = in.y < (a * 0.005f + b) ? (in.y - b) / a : _expf((in.y - c) / d) - e;
352 | out.z = in.z < (a * 0.005f + b) ? (in.z - b) / a : _expf((in.z - c) / d) - e;
353 |
354 | return out;
355 | }
356 |
357 | __DEVICE__ float3 LinToCLog (float3 in) {
358 | float3 out;
359 |
360 | out.x = in.x < 0 ? -.529136 * _log10f(1 - 10.1596 * in.x) + 0.0730597 : .529136 * _log10f(10.1596 * in.x + 1) + 0.0730597;
361 | out.y = in.y < 0 ? -.529136 * _log10f(1 - 10.1596 * in.y) + 0.0730597 : .529136 * _log10f(10.1596 * in.y + 1) + 0.0730597;
362 | out.z = in.z < 0 ? -.529136 * _log10f(1 - 10.1596 * in.z) + 0.0730597 : .529136 * _log10f(10.1596 * in.z + 1) + 0.0730597;
363 |
364 | return out;
365 | }
366 |
367 | __DEVICE__ float3 CLogToLin (float3 in) {
368 | float3 out;
369 |
370 | out.x = in.x < 0.0730597 ? -(_powf(10, (0.0730597 - in.x) / .529136) - 1) / 10.1596 : (_powf(10, (in.x - 0.0730597) / .529136) - 1) / 10.1596;
371 | out.y = in.y < 0.0730597 ? -(_powf(10, (0.0730597 - in.y) / .529136) - 1) / 10.1596 : (_powf(10, (in.y - 0.0730597) / .529136) - 1) / 10.1596;
372 | out.z = in.z < 0.0730597 ? -(_powf(10, (0.0730597 - in.z) / .529136) - 1) / 10.1596 : (_powf(10, (in.z - 0.0730597) / .529136) - 1) / 10.1596;
373 |
374 | return out;
375 | }
376 |
377 | __DEVICE__ float3 LinToCLog2 (float3 in) {
378 | float3 out;
379 |
380 | out.x = in.x < 0 ? -0.24136077 * _log10f(1 - 87.099375 * in.x) + 0.092864125 : 0.24136077 * _log10f(87.099375 * in.x + 1) + 0.092864125;
381 | out.y = in.y < 0 ? -0.24136077 * _log10f(1 - 87.099375 * in.y) + 0.092864125 : 0.24136077 * _log10f(87.099375 * in.y + 1) + 0.092864125;
382 | out.z = in.z < 0 ? -0.24136077 * _log10f(1 - 87.099375 * in.z) + 0.092864125 : 0.24136077 * _log10f(87.099375 * in.z + 1) + 0.092864125;
383 |
384 | return out;
385 | }
386 |
387 | __DEVICE__ float3 CLog2ToLin (float3 in) {
388 | float3 out;
389 |
390 | out.x = in.x < 0.092864125 ? -(_powf(10, (0.092864125 - in.x) / 0.24136077) - 1) / 87.099375 : (_powf(10, (in.x - 0.092864125) / 0.24136077) - 1) / 87.099375;
391 | out.y = in.y < 0.092864125 ? -(_powf(10, (0.092864125 - in.y) / 0.24136077) - 1) / 87.099375 : (_powf(10, (in.y - 0.092864125) / 0.24136077) - 1) / 87.099375;
392 | out.z = in.z < 0.092864125 ? -(_powf(10, (0.092864125 - in.z) / 0.24136077) - 1) / 87.099375 : (_powf(10, (in.z - 0.092864125) / 0.24136077) - 1) / 87.099375;
393 |
394 | return out;
395 | }
396 |
397 | __DEVICE__ float3 LinToCLog3 (float3 in) {
398 | float3 out;
399 |
400 | out.x = in.x < -0.014 ? -0.36726845 * _log10f(1 - 14.98325 * in.x) + 0.12783901 : in.x <= 0.014 ? 1.9754798 * in.x + 0.12512219 : 0.36726845 * _log10f(14.98325 * in.x + 1) + 0.12240537;
401 | out.y = in.y < -0.014 ? -0.36726845 * _log10f(1 - 14.98325 * in.y) + 0.12783901 : in.y <= 0.014 ? 1.9754798 * in.y + 0.12512219 : 0.36726845 * _log10f(14.98325 * in.y + 1) + 0.12240537;
402 | out.z = in.z < -0.014 ? -0.36726845 * _log10f(1 - 14.98325 * in.z) + 0.12783901 : in.z <= 0.014 ? 1.9754798 * in.z + 0.12512219 : 0.36726845 * _log10f(14.98325 * in.z + 1) + 0.12240537;
403 |
404 | return out;
405 | }
406 |
407 | __DEVICE__ float3 CLog3ToLin (float3 in) {
408 | float3 out;
409 |
410 | out.x = in.x < 0.097465473 ? -(_powf(10, (0.12783901 - in.x) / 0.36726845) - 1) / 14.98325 : in.x <= 0.15277891 ? (in.x - 0.12512219) / 1.9754798 : (_powf(10, (in.x - 0.12240537) / 0.36726845) - 1) / 14.98325;
411 | out.y = in.y < 0.097465473 ? -(_powf(10, (0.12783901 - in.y) / 0.36726845) - 1) / 14.98325 : in.y <= 0.15277891 ? (in.y - 0.12512219) / 1.9754798 : (_powf(10, (in.y - 0.12240537) / 0.36726845) - 1) / 14.98325;
412 | out.z = in.z < 0.097465473 ? -(_powf(10, (0.12783901 - in.z) / 0.36726845) - 1) / 14.98325 : in.z <= 0.15277891 ? (in.z - 0.12512219) / 1.9754798 : (_powf(10, (in.z - 0.12240537) / 0.36726845) - 1) / 14.98325;
413 |
414 | return out;
415 | }
416 |
417 |
418 | __DEVICE__ float3 GammaCurveToLin (float3 in, float gamma) {
419 | float3 out;
420 |
421 | out.x = _powf(_fmaxf(in.x, 0.0f), gamma);
422 | out.y = _powf(_fmaxf(in.y, 0.0f), gamma);
423 | out.z = _powf(_fmaxf(in.z, 0.0f), gamma);
424 |
425 | return out;
426 | }
427 |
428 | __DEVICE__ float3 LinToGammaCurve (float3 in, float gamma) {
429 | float3 out;
430 |
431 | out.x = _powf(_fmaxf(in.x, 0.0f), (1 / gamma));
432 | out.y = _powf(_fmaxf(in.y, 0.0f), (1 / gamma));
433 | out.z = _powf(_fmaxf(in.z, 0.0f), (1 / gamma));
434 |
435 | return out;
436 | }
437 |
438 |
439 |
440 |
441 | //functions to apply transfer function conversions
442 |
443 | __DEVICE__ float3 GammaToLin (float3 in, int gamma) {
444 |
445 | if (gamma == 0) return LogC3ToLin(in);
446 | if (gamma == 1) return LogC4ToLin(in);
447 | if (gamma == 2) return DItoLin(in);
448 | if (gamma == 3) return ACEScctToLin (in);
449 | if (gamma == 4) return Log3G10toLin(in);
450 | if (gamma == 5) return SLog3ToLin(in);
451 | if (gamma == 6) return BMDFilmGen5ToLin(in);
452 | if (gamma == 7) return CLog3ToLin(in);
453 | if (gamma == 8) return DLogToLin(in);
454 | if (gamma == 9) return FLogToLin(in);
455 | if (gamma == 10) return FLog2ToLin(in);
456 | if (gamma == 11) return VLogToLin(in);
457 | if (gamma == 12) return GammaCurveToLin(in, 2.2);
458 | if (gamma == 13) return GammaCurveToLin(in, 2.4);
459 | if (gamma == 14) return GammaCurveToLin(in, 2.6);
460 | if (gamma == 15) return in; // Lin
461 |
462 |
463 | return make_float3(0, 0, 1); // Blue on error
464 | }
465 |
466 | __DEVICE__ float3 LinToGamma (float3 in, int gamma) {
467 | if (gamma == 0) return LinToLogC3(in);
468 | if (gamma == 1) return LinToLogC4(in);
469 | if (gamma == 2) return LinToDI(in);
470 | if (gamma == 3) return LinToACEScct(in);
471 | if (gamma == 4) return LinToLog3G10(in);
472 | if (gamma == 5) return LinToSLog3(in);
473 | if (gamma == 6) return LinToBMDFilmGen5(in);
474 | if (gamma == 7) return LinToCLog3(in);
475 | if (gamma == 8) return LinToDLog(in);
476 | if (gamma == 9) return LinToFLog(in);
477 | if (gamma == 10) return LinToFLog2(in);
478 | if (gamma == 11) return LinToVLog(in);
479 | if (gamma == 12) return LinToGammaCurve(in, 2.2);
480 | if (gamma == 13) return LinToGammaCurve(in, 2.4);
481 | if (gamma == 14) return LinToGammaCurve(in, 2.6);
482 | if (gamma == 15) return in; // Lin
483 |
484 |
485 |
486 | return make_float3(1, 0, 0); // Red on error
487 | }
488 |
489 | __DEVICE__ float set_pivot (float pivot, int gamma) {
490 |
491 | float3 midgray = LinToGamma(make_float3(0.18f, 0.18f,0.18f), gamma);
492 | pivot = pivot + midgray.x;
493 |
494 | return pivot;
495 | }
496 |
497 | __DEVICE__ float3 SetWorkingSpace (float3 in, int inTF) {
498 |
499 | float3 linearized;
500 | if (inTF == 2) { return in;}
501 |
502 | if (inTF == 0) { in = GammaToLin(in, 0); }
503 | if (inTF == 1) { in = GammaToLin(in, 1); }
504 |
505 | if (inTF == 3) { in = GammaToLin(in, 3); }
506 | if (inTF == 4) { in = GammaToLin(in, 4); }
507 | if (inTF == 5) { in = GammaToLin(in, 5); }
508 | if (inTF == 6) { in = GammaToLin(in, 6); }
509 | if (inTF == 7) { in = GammaToLin(in, 7); }
510 | if (inTF == 8) { in = GammaToLin(in, 8); }
511 | if (inTF == 9) { in = GammaToLin(in, 9); }
512 | if (inTF == 10) { in = GammaToLin(in,10); }
513 | if (inTF == 11) { in = GammaToLin(in,11); }
514 | if (inTF == 12) { in = GammaToLin(in,12); }
515 | if (inTF == 13) { in = GammaToLin(in,13); }
516 | if (inTF == 14) { in = GammaToLin(in,14); }
517 | if (inTF == 15) { in = GammaToLin(in,15); }
518 | linearized = in;
519 |
520 | if (inTF == 0) { return LinToGamma(linearized,2); }
521 | if (inTF == 1) { return LinToGamma(linearized,2); }
522 |
523 | if (inTF == 3) { return LinToGamma(linearized,2); }
524 | if (inTF == 4) { return LinToGamma(linearized,2); }
525 | if (inTF == 5) { return LinToGamma(linearized,2); }
526 | if (inTF == 6) { return LinToGamma(linearized,2); }
527 | if (inTF == 7) { return LinToGamma(linearized,2); }
528 | if (inTF == 8) { return LinToGamma(linearized,2); }
529 | if (inTF == 9) { return LinToGamma(linearized,2); }
530 | if (inTF == 10) { return LinToGamma(linearized,2); }
531 | if (inTF == 11) { return LinToGamma(linearized,2); }
532 | if (inTF == 12) { return LinToGamma(linearized,2); }
533 | if (inTF == 13) { return LinToGamma(linearized,2); }
534 | if (inTF == 14) { return LinToGamma(linearized,2); }
535 | if (inTF == 15) { return LinToGamma(linearized,2); }
536 |
537 |
538 |
539 |
540 |
541 | return make_float3(1, 0, 0); // Red on error;
542 |
543 | }
544 |
545 |
546 | __DEVICE__ float3 Inverse_WorkingSpace (float3 in, int inTF) {
547 |
548 |
549 | //convert back to the selected input space
550 | float3 linearized =in;
551 | linearized = GammaToLin(in,2);
552 |
553 |
554 |
555 | if (inTF == 0) { return LinToGamma(linearized,0); }
556 | if (inTF == 1) { return LinToGamma(linearized,1); }
557 | //passthrough DI which is set as 2 as per the list parameter UI
558 | if (inTF == 2) { return in;}
559 | if (inTF == 3) { return LinToGamma(linearized, 3); }
560 | if (inTF == 4) { return LinToGamma(linearized, 4); }
561 | if (inTF == 5) { return LinToGamma(linearized, 5); }
562 | if (inTF == 6) { return LinToGamma(linearized, 6); }
563 | if (inTF == 7) { return LinToGamma(linearized, 7); }
564 | if (inTF == 8) { return LinToGamma(linearized, 8); }
565 | if (inTF == 9) { return LinToGamma(linearized, 9); }
566 | if (inTF == 10) { return LinToGamma(linearized,10); }
567 | if (inTF == 11) { return LinToGamma(linearized,11); }
568 | if (inTF == 12) { return LinToGamma(linearized,12); }
569 | if (inTF == 13) { return LinToGamma(linearized,13); }
570 | if (inTF == 14) { return LinToGamma(linearized,14); }
571 | if (inTF == 15) { return LinToGamma(linearized,15); }
572 |
573 | return make_float3(1, 0, 0); // Red on error;
574 |
575 |
576 | }
577 |
578 |
579 | __DEVICE__ float powf(float base, float exp) {
580 | return _copysignf(_powf(_fabs(base), exp), base);
581 | }
582 |
583 |
584 | //main tool functions
585 |
586 |
587 | __DEVICE__ float3 exposure_high(float3 rgb, float ex, float pv, float fa, int inv) {
588 | // Zoned highlight exposure with falloff : https://www.desmos.com/calculator/ylq5yvkhoq
589 | // Original code written by Jed smith
590 |
591 | // Parameter setup
592 | const float f = 5.0f * _powf(fa, 1.6f) + 1.0f;
593 | const float p = _fabs(ex + f) < 1e-8f ? 1e-8f : (ex + f) / f;
594 | const float m = _powf(2.0f, ex);
595 | const float t0 = 0.18f * _powf(2.0f, pv);
596 | const float a = _powf(t0, 1.0f - p) / p;
597 | const float b = t0 * (1.0f - 1.0f / p);
598 | const float x1 = t0 * _powf(2.0f, f);
599 | const float y1 = a * _powf(x1, p) + b;
600 |
601 | // Calculate scale factor for rgb
602 | float n = _fmaxf(rgb.x, _fmaxf(rgb.y, rgb.z));
603 | float s;
604 | if (inv == 1)
605 | s = n < t0 ? 1.0f : n > y1 ? ((m * x1 - y1 + n) / m) / n : _powf((n - b) / a, 1.0f / p) / n;
606 | else
607 | s = n < t0 ? 1.0f : n > x1 ? (m * (n - x1) + y1) / n : (a * _powf(n, p) + b) / n;
608 | return rgb * s;
609 | }
610 |
611 | __DEVICE__ float3 exposure_low(float3 rgb, float ex, float pv, float fa) {
612 | // Zoned shadow exposure with falloff : https://www.desmos.com/calculator/my116fpnix
613 | // https://colab.research.google.com/drive/1GAoiqR33U2zlW5fw1byUdZBw7eqJibjN
614 | // Original code written by Jed smith
615 |
616 | // Parameter setup
617 | const float f = 6.0f - 5.0f * fa;
618 | const float p = _fminf(f / 2.0f, f / 2.0f * _powf(0.5, ex));
619 | const float t0 = 0.18f * _powf(2.0f, pv);
620 | const float _c = _powf(2.0f, ex);
621 | const float _a = p*(_c - 1.0f)/_powf(t0, p + 1.0f);
622 | const float _b = (1.0f - _c)*(p + 1.0f)/_powf(t0, p);
623 |
624 | // Calculate scale factor for rgb
625 | float n = _fmaxf(rgb.x, _fmaxf(rgb.y, rgb.z));
626 | float s = n > t0 || n < 0.0f ? 1.0f : _powf(n, p) * (_a * n + _b) + _c; // implicit divide by n here
627 | return rgb * s;
628 | }
629 |
630 |
631 |
632 |
633 |
634 | //functions for implementing the feathered luma mask
635 |
636 | __DEVICE__ float3 mixFloat3(float mix, float3 inA, float3 inB) {
637 | // Note that when a float3 is multiplied by a float, it multiplies each component
638 | return inA * (1-mix) + inB * mix;
639 | }
640 |
641 | typedef struct {
642 | float HiThreshold, HiFeather, LoThreshold, LoFeather, TF;
643 | int X, Y, height;
644 | bool alpha, matteMode;
645 |
646 | } params_t;
647 |
648 | // Function to draw transparency overlay based on the given parameters
649 | __DEVICE__ float3 drawTransparencyOverlay(float3 in, float matte, params_t params) {
650 | float3 out = in;
651 |
652 | if (params.matteMode) {
653 | // If matte mode is enabled, set the output color to the matte value
654 | out = make_float3(matte, matte, matte);
655 | } else {
656 | float transparentColor = .3;
657 | float squareSize = params.height / 64;
658 |
659 | // Calculate the row and column based on the X and Y coordinates and the square size
660 | int row = _floorf(params.X / squareSize);
661 | int col = _floorf(params.Y / squareSize);
662 |
663 | // Check if the sum of row and column is even to determine the transparency color
664 | if ((row + col) % 2 == 0) transparentColor = .35;
665 |
666 | // Fade between the original input image and the transparency checkerboard based on the matte
667 | out = mixFloat3(matte, make_float3(transparentColor, transparentColor, transparentColor), in);
668 | }
669 |
670 | return out;
671 | }
672 |
673 | __DEVICE__ float smootherstep(float x) {
674 | x = _clampf(x, 0.0, 1.0);
675 | return 3.0 * powf(x, 2.0) - 2.0 * powf(x, 3.0);}
676 |
677 | __DEVICE__ float3 HiLoLumaMask (float3 in, float3 base, params_t params) {
678 | float3 mid_grey_f3 = LinToGamma(make_float3 (0.18,0.18,0.18), params.TF);
679 | float mid_grey = mid_grey_f3.x;
680 | //float pxlX = (float)X;
681 | //float pxlY = (float)Y;
682 |
683 | //mid_grey = 0.18;
684 |
685 |
686 | float Lo_min = mid_grey * _exp2f(params.LoThreshold - 0.5 * params.LoFeather);
687 | float Lo_max = mid_grey * _exp2f(params.LoThreshold + 0.5 * params.LoFeather);
688 | float Hi_min = mid_grey * _exp2f(params.HiThreshold - 0.5 * params.HiFeather);
689 | float Hi_max = mid_grey * _exp2f(params.HiThreshold + 0.5 * params.HiFeather);
690 | float input_metric = _fmaxf(_fmaxf(base.x, base.y), base.z);
691 |
692 | float input_metric_log = _log2f(_fmaxf(input_metric, 0.0));
693 | float Hi_min_log = _log2f(Hi_min);
694 | float Hi_max_log = _log2f(Hi_max);
695 | float Lo_min_log = _log2f(Lo_min);
696 | float Lo_max_log = _log2f(Lo_max);
697 |
698 | float shadow_mask;
699 | if (input_metric < Lo_min) {
700 | shadow_mask = 1.0;
701 | } else if (Lo_max < input_metric) {
702 | shadow_mask = 0.0;
703 | } else {
704 | shadow_mask = _mix(1.0, 0.0, smootherstep((input_metric_log - Lo_min_log) / (Lo_max_log - Lo_min_log)));
705 | }
706 |
707 |
708 | float highlight_mask;
709 | if (input_metric < Hi_min) {
710 | highlight_mask = 1.0;
711 | }
712 | else if (Hi_max < input_metric) {
713 | highlight_mask = 0.0;
714 | }
715 | else {
716 | highlight_mask = _mix(1.0, 0.0, smootherstep((input_metric_log - Hi_min_log) / (Hi_max_log - Hi_min_log)));
717 |
718 | }
719 | highlight_mask = 1- highlight_mask;
720 |
721 | float HiLo_mask = shadow_mask + highlight_mask;
722 | HiLo_mask = 1- _saturatef(HiLo_mask);
723 |
724 | float3 pinends = _mix(base,in,HiLo_mask);
725 |
726 | float3 output;
727 |
728 | if (params.alpha) {
729 | output = drawTransparencyOverlay(pinends, HiLo_mask, params);
730 | } else {output = pinends;}
731 |
732 |
733 | return output;
734 | }
735 |
736 |
737 |
738 | DEFINE_UI_PARAMS(P_exHI, KEY - Exposure__, DCTLUI_SLIDER_FLOAT, 0.0, -5.99, 5.99, 0.1)
739 | DEFINE_UI_PARAMS(P_faHI, Key Falloff, DCTLUI_SLIDER_FLOAT, 0.5, 0.0, 1.0, 0.0)
740 |
741 | DEFINE_UI_PARAMS(P_exLo, FILL - Exposure__, DCTLUI_SLIDER_FLOAT, 0.0, -5.99, 5.99, 0.1)
742 | DEFINE_UI_PARAMS(P_faLo, Fill Falloff, DCTLUI_SLIDER_FLOAT, 0.5, 0.0, 1.0, 0.0)
743 |
744 |
745 | DEFINE_UI_PARAMS(P_pvHI, HI Pivot, DCTLUI_SLIDER_FLOAT, 0.0, -5.0, 5.0, 0.1)
746 | DEFINE_UI_PARAMS(P_pvLo, Lo Pivot, DCTLUI_SLIDER_FLOAT, 0.0, -3.0, 3.0, 0.1)
747 |
748 | DEFINE_UI_PARAMS(p_exposure, Overall - Exposure, DCTLUI_SLIDER_FLOAT, 0.0, -1.0, 1.0, 0.1)
749 |
750 | DEFINE_UI_PARAMS(p_save_sat, Preserve Color , DCTLUI_SLIDER_FLOAT, 0.5, 0.0, 1.0, 0.25)
751 |
752 | DEFINE_UI_PARAMS(p_Hi_stops, Mask Highlights, DCTLUI_SLIDER_FLOAT, 5.0, -3.0, 5.0, 0.1)
753 | DEFINE_UI_PARAMS(p_Lo_stops, Mask Shadows, DCTLUI_SLIDER_FLOAT, -7.0, -7.0, 1.0, 0.1)
754 |
755 |
756 |
757 | DEFINE_UI_PARAMS(bypass, Bypass, DCTLUI_CHECK_BOX, 0)
758 | DEFINE_UI_PARAMS(opt_showcurve, Show Curve, DCTLUI_CHECK_BOX, 0)
759 | DEFINE_UI_PARAMS(opt_ramp, Show Ramp, DCTLUI_CHECK_BOX, 0)
760 | DEFINE_UI_PARAMS(opt_ramp_scope, = Wide aspect overlays =, DCTLUI_CHECK_BOX, 0)
761 |
762 | DEFINE_UI_PARAMS(alpha_toggle, Show Mask, DCTLUI_CHECK_BOX, 0)
763 | DEFINE_UI_PARAMS(opt_soft, Preserve curve ends, DCTLUI_CHECK_BOX, 1)
764 |
765 |
766 | DEFINE_UI_PARAMS(alpha_matte, Highlight mode, DCTLUI_COMBO_BOX, 0, {overlay, matte}, {Overlay, Matte})
767 | DEFINE_UI_PARAMS(p_transfer_f, Input Space, DCTLUI_COMBO_BOX, 2, {logc3, logc4, di, aces_cct, log3g10, slog3, bmd_f5, clog3, dlog, fLog, fLog2, vlog, g22, g24, g26, linear}, {ARRI LogC3, ARRI LogC4, DaVinci Intermediate, ACEScct, RED Log3G10, Sony S-Log3, BMD Film Gen 5, Canon Log 3, DJI D-Log, FujiFilm F-Log, FujiFilm F-Log2, Panasonic V-Log, Gamma 2.2, Gamma 2.4, Gamma 2.6, Linear})
768 |
769 |
770 | __DEVICE__ float3 transform(int p_Width, int p_Height, int p_X, int p_Y, float p_R, float p_G, float p_B)
771 | {
772 |
773 | //--------------------------
774 | //--------------------------
775 | //prepare for doing magic here
776 | //--------------------------
777 | //--------------------------
778 |
779 |
780 | // experimenting with Rec.601 coefficients
781 | //const float3 luma_coefficients = {0.29912, 0.58749, 0.11437};
782 | // correct coefficients for DWG
783 | const float3 luma_coefficients = {0.27411851f, 0.87363190f, -0.14775041f};
784 |
785 | const float3 bypass_RGB = make_float3(p_R, p_G, p_B);
786 | float3 out;
787 | //float3 outRGB0;
788 | out = bypass_RGB;
789 |
790 | P_pvLo = P_pvLo == 0 ?powf(2.0, 0.000001)*set_pivot(.5, 2) : powf(2.0, P_pvLo)*set_pivot(.5, 2);
791 | P_pvHI = P_pvHI == 0 ?powf(2.0, 0.000001)*set_pivot(.5, 2) : powf(2.0, P_pvHI)*set_pivot(.5, 2);
792 |
793 | //ensure the shadow mask is not active by default by covering a wider range than what most images can hold if the opt_soft option is off
794 | if (opt_soft == 0) {if (p_Lo_stops == -7) {p_Lo_stops=-20;}}
795 |
796 |
797 |
798 | //move to working color space - Davinci Wide gamut Intermediate
799 |
800 | out = SetWorkingSpace(out, p_transfer_f);
801 |
802 | //create a linear ramp to enable the view graph control
803 | float width = (float)p_Width;
804 | float height = (float)p_Height;
805 | if (opt_ramp_scope) {height = height*0.65f; }
806 | float X = (float)p_X;
807 | float Y = height - (float)p_Y;
808 | if (opt_ramp_scope) { Y = height*1.30f - (float)p_Y; }
809 | //Relative X,Y
810 | float rY = Y / height;
811 | float rX = X / width;
812 | float3 ramp = {rX, rX, rX};
813 |
814 | //a clean version of the ramp to show in the bypass version
815 | float3 cleanRamp = ramp;
816 |
817 | //extract original luminance
818 |
819 |
820 | float luma_in = luma_coefficients.x * out.x + luma_coefficients.y * out.y + luma_coefficients.z * out.z;
821 | float3 luma_in_3 = make_float3(luma_in, luma_in, luma_in);
822 |
823 |
824 | // set up the Highlights and shadows masks control parameters
825 | params_t HiLo_params;
826 |
827 |
828 | HiLo_params.HiThreshold = p_Hi_stops;
829 | HiLo_params.HiFeather = 1.5 * powf(3 / 1.5,((5-p_Hi_stops) / 8.0));
830 | HiLo_params.LoThreshold = p_Lo_stops;
831 | HiLo_params.LoFeather = 5 * powf(1.5 / 5,((p_Lo_stops-(-7)) / 8.0));
832 | HiLo_params.TF = p_transfer_f;
833 | HiLo_params.alpha = alpha_toggle;
834 | HiLo_params.matteMode = alpha_matte;
835 | HiLo_params.X = (int)p_X;
836 | HiLo_params.Y= (int)p_Y;
837 | HiLo_params.height= (float)p_Height;
838 |
839 |
840 |
841 |
842 |
843 | //--------------------------
844 | //--------------------------
845 | //start doing magic here
846 | //--------------------------
847 | //--------------------------
848 |
849 | //Applly fill adjustment
850 | float3 fill = exposure_low(out, P_exLo, P_pvLo, P_faLo);
851 | float3 ramp_fill = exposure_low(ramp, P_exLo, P_pvLo, P_faLo);
852 | float3 luma_fill= exposure_low(luma_in_3, P_exLo, P_pvLo, P_faLo);
853 | float3 luma_fill_out = out- luma_in + luma_fill.x;
854 |
855 | //color preservation behavior
856 | float3 fill_out = mixFloat3(P_exLo<0?p_save_sat:(1-p_save_sat),fill, luma_fill_out);
857 |
858 | //Applly Key adjustment
859 | float3 key = exposure_high(out, P_exHI, P_pvHI, P_faHI, 0);
860 | float3 ramp_key = exposure_high(ramp, P_exHI, P_pvHI, P_faHI, 0);
861 | float3 luma_key = exposure_high(luma_in_3, P_exHI, P_pvHI, P_faHI, 0);
862 | float3 luma_key_out = out- luma_in + luma_key.x;
863 |
864 | //color preservation behavior
865 | float3 key_out = mixFloat3(P_exHI<0?1-p_save_sat:p_save_sat,key, luma_key_out);
866 |
867 | //Exposure and offset in linear
868 | //with increase in exposure I automatically add a slight negative offset down
869 | //to keep the black levels from getting murcky
870 | //also with negative exposure I add the same positive amount as linear offset to keep black levels from crashing.
871 |
872 | float minF= -0.01f;
873 | float maxF = 0.01f;
874 | float flare = 0;
875 | if (p_exposure > 0) {
876 | flare += p_exposure * minF;
877 | } else if (p_exposure < 0) {
878 | flare += p_exposure * (-maxF);
879 | } else {
880 | flare += 0;
881 | }
882 | float3 exp_out = GammaToLin(out, 2);
883 | float3 ramp_exp = GammaToLin(ramp, 2);
884 | float3 luma_exp = GammaToLin(luma_in_3, 2);
885 |
886 |
887 | // Apply linear gain
888 | p_exposure = powf(2.0, p_exposure);
889 | exp_out = exp_out * p_exposure;
890 | ramp_exp = ramp_exp * p_exposure;
891 | luma_exp = luma_exp * p_exposure;
892 |
893 | // Apply linear offset
894 | exp_out = exp_out + flare;
895 | ramp_exp = ramp_exp + flare;
896 | luma_exp = luma_exp + flare;
897 |
898 |
899 | exp_out = LinToGamma(exp_out, 2);
900 | ramp_exp = LinToGamma(ramp_exp, 2);
901 | luma_exp = LinToGamma(luma_exp, 2);
902 | float3 luma_exp_out = out- luma_in + luma_exp.x;
903 |
904 | //color preservation behavior
905 | exp_out = mixFloat3(p_exposure<0?1-p_save_sat:p_save_sat,exp_out, luma_exp_out);
906 |
907 |
908 |
909 | //parellal mixing all adjustment
910 | out = out + (fill_out - out) + (key_out - out) + (exp_out - out);
911 | ramp = ramp + (ramp_fill - ramp) + (ramp_key - ramp) + (ramp_exp - ramp);
912 |
913 |
914 |
915 | // move back to the orignal color space
916 | out = Inverse_WorkingSpace(out,p_transfer_f);
917 |
918 |
919 | if (opt_soft) {
920 | // add an automatic mask to minimize chances of clipping, but allow the user to still make somewhat big adjustments
921 | p_Hi_stops = -3 + powf((p_Hi_stops + 3) / 8.0, 0.3) * 3.8;
922 | HiLo_params.HiThreshold = p_Hi_stops;
923 | HiLo_params.HiFeather = 1.5 * powf(3 / 1.5,((5-p_Hi_stops) / 8.0));
924 |
925 | p_Lo_stops = -1 + powf(((p_Lo_stops + 7) / 8.0), 1.8) * 2.0;
926 | HiLo_params.LoThreshold = p_Lo_stops;
927 | HiLo_params.LoFeather = 5 * powf(1.7 / 5,((p_Lo_stops-(-7)) / 8.0));
928 | }
929 |
930 | out = HiLoLumaMask (out, bypass_RGB, HiLo_params);
931 | ramp = HiLoLumaMask (ramp, cleanRamp, HiLo_params);
932 |
933 |
934 |
935 | // bypass option including a bypass option to the ramp to display an untouched curve
936 | if (bypass ==1 ) {
937 |
938 | out = bypass_RGB;
939 | ramp = cleanRamp;
940 | }
941 |
942 | //option to overlay a grayscale ramp on the bottom edge of the frame
943 | if (opt_ramp) {
944 |
945 | if (opt_ramp_scope){
946 |
947 | if( rY < (0.00001f * height) && rY > (-0.201f * height)) {out = ramp;}
948 | }
949 |
950 | //displaying the value of internal variables for debugging
951 | //if( rY > (0.0003f * height) ) {out = make_float3 (flare, flare,flare);}
952 |
953 | else if( rY < (0.00003f * height) ) {out = ramp;}
954 |
955 | }
956 |
957 | //Optional show curve functionality
958 | if (opt_showcurve == 1 && alpha_toggle==0 ) {
959 |
960 | float3 scopeY = LinToGamma(make_float3(1,1,1), 2);
961 |
962 | float overlayR = ramp.x >= (Y - (0.003f * height)) / height && ramp.x <= (Y + 0.003f * height) / height ? scopeY.x : 0.0f;
963 | float overlayG = ramp.y >= (Y - (0.003f * height)) / height && ramp.y <= (Y + 0.003f * height) / height ? scopeY.y : 0.0f;
964 | float overlayB = ramp.z >= (Y - (0.003f * height)) / height && ramp.z <= (Y + 0.003f * height) / height ? scopeY.z : 0.0f;
965 | out.x = overlayR == 0.0f ? out.x : overlayR;
966 | out.y = overlayG == 0.0f ? out.y : overlayG;
967 | out.z = overlayB == 0.0f ? out.z : overlayB;
968 |
969 | if (opt_ramp_scope){
970 |
971 |
972 | float overlayR = ramp.x >= (Y - (0.003f * height)) / height && ramp.x <= (Y + 0.003f * height) / height ? scopeY.x : 0.0f;
973 | float overlayG = ramp.y >= (Y - (0.003f * height)) / height && ramp.y <= (Y + 0.003f * height) / height ? scopeY.y : 0.0f;
974 | float overlayB = ramp.z >= (Y - (0.003f * height)) / height && ramp.z <= (Y + 0.003f * height) / height ? scopeY.z : 0.0f;
975 | out.x = overlayR == 0.0f ? out.x : overlayR;
976 | out.y = overlayG == 0.0f ? out.y : overlayG;
977 | out.z = overlayB == 0.0f ? out.z : overlayB;
978 |
979 | }
980 | return out;
981 | }
982 |
983 | return out;
984 | }
985 |
--------------------------------------------------------------------------------
/ME_Filmic Contrast new curve.dctl:
--------------------------------------------------------------------------------
1 | #line 2
2 | //Flimic Contrast V1.1.1
3 |
4 |
5 | //functions for Transfer function conversion
6 | __DEVICE__ float3 LinToLogC3 (float3 in) {
7 | float3 out;
8 |
9 | float cut = 0.010591;
10 | float a = 5.555556;
11 | float b = 0.052272;
12 | float c = 0.247190;
13 | float d = 0.385537;
14 | float e = 5.367655;
15 | float f = 0.092809;
16 |
17 | out.x = (in.x > cut) ? c * log10(a * in.x + b) + d: e * in.x + f;
18 | out.y = (in.y > cut) ? c * log10(a * in.y + b) + d: e * in.y + f;
19 | out.z = (in.z > cut) ? c * log10(a * in.z + b) + d: e * in.z + f;
20 |
21 | return out;
22 | }
23 |
24 | __DEVICE__ float3 LogC3ToLin (float3 in) {
25 | float3 out;
26 |
27 | float cut = 0.010591;
28 | float a = 5.555556;
29 | float b = 0.052272;
30 | float c = 0.247190;
31 | float d = 0.385537;
32 | float e = 5.367655;
33 | float f = 0.092809;
34 |
35 | out.x = (in.x > e * cut + f) ? (_powf(10, (in.x - d) / c) - b) / a : (in.x - f) / e;
36 | out.y = (in.y > e * cut + f) ? (_powf(10, (in.y - d) / c) - b) / a : (in.y - f) / e;
37 | out.z = (in.z > e * cut + f) ? (_powf(10, (in.z - d) / c) - b) / a : (in.z - f) / e;
38 |
39 | return out;
40 | }//0
41 |
42 | __DEVICE__ float3 LinToDI (float3 in) {
43 | float3 out;
44 |
45 | float a = 0.0075;
46 | float b = 7.0;
47 | float c = 0.07329248;
48 | float m = 10.44426855;
49 | float lin_cut = 0.00262409;
50 |
51 | out.x = in.x > lin_cut ? (_log2f(in.x + a) + b) * c : out.x = in.x * m;
52 | out.y = in.y > lin_cut ? (_log2f(in.y + a) + b) * c : out.y = in.y * m;
53 | out.z = in.z > lin_cut ? (_log2f(in.z + a) + b) * c : out.z = in.z * m;
54 |
55 | return out;
56 | }
57 |
58 | __DEVICE__ float3 DItoLin (float3 in) {
59 | float3 out;
60 |
61 | float a = 0.0075;
62 | float b = 7.0;
63 | float c = 0.07329248;
64 | float m = 10.44426855;
65 | float log_cut = 0.02740668;
66 |
67 | out.x = in.x > log_cut ? _powf(2.f, (in.x / c) - b) - a : in.x / m;
68 | out.y = in.y > log_cut ? _powf(2.f, (in.y / c) - b) - a : in.y / m;
69 | out.z = in.z > log_cut ? _powf(2.f, (in.z / c) - b) - a : in.z / m;
70 |
71 | return out;
72 | }//2
73 |
74 | __DEVICE__ float3 LinToACEScct (float3 in) {
75 | float3 out;
76 |
77 | float a = 10.5402377416545;
78 | float b = 0.0729055341958355;
79 | float c = 9.72;
80 | float d = 17.52;
81 | float e = 0.0078125;
82 |
83 | out.x = in.x <= e ? a * in.x + b : (_log2f(in.x) + c) / d;
84 | out.y = in.y <= e ? a * in.y + b : (_log2f(in.y) + c) / d;
85 | out.z = in.z <= e ? a * in.z + b : (_log2f(in.z) + c) / d;
86 |
87 | return out;
88 | }
89 |
90 | __DEVICE__ float3 ACEScctToLin (float3 in) {
91 | float3 out;
92 |
93 | float a = 10.5402377416545;
94 | float b = 0.0729055341958355;
95 | float c = 9.72;
96 | float d = 17.52;
97 | float e = _log2f(65504);
98 | float lin_cut = 0.155251141552511;
99 |
100 | out.x = in.x <= lin_cut ? (in.x - b) / a : in.x < (e + c) / d ? _powf(2, in.x*d-c) : 65504;
101 | out.y = in.y <= lin_cut ? (in.y - b) / a : in.y < (e + c) / d ? _powf(2, in.y*d-c) : 65504;
102 | out.z = in.z <= lin_cut ? (in.z - b) / a : in.z < (e + c) / d ? _powf(2, in.z*d-c) : 65504;
103 |
104 | return out;
105 | }//3
106 |
107 | __DEVICE__ float3 LinToLogC4 (float3 in) {
108 | float3 out;
109 |
110 | float a = (_powf(2.0, 18.0) - 16.0) / 117.45;
111 | float b = (1023.0 - 95.0) / 1023.0;
112 | float c = 95.0 / 1023.0;
113 | float s = (7 * _logf(2) * _powf(2.0, 7 - 14 * c / b)) / (a * b);
114 | float t = (_powf(2.0, 14.0 * (-c / b) + 6.0) - 64.0) / a;
115 |
116 | out.x = in.x < t ? (in.x - t) / s : (_log2f( a * in.x + 64.0) - 6.0) / 14.0 * b + c;
117 | out.y = in.y < t ? (in.y - t) / s : (_log2f( a * in.y + 64.0) - 6.0) / 14.0 * b + c;
118 | out.z = in.z < t ? (in.z - t) / s : (_log2f( a * in.z + 64.0) - 6.0) / 14.0 * b + c;
119 |
120 | return out;
121 | }
122 |
123 | __DEVICE__ float3 LogC4ToLin (float3 in) {
124 | float3 out;
125 |
126 | float a = (_powf(2.0, 18.0) - 16.0) / 117.45;
127 | float b = (1023.0 - 95.0) / 1023.0;
128 | float c = 95.0 / 1023.0;
129 | float s = (7 * _logf(2) * _powf(2.0, 7 - 14 * c / b)) / (a * b);
130 | float t = (_powf(2.0, 14.0 * (-c / b) + 6.0) - 64.0) / a;
131 |
132 | out.x = in.x < 0.0 ? in.x * s + t : (_powf(2.0, 14.0 * (in.x - c) / b + 6.0) - 64.0) / a;
133 | out.y = in.y < 0.0 ? in.y * s + t : (_powf(2.0, 14.0 * (in.y - c) / b + 6.0) - 64.0) / a;
134 | out.z = in.z < 0.0 ? in.z * s + t : (_powf(2.0, 14.0 * (in.z - c) / b + 6.0) - 64.0) / a;
135 |
136 | return out;
137 | }//1
138 |
139 | __DEVICE__ float3 LinToDLog (float3 in) {
140 | float3 out;
141 |
142 | out.x = in.x <= 0.0078 ? 6.025 * in.x + 0.0929 : (_log10f(in.x * 0.9892 + 0.0108)) * 0.256663 + 0.584555;
143 | out.y = in.y <= 0.0078 ? 6.025 * in.y + 0.0929 : (_log10f(in.y * 0.9892 + 0.0108)) * 0.256663 + 0.584555;
144 | out.z = in.z <= 0.0078 ? 6.025 * in.z + 0.0929 : (_log10f(in.z * 0.9892 + 0.0108)) * 0.256663 + 0.584555;
145 |
146 | return out;
147 | }
148 |
149 | __DEVICE__ float3 DLogToLin (float3 in) {
150 | float3 out;
151 |
152 | out.x = in.x <= 0.14 ? (in.x - 0.0929) / 6.025 : (_powf(10, 3.89616 * in.x - 2.27752) - 0.0108) / 0.9892;
153 | out.y = in.y <= 0.14 ? (in.y - 0.0929) / 6.025 : (_powf(10, 3.89616 * in.y - 2.27752) - 0.0108) / 0.9892;
154 | out.z = in.z <= 0.14 ? (in.z - 0.0929) / 6.025 : (_powf(10, 3.89616 * in.z - 2.27752) - 0.0108) / 0.9892;
155 |
156 | return out;
157 | }
158 |
159 | __DEVICE__ float3 LinToFLog (float3 in) {
160 | float3 out;
161 |
162 | float a = 0.555556;
163 | float b = 0.009468;
164 | float c = 0.344676;
165 | float d = 0.790453;
166 | float e = 8.735631;
167 | float f = 0.092864;
168 | float cut = 0.00089;
169 |
170 | out.x = in.x >= cut ? c * _log10f(a * in.x + b) + d : e * in.x + f;
171 | out.y = in.y >= cut ? c * _log10f(a * in.y + b) + d : e * in.y + f;
172 | out.z = in.z >= cut ? c * _log10f(a * in.z + b) + d : e * in.z + f;
173 |
174 | return out;
175 | }
176 |
177 | __DEVICE__ float3 FLogToLin (float3 in) {
178 | float3 out;
179 |
180 | float a = 0.555556;
181 | float b = 0.009468;
182 | float c = 0.344676;
183 | float d = 0.790453;
184 | float e = 8.735631;
185 | float f = 0.092864;
186 | float cut = 0.100537775223865;
187 |
188 | out.x = in.x >= cut ? _powf(10, ((in.x - d) / c)) / a - b / a : (in.x - f) / e;
189 | out.y = in.y >= cut ? _powf(10, ((in.y - d) / c)) / a - b / a : (in.y - f) / e;
190 | out.z = in.z >= cut ? _powf(10, ((in.z - d) / c)) / a - b / a : (in.z - f) / e;
191 |
192 | return out;
193 | }
194 |
195 | __DEVICE__ float3 LinToFLog2 (float3 in) {
196 | float3 out;
197 |
198 | float a = 5.555556;
199 | float b = 0.064829;
200 | float c = 0.245281;
201 | float d = 0.384316;
202 | float e = 8.799461;
203 | float f = 0.092864;
204 | float cut = 0.000889;
205 |
206 | out.x = in.x >= cut ? c * _log10f(a * in.x + b) + d : e * in.x + f;
207 | out.y = in.y >= cut ? c * _log10f(a * in.y + b) + d : e * in.y + f;
208 | out.z = in.z >= cut ? c * _log10f(a * in.z + b) + d : e * in.z + f;
209 |
210 | return out;
211 | }
212 |
213 | __DEVICE__ float3 FLog2ToLin (float3 in) {
214 | float3 out;
215 |
216 | float a = 5.555556;
217 | float b = 0.064829;
218 | float c = 0.245281;
219 | float d = 0.384316;
220 | float e = 8.799461;
221 | float f = 0.092864;
222 | float cut = 0.100686685370811;
223 |
224 | out.x = in.x >= cut ? _powf(10, ((in.x - d) / c)) / a - b / a : (in.x - f) / e;
225 | out.y = in.y >= cut ? _powf(10, ((in.y - d) / c)) / a - b / a : (in.y - f) / e;
226 | out.z = in.z >= cut ? _powf(10, ((in.z - d) / c)) / a - b / a : (in.z - f) / e;
227 |
228 | return out;
229 | }
230 |
231 | __DEVICE__ float3 LinToVLog (float3 in) {
232 | float3 out;
233 |
234 | float cut = 0.01;
235 | float b = 0.00873;
236 | float c = 0.241514;
237 | float d = 0.598206;
238 |
239 | out.x = in.x < cut ? 5.6 * in.x + 0.125 : c * _log10f(in.x + b) + d;
240 | out.y = in.y < cut ? 5.6 * in.y + 0.125 : c * _log10f(in.y + b) + d;
241 | out.z = in.z < cut ? 5.6 * in.z + 0.125 : c * _log10f(in.z + b) + d;
242 |
243 | return out;
244 | }
245 |
246 | __DEVICE__ float3 VLogToLin (float3 in) {
247 | float3 out;
248 |
249 | float cut = 0.181;
250 | float b = 0.00873;
251 | float c = 0.241514;
252 | float d = 0.598206;
253 |
254 | out.x = in.x < cut ? (in.x - 0.125) / 5.6 : _powf(10.0, ((in.x - d) / c)) - b;
255 | out.y = in.y < cut ? (in.y - 0.125) / 5.6 : _powf(10.0, ((in.y - d) / c)) - b;
256 | out.z = in.z < cut ? (in.z - 0.125) / 5.6 : _powf(10.0, ((in.z - d) / c)) - b;
257 |
258 | return out;
259 | }
260 |
261 | __DEVICE__ float3 LinToLog3G10 (float3 in) {
262 | float3 out;
263 |
264 | float a = 0.224282f;
265 | float b = 155.975327f;
266 | float c = 0.01f;
267 | float g = 15.1927f;
268 |
269 | in.x += c;
270 | in.y += c;
271 | in.z += c;
272 |
273 | out.x = in.x < 0.0f ? in.x * g : a * _log10f((in.x * b) + 1.0f);
274 | out.y = in.y < 0.0f ? in.y * g : a * _log10f((in.y * b) + 1.0f);
275 | out.z = in.z < 0.0f ? in.z * g : a * _log10f((in.z * b) + 1.0f);
276 |
277 | return out;
278 | }
279 |
280 | __DEVICE__ float3 Log3G10toLin (float3 in) {
281 | float3 out;
282 |
283 | float a = 0.224282f;
284 | float b = 155.975327f;
285 | float c = 0.01f;
286 | float g = 15.1927f;
287 |
288 | out.x = in.x < 0.0f ? (in.x / g) - c : (_powf(10.0f, in.x / a) - 1.0f) / b;
289 | out.y = in.y < 0.0f ? (in.y / g) - c : (_powf(10.0f, in.y / a) - 1.0f) / b;
290 | out.z = in.z < 0.0f ? (in.z / g) - c : (_powf(10.0f, in.z / a) - 1.0f) / b;
291 |
292 | out.x -= c;
293 | out.y -= c;
294 | out.z -= c;
295 |
296 | return out;
297 | }
298 |
299 | __DEVICE__ float3 LinToSLog3 (float3 in) {
300 | float3 out;
301 |
302 | out.x = in.x >= 0.01125000 ? (420.0 + _log10f((in.x + 0.01) / (0.18 + 0.01)) * 261.5) / 1023.0 : (in.x * (171.2102946929 - 95.0)/0.01125000 + 95.0) / 1023.0;
303 | out.y = in.y >= 0.01125000 ? (420.0 + _log10f((in.y + 0.01) / (0.18 + 0.01)) * 261.5) / 1023.0 : (in.y * (171.2102946929 - 95.0)/0.01125000 + 95.0) / 1023.0;
304 | out.z = in.z >= 0.01125000 ? (420.0 + _log10f((in.z + 0.01) / (0.18 + 0.01)) * 261.5) / 1023.0 : (in.z * (171.2102946929 - 95.0)/0.01125000 + 95.0) / 1023.0;
305 |
306 | return out;
307 | }
308 |
309 | __DEVICE__ float3 SLog3ToLin (float3 in) {
310 | float3 out;
311 |
312 | out.x = in.x >= 171.2102946929 / 1023.0 ? (_powf(10.0, ((in.x * 1023.0 - 420.0) / 261.5))) * (0.18 + 0.01) - 0.01 : (in.x * 1023.0 - 95.0) * 0.01125000 / (171.2102946929 - 95.0);
313 | out.y = in.y >= 171.2102946929 / 1023.0 ? (_powf(10.0, ((in.y * 1023.0 - 420.0) / 261.5))) * (0.18 + 0.01) - 0.01 : (in.y * 1023.0 - 95.0) * 0.01125000 / (171.2102946929 - 95.0);
314 | out.z = in.z >= 171.2102946929 / 1023.0 ? (_powf(10.0, ((in.z * 1023.0 - 420.0) / 261.5))) * (0.18 + 0.01) - 0.01 : (in.z * 1023.0 - 95.0) * 0.01125000 / (171.2102946929 - 95.0);
315 |
316 | return out;
317 | }
318 |
319 | __DEVICE__ float3 LinToBMDFilmGen5(float3 in) {
320 | float3 out;
321 |
322 | float a = 8.283605932402494f;
323 | float b = 0.09246575342465753f;
324 | float c = 0.5300133392291939f;
325 | float d = 0.08692876065491224f;
326 | float e = 0.005494072432257808f;
327 | float cut = 0.005f;
328 |
329 | out.x = in.x < cut ? a * in.x + b : d * _logf(in.x + e) + c;
330 | out.y = in.y < cut ? a * in.y + b : d * _logf(in.y + e) + c;
331 | out.z = in.z < cut ? a * in.z + b : d * _logf(in.z + e) + c;
332 |
333 | return out;
334 | }
335 |
336 | __DEVICE__ float3 BMDFilmGen5ToLin(float3 in) {
337 | float3 out;
338 |
339 | float a = 8.283605932402494f;
340 | float b = 0.09246575342465753f;
341 | float c = 0.5300133392291939f;
342 | float d = 0.08692876065491224f;
343 | float e = 0.005494072432257808f;
344 | float cut = a * 0.005f + b;
345 |
346 | out.x = in.x < (a * 0.005f + b) ? (in.x - b) / a : _expf((in.x - c) / d) - e;
347 | out.y = in.y < (a * 0.005f + b) ? (in.y - b) / a : _expf((in.y - c) / d) - e;
348 | out.z = in.z < (a * 0.005f + b) ? (in.z - b) / a : _expf((in.z - c) / d) - e;
349 |
350 | return out;
351 | }
352 |
353 | __DEVICE__ float3 LinToCLog (float3 in) {
354 | float3 out;
355 |
356 | out.x = in.x < 0 ? -.529136 * _log10f(1 - 10.1596 * in.x) + 0.0730597 : .529136 * _log10f(10.1596 * in.x + 1) + 0.0730597;
357 | out.y = in.y < 0 ? -.529136 * _log10f(1 - 10.1596 * in.y) + 0.0730597 : .529136 * _log10f(10.1596 * in.y + 1) + 0.0730597;
358 | out.z = in.z < 0 ? -.529136 * _log10f(1 - 10.1596 * in.z) + 0.0730597 : .529136 * _log10f(10.1596 * in.z + 1) + 0.0730597;
359 |
360 | return out;
361 | }
362 |
363 | __DEVICE__ float3 CLogToLin (float3 in) {
364 | float3 out;
365 |
366 | out.x = in.x < 0.0730597 ? -(_powf(10, (0.0730597 - in.x) / .529136) - 1) / 10.1596 : (_powf(10, (in.x - 0.0730597) / .529136) - 1) / 10.1596;
367 | out.y = in.y < 0.0730597 ? -(_powf(10, (0.0730597 - in.y) / .529136) - 1) / 10.1596 : (_powf(10, (in.y - 0.0730597) / .529136) - 1) / 10.1596;
368 | out.z = in.z < 0.0730597 ? -(_powf(10, (0.0730597 - in.z) / .529136) - 1) / 10.1596 : (_powf(10, (in.z - 0.0730597) / .529136) - 1) / 10.1596;
369 |
370 | return out;
371 | }
372 |
373 | __DEVICE__ float3 LinToCLog2 (float3 in) {
374 | float3 out;
375 |
376 | out.x = in.x < 0 ? -0.24136077 * _log10f(1 - 87.099375 * in.x) + 0.092864125 : 0.24136077 * _log10f(87.099375 * in.x + 1) + 0.092864125;
377 | out.y = in.y < 0 ? -0.24136077 * _log10f(1 - 87.099375 * in.y) + 0.092864125 : 0.24136077 * _log10f(87.099375 * in.y + 1) + 0.092864125;
378 | out.z = in.z < 0 ? -0.24136077 * _log10f(1 - 87.099375 * in.z) + 0.092864125 : 0.24136077 * _log10f(87.099375 * in.z + 1) + 0.092864125;
379 |
380 | return out;
381 | }
382 |
383 | __DEVICE__ float3 CLog2ToLin (float3 in) {
384 | float3 out;
385 |
386 | out.x = in.x < 0.092864125 ? -(_powf(10, (0.092864125 - in.x) / 0.24136077) - 1) / 87.099375 : (_powf(10, (in.x - 0.092864125) / 0.24136077) - 1) / 87.099375;
387 | out.y = in.y < 0.092864125 ? -(_powf(10, (0.092864125 - in.y) / 0.24136077) - 1) / 87.099375 : (_powf(10, (in.y - 0.092864125) / 0.24136077) - 1) / 87.099375;
388 | out.z = in.z < 0.092864125 ? -(_powf(10, (0.092864125 - in.z) / 0.24136077) - 1) / 87.099375 : (_powf(10, (in.z - 0.092864125) / 0.24136077) - 1) / 87.099375;
389 |
390 | return out;
391 | }
392 |
393 | __DEVICE__ float3 LinToCLog3 (float3 in) {
394 | float3 out;
395 |
396 | out.x = in.x < -0.014 ? -0.36726845 * _log10f(1 - 14.98325 * in.x) + 0.12783901 : in.x <= 0.014 ? 1.9754798 * in.x + 0.12512219 : 0.36726845 * _log10f(14.98325 * in.x + 1) + 0.12240537;
397 | out.y = in.y < -0.014 ? -0.36726845 * _log10f(1 - 14.98325 * in.y) + 0.12783901 : in.y <= 0.014 ? 1.9754798 * in.y + 0.12512219 : 0.36726845 * _log10f(14.98325 * in.y + 1) + 0.12240537;
398 | out.z = in.z < -0.014 ? -0.36726845 * _log10f(1 - 14.98325 * in.z) + 0.12783901 : in.z <= 0.014 ? 1.9754798 * in.z + 0.12512219 : 0.36726845 * _log10f(14.98325 * in.z + 1) + 0.12240537;
399 |
400 | return out;
401 | }
402 |
403 | __DEVICE__ float3 CLog3ToLin (float3 in) {
404 | float3 out;
405 |
406 | out.x = in.x < 0.097465473 ? -(_powf(10, (0.12783901 - in.x) / 0.36726845) - 1) / 14.98325 : in.x <= 0.15277891 ? (in.x - 0.12512219) / 1.9754798 : (_powf(10, (in.x - 0.12240537) / 0.36726845) - 1) / 14.98325;
407 | out.y = in.y < 0.097465473 ? -(_powf(10, (0.12783901 - in.y) / 0.36726845) - 1) / 14.98325 : in.y <= 0.15277891 ? (in.y - 0.12512219) / 1.9754798 : (_powf(10, (in.y - 0.12240537) / 0.36726845) - 1) / 14.98325;
408 | out.z = in.z < 0.097465473 ? -(_powf(10, (0.12783901 - in.z) / 0.36726845) - 1) / 14.98325 : in.z <= 0.15277891 ? (in.z - 0.12512219) / 1.9754798 : (_powf(10, (in.z - 0.12240537) / 0.36726845) - 1) / 14.98325;
409 |
410 | return out;
411 | }
412 |
413 |
414 | __DEVICE__ float3 GammaCurveToLin (float3 in, float gamma) {
415 | float3 out;
416 |
417 | out.x = _powf(_fmaxf(in.x, 0.0f), gamma);
418 | out.y = _powf(_fmaxf(in.y, 0.0f), gamma);
419 | out.z = _powf(_fmaxf(in.z, 0.0f), gamma);
420 |
421 | return out;
422 | }
423 |
424 | __DEVICE__ float3 LinToGammaCurve (float3 in, float gamma) {
425 | float3 out;
426 |
427 | out.x = _powf(_fmaxf(in.x, 0.0f), (1 / gamma));
428 | out.y = _powf(_fmaxf(in.y, 0.0f), (1 / gamma));
429 | out.z = _powf(_fmaxf(in.z, 0.0f), (1 / gamma));
430 |
431 | return out;
432 | }
433 |
434 |
435 | //functions that convert between color models
436 |
437 | __DEVICE__ float3 RGB_to_HSV(float3 RGB) {
438 | float3 HSV;
439 | float min = _fminf(_fminf(RGB.x, RGB.y), RGB.z);
440 | float max = _fmaxf(_fmaxf(RGB.x, RGB.y), RGB.z);
441 | HSV.z = max;
442 | float delta = max - min;
443 | if (max != 0.0f) {
444 | HSV.y = delta / max;
445 | } else {
446 | HSV.y = 0.0f;
447 | HSV.x = 0.0f;
448 | return HSV;
449 | }
450 | if (delta == 0.0f) {
451 | HSV.x = 0.0f;
452 | } else if (RGB.x == max) {
453 | HSV.x = (RGB.y - RGB.z) / delta;
454 | } else if (RGB.y == max) {
455 | HSV.x = 2.0f + (RGB.z - RGB.x) / delta;
456 | } else {
457 | HSV.x = 4.0f + (RGB.x - RGB.y) / delta;
458 | }
459 | HSV.x *= 1.0f / 6.0f;
460 | if (HSV.x < 0.0f)
461 | HSV.x += 1.0f;
462 | return HSV;
463 | } //Convert to HSV
464 |
465 | __DEVICE__ float3 HSV_to_RGB(float3 HSV) {
466 | float3 RGB;
467 | if (HSV.y == 0.0f) {
468 | RGB.x = RGB.y = RGB.z = HSV.z;
469 | } else {
470 | HSV.x *= 6.0f;
471 | int i = floor(HSV.x);
472 | float f = HSV.x - i;
473 | i = (i >= 0) ? (i % 6) : (i % 6) + 6;
474 | float p = HSV.z * (1.0f - HSV.y);
475 | float q = HSV.z * (1.0f - HSV.y * f);
476 | float t = HSV.z * (1.0f - HSV.y * (1.0f - f));
477 | RGB.x = i == 0 ? HSV.z : i == 1 ? q : i == 2 ? p : i == 3 ? p : i == 4 ? t : HSV.z;
478 | RGB.y = i == 0 ? t : i == 1 ? HSV.z : i == 2 ? HSV.z : i == 3 ? q : i == 4 ? p : p;
479 | RGB.z = i == 0 ? p : i == 1 ? p : i == 2 ? t : i == 3 ? HSV.z : i == 4 ? HSV.z : q;
480 | }
481 | return RGB;
482 | } //Convert from HSV to RGB
483 |
484 | __DEVICE__ float3 RGB_to_cone(float3 rgb) {
485 | const float pi= 3.14159265359f;
486 | const float rtr = rgb.x * 0.81649658f + rgb.y * -0.40824829f + rgb.z * -0.40824829f;
487 | const float rtg = rgb.x * 0.0f + rgb.y * 0.70710678f + rgb.z * -0.70710678f;
488 | const float rtb = rgb.x * 0.57735027f + rgb.y * 0.57735027f + rgb.z * 0.57735027f;
489 |
490 | const float art = _atan2f(rtg, rtr);
491 |
492 | const float sphr = _sqrtf(rtr*rtr + rtg*rtg + rtb*rtb);
493 | const float spht = art < 0.0f ? art + 2.0f * 3.141592653589f : art;
494 | const float sphp = _atan2f(_sqrtf(rtr*rtr + rtg*rtg), rtb);
495 |
496 | //This is to modify the lum component which is the main reason why the saturation component has a different behavior
497 | const float huecoef1= 1.0f/(2.0f-(0.78539816f/0.61547971f));
498 | const float huecoef2 = 2.0f*sphp*_sinf((2.0f*pi/3.0f)-_fmod(spht,(pi/3.0f)))/1.7320508075688f;
499 | const float huemag =((_acosf(_cosf(3.0f*spht+pi)))/(pi*huecoef1)+(((0.78539816f/0.61547971f))-1.0f))*huecoef2;
500 | const float satmag = _sinf(huemag+0.61547971f);
501 |
502 |
503 |
504 | return make_float3(
505 | sphr*satmag,
506 | spht * 0.15915494309189535f,
507 | sphp * 1.0467733744265997f
508 | );
509 | } //Convert to cone cordinates by Juan Pablo Zambrano
510 |
511 | __DEVICE__ float3 cone_to_RGB(float3 sph) {
512 |
513 | const float pi= 3.14159265359f;
514 | sph.y *= 6.283185307179586f;
515 | sph.z *= 0.9553166181245093f;
516 | const float huecoef1= 1.0f/(2.0f-(0.78539816f/0.61547971f));
517 | const float huecoef2 = 2.0f*sph.z*_sinf((2.0f*pi/3.0f)- _fmod(sph.y,(pi/3.0f)))/1.7320508075688f;
518 | const float huemag =((_acosf(_cosf(3.0f*sph.y+pi)))/(pi*huecoef1)+(((0.78539816f/0.61547971f))-1.0f))*huecoef2;
519 | const float satmagsp = _sinf(huemag+0.61547971f);
520 | sph.x *= 1.0f/satmagsp;
521 |
522 | const float ctr = sph.x * _sinf(sph.z) * _cosf(sph.y);
523 | const float ctg = sph.x * _sinf(sph.z) * _sinf(sph.y);
524 | const float ctb = sph.x * _cosf(sph.z);
525 |
526 | return make_float3(
527 | ctr * 0.81649658f + ctg * 0.0f + ctb * 0.57735027f,
528 | ctr * -0.40824829f + ctg * 0.70710678f + ctb * 0.57735027f,
529 | ctr * -0.40824829f + ctg * -0.70710678f + ctb * 0.57735027f
530 | );
531 | } // convert from cone to RGB
532 |
533 | __DEVICE__ float3 RGBtoCHEN(float3 in) {
534 | float r = in.x;
535 | float g = in.y;
536 | float b = in.z;
537 |
538 | float h;
539 | float c;
540 | float l;
541 |
542 | const float rtr = r * 0.81649658f + g * -0.40824829f + b * -0.40824829f;
543 | const float rtg = r * 0.0f + g * 0.70710678f + b * -0.70710678f;
544 | const float rtb = r * 0.57735027f + g * 0.57735027f + b * 0.57735027f;
545 |
546 | const float art = _atan2f(rtg, rtr);
547 |
548 | const float sphr = _sqrtf(rtr*rtr + rtg*rtg + rtb*rtb);
549 | const float spht = art < 0.0f ? art + 2.0f * 3.141592653589f : art;
550 | const float sphp = _atan2f(_sqrtf(rtr*rtr + rtg*rtg), rtb);
551 |
552 | l = sphr * 0.5773502691896258f;
553 | h = spht * 0.15915494309189535f;
554 | c = sphp * 1.0467733744265997f;
555 |
556 | return make_float3(h, c, l);
557 | } //by Kaur Hendrikson
558 |
559 | __DEVICE__ float3 CHENtoRGB(float3 in) {
560 | float h = in.x * 6.283185307179586f;
561 | float c = in.y * 0.9553166181245093f;
562 | float l = in.z * 1.7320508075688772f;
563 |
564 | float r = 0;
565 | float g = 0;
566 | float b = 0;
567 |
568 | const float ctr = l * _sinf(c) * _cosf(h);
569 | const float ctg = l * _sinf(c) * _sinf(h);
570 | const float ctb = l * _cosf(c);
571 |
572 | r = ctr * 0.81649658f + ctg * 0.0f + ctb * 0.57735027f;
573 | g = ctr * -0.40824829f + ctg * 0.70710678f + ctb * 0.57735027f;
574 | b = ctr * -0.40824829f + ctg * -0.70710678f + ctb * 0.57735027f;
575 |
576 | return make_float3(r, g, b);
577 | } //by Kaur Hendrikson
578 |
579 |
580 |
581 | // Helper functions
582 |
583 | __DEVICE__ float powf(float base, float exp) {
584 | return _copysignf(_powf(_fabs(base), exp), base);
585 | }
586 |
587 | __DEVICE__ float pow2f(float base) {
588 | return _powf(_fabs(base), 2.0);
589 | }
590 |
591 | __DEVICE__ float maxf3(float3 x) {
592 | return _fmaxf(_fmaxf(x.x, x.y), x.z);
593 | }
594 |
595 | __DEVICE__ float minf3(float3 x) {
596 | return _fminf(_fminf(x.x, x.y), x.z);
597 | }
598 |
599 | __DEVICE__ float3 powf3(float3 base, float exp) {
600 | return make_float3(powf(base.x, exp), powf(base.y, exp), powf(base.z, exp));
601 | }
602 |
603 |
604 |
605 | //functions to apply transfer function conversions
606 |
607 | __DEVICE__ float3 GammaToLin (float3 in, int gamma) {
608 |
609 | if (gamma == 0) return LogC3ToLin(in);
610 | if (gamma == 1) return LogC4ToLin(in);
611 | if (gamma == 2) return DItoLin(in);
612 | if (gamma == 3) return ACEScctToLin (in);
613 | if (gamma == 4) return Log3G10toLin(in);
614 | if (gamma == 5) return SLog3ToLin(in);
615 | if (gamma == 6) return BMDFilmGen5ToLin(in);
616 | if (gamma == 7) return CLog3ToLin(in);
617 | if (gamma == 8) return DLogToLin(in);
618 | if (gamma == 9) return FLogToLin(in);
619 | if (gamma == 10) return FLog2ToLin(in);
620 | if (gamma == 11) return VLogToLin(in);
621 | if (gamma == 12) return GammaCurveToLin(in, 2.2);
622 | if (gamma == 13) return GammaCurveToLin(in, 2.4);
623 | if (gamma == 14) return GammaCurveToLin(in, 2.6);
624 | if (gamma == 15) return in; // Lin
625 |
626 |
627 | return make_float3(0, 0, 1); // Blue on error
628 | }
629 |
630 | __DEVICE__ float3 LinToGamma (float3 in, int gamma) {
631 | if (gamma == 0) return LinToLogC3(in);
632 | if (gamma == 1) return LinToLogC4(in);
633 | if (gamma == 2) return LinToDI(in);
634 | if (gamma == 3) return LinToACEScct(in);
635 | if (gamma == 4) return LinToLog3G10(in);
636 | if (gamma == 5) return LinToSLog3(in);
637 | if (gamma == 6) return LinToBMDFilmGen5(in);
638 | if (gamma == 7) return LinToCLog3(in);
639 | if (gamma == 8) return LinToDLog(in);
640 | if (gamma == 9) return LinToFLog(in);
641 | if (gamma == 10) return LinToFLog2(in);
642 | if (gamma == 11) return LinToVLog(in);
643 | if (gamma == 12) return LinToGammaCurve(in, 2.2);
644 | if (gamma == 13) return LinToGammaCurve(in, 2.4);
645 | if (gamma == 14) return LinToGammaCurve(in, 2.6);
646 | if (gamma == 15) return in; // Lin
647 |
648 |
649 |
650 | return make_float3(0, 1, 0); // Green on error
651 | }
652 |
653 | __DEVICE__ float set_pivot (float pivot, int gamma) {
654 | float p_transfer_f = gamma;
655 | float midgray;
656 | const float logc3_gray = 0.39101f;
657 | const float logc4_gray = 0.2784f;
658 | const float DI_gray = 0.33604f;
659 | const float ACEScct_gray = 0.41359f;
660 | const float log3g10_gray = 0.3333f;
661 | const float slog3_gray = 0.41056f;
662 | const float bmd_f5_gray = 0.38356f;
663 | const float clog3_gray = 0.34339f;
664 | const float dlog_gray = 0.39876f;
665 | const float fLog_gray = 0.45932f;
666 | const float fLog2_gray = 0.39101f;
667 | const float vlog_gray = 0.42331f;
668 | const float g22_gray = 0.45866f;
669 | const float g24_gray = 0.48944f;
670 | const float g26_gray = 0.51709f;
671 | const float linear_gray = 0.18f;
672 |
673 | if (p_transfer_f == 0) { midgray = logc3_gray;}
674 | if (p_transfer_f == 1) { midgray = logc4_gray; }
675 | if (p_transfer_f == 2) { midgray = DI_gray;}
676 | if (p_transfer_f == 3) { midgray = ACEScct_gray;}
677 | if (p_transfer_f == 4) { midgray = log3g10_gray;}
678 | if (p_transfer_f == 5) { midgray = slog3_gray;}
679 | if (p_transfer_f == 6) { midgray = bmd_f5_gray;}
680 | if (p_transfer_f == 7) { midgray = clog3_gray;}
681 | if (p_transfer_f == 8) { midgray = dlog_gray;}
682 | if (p_transfer_f == 9) { midgray = fLog_gray;}
683 | if (p_transfer_f == 10) { midgray = fLog2_gray;}
684 | if (p_transfer_f == 11) { midgray = vlog_gray;}
685 | if (p_transfer_f == 12) { midgray = g22_gray;}
686 | if (p_transfer_f == 13) { midgray = g24_gray;}
687 | if (p_transfer_f == 14) { midgray = g26_gray;}
688 | if (p_transfer_f == 15) { midgray = linear_gray;}
689 |
690 | float3 get_mid = make_float3(0.18f, 0.18f,0.18f);
691 | get_mid = LinToGamma(get_mid, p_transfer_f);
692 | //get_mid = maxf3(get_mid);
693 | midgray = get_mid.x;
694 |
695 | pivot = _clampf(( pivot + midgray), 0.02f, 1.0f); //clamping to 0 caused artifacts
696 |
697 | return pivot;
698 | }
699 |
700 |
701 |
702 |
703 |
704 | //functions for the main functionality of contrast and split toning
705 |
706 | __DEVICE__ float apply_linear_contrast (float in, float contrast, float pivot) {
707 |
708 | float out = in;
709 | //offsetting the user slider to set the starting point at zero
710 | contrast = contrast+1;
711 | //limit user input to zero
712 | if (contrast <0) {contrast = _fmaxf(contrast, 0.0f);}
713 |
714 | out = (in - pivot) * contrast + pivot;
715 |
716 |
717 | return out;
718 | }
719 |
720 | __DEVICE__ float3 apply_linear_contrastf3 (float3 in, float contrast, float pivot) {
721 | float3 out = in;
722 |
723 | out.x = apply_linear_contrast (out.x, contrast, pivot);
724 | out.y = apply_linear_contrast (out.y, contrast, pivot);
725 | out.z = apply_linear_contrast (out.z, contrast, pivot);
726 |
727 | return out;
728 | }
729 |
730 | __DEVICE__ float3 apply_rolling_contrastf3 (float3 in, float contrast, float pivot) {
731 |
732 | float3 out = in;
733 | //offsett the user slider to set the starting point at zero instead of 1
734 | contrast = contrast + 1.f;
735 |
736 | // apply rolling contrast
737 | if (in.x <= pivot) {out.x = powf((in.x / pivot) , contrast) * pivot;}
738 | if (in.x > pivot) {
739 | in.x = 1 - in.x;
740 | pivot = 1 - pivot;
741 | out.x = powf((in.x / pivot) , contrast) * pivot;
742 | out.x = 1 - out.x;
743 | pivot = 1 - pivot;
744 | }
745 |
746 | if (in.y <= pivot ) {out.y = powf((in.y / pivot) , contrast) * pivot;}
747 | if (in.y > pivot) {
748 | in.y = 1 - in.y;
749 | pivot = 1 - pivot;
750 | out.y = powf((in.y / pivot) , contrast) * pivot;
751 | out.y = 1 - out.y;
752 | pivot = 1 - pivot;
753 | }
754 |
755 | if (in.z <= pivot) {out.z = powf((in.z / pivot) , contrast) * pivot;}
756 |
757 | if (in.z > pivot) {
758 | in.z = 1 - in.z;
759 | pivot = 1 - pivot;
760 | out.z = powf((in.z / pivot) , contrast) * pivot;
761 | out.z = 1 - out.z;
762 | pivot = 1 - pivot;
763 | }
764 |
765 | return out;
766 |
767 | }
768 |
769 | __DEVICE__ float3 apply_white_point (float3 in, float white_point, float pivot, float shoulder_strength) {
770 |
771 | float3 out = in;
772 | float scale_factor;
773 |
774 | if (in.x > pivot) {
775 | scale_factor = (1.0f - pivot) / _powf(_powf((white_point - pivot) / (1.0f - pivot), -1.0f*shoulder_strength) - 1.0f, 1.0f/shoulder_strength);
776 |
777 | out.x = pivot + scale_factor *((in.x - pivot) / scale_factor) / (_powf(1.0f + _powf((in.x - pivot) / scale_factor, shoulder_strength), 1.0f / shoulder_strength));
778 |
779 | }
780 |
781 | else {
782 |
783 | out.x = in.x;
784 |
785 | }
786 |
787 | if (in.y > pivot) {
788 | scale_factor = (1.0f - pivot) / _powf(_powf((white_point - pivot) / (1.0f - pivot), -1.0f*shoulder_strength) - 1.0f, 1.0f/shoulder_strength);
789 |
790 | out.y = pivot + scale_factor *((in.y - pivot) / scale_factor) / (_powf(1.0f + _powf((in.y - pivot) / scale_factor, shoulder_strength), 1.0f / shoulder_strength));
791 |
792 | }
793 |
794 | else {
795 |
796 | out.y = in.y;
797 |
798 | }
799 |
800 | if (in.z > pivot) {
801 | scale_factor = (1.0f - pivot) / _powf(_powf((white_point - pivot) / (1.0f - pivot), -1.0f*shoulder_strength) - 1.0f, 1.0f/shoulder_strength);
802 |
803 | out.z = pivot + scale_factor *((in.z - pivot) / scale_factor) / (_powf(1.0f + _powf((in.z - pivot) / scale_factor, shoulder_strength), 1.0f / shoulder_strength));
804 |
805 | }
806 |
807 | else {
808 |
809 | out.z = in.z;
810 |
811 | }
812 |
813 | return out;
814 |
815 | }
816 |
817 | __DEVICE__ float3 apply_black_point (float3 in, float black_point, float pivot, float toe_str) {
818 |
819 | float3 out = in;
820 |
821 | in.x = 1.0f - in.x;
822 | in.y = 1.0f - in.y ;
823 | in.z = 1.0f - in.z ;
824 |
825 | float scale_factor;
826 |
827 | if (in.x > pivot) {
828 | scale_factor = (1.0f - pivot) / _powf(_powf((black_point - pivot) / (1.0f - pivot), -1.0f*toe_str) - 1.0f, 1.0f/toe_str);
829 |
830 | out.x = pivot + scale_factor *((in.x - pivot) / scale_factor) / (_powf(1.0f + _powf((in.x - pivot) / scale_factor, toe_str), 1.0f / toe_str));
831 | }
832 |
833 | else {
834 |
835 | out.x = in.x;
836 |
837 | }
838 |
839 | if (in.y > pivot) {
840 |
841 | scale_factor = (1.0f - pivot) / _powf(_powf((black_point - pivot) / (1.0f - pivot), -1.0f*toe_str) - 1.0f, 1.0f/toe_str);
842 |
843 | out.y = pivot + scale_factor *((in.y - pivot) / scale_factor) / (_powf(1.0f + _powf((in.y - pivot) / scale_factor, toe_str), 1.0f / toe_str));
844 |
845 | }
846 |
847 | else {
848 |
849 | out.y = in.y;
850 |
851 | }
852 |
853 | if (in.z > pivot) {
854 | scale_factor = (1.0f - pivot) / _powf(_powf((black_point - pivot) / (1.0f - pivot), -1.0f*toe_str) - 1.0f, 1.0f/toe_str);
855 |
856 | out.z = pivot + scale_factor *((in.z - pivot) / scale_factor) / (_powf(1.0f + _powf((in.z - pivot) / scale_factor, toe_str), 1.0f / toe_str));
857 |
858 | }
859 |
860 | else {
861 |
862 | out.z = in.z;
863 |
864 | }
865 |
866 | out.x = 1 - out.x;
867 | out.y = 1 - out.y;
868 | out.z = 1 - out.z;
869 |
870 | return out;
871 |
872 | }
873 |
874 |
875 | __DEVICE__ float apply_contrast_curve (float input, float contrast, float pivot, float white, float black, float shoulder, float toe) {
876 |
877 | float output = input;
878 |
879 | //params
880 | float p_slope = contrast;
881 | float p_ls = shoulder;
882 | float P_lt = toe;
883 |
884 | //pivot
885 | float P_ivx = pivot;
886 | float P_ivy = pivot;
887 |
888 | // control point shoulder
889 | float p_sx = (p_ls/_sqrtf((powf(p_slope , 2)+1))) + P_ivx;
890 | float p_sy = ((p_slope * p_ls)/_sqrtf((powf(p_slope ,2)+1))) + P_ivy;
891 |
892 | // white
893 | float p_wx = 1.2f;
894 | float p_wy = white;
895 | //if (p_transfer_f == 15) {
896 | // p_wy = white * 2.0f;
897 | // p_wx = 2.0f;}
898 | //control point toe
899 | float p_tx = ((-1 * P_lt)/_sqrtf(powf(p_slope , 2)+1)) + P_ivx;
900 | float p_ty = ((-1 * p_slope * P_lt)/_sqrtf(powf(p_slope, 2)+1)) + P_ivy;
901 |
902 | //black
903 | float p_bx = 0.0f;
904 | float p_by = black;
905 |
906 | //sanitize user parameters
907 |
908 | //shoulder = _fminf(shoulder, pivot );
909 | //toe = _fminf(toe, pivot );
910 | //white = _fmaxf(white, shoulder);
911 |
912 | //Slope Intercept Form of Linear Segment
913 |
914 | float m = (p_sy - p_ty) / (p_sx - p_tx);
915 | float b = p_ty - p_tx * m;
916 | float f_lin = input * m + b;
917 |
918 | //inverse
919 | //float f_ilin = ( input - b) / m;
920 |
921 | //float m_t = m * powf((m*p_tx +b),0.0f);
922 |
923 |
924 | //Solve Toe Segment
925 |
926 | float b_t = (m * (p_tx - p_bx))/ (p_ty - p_by);
927 | float a_t = _logf(p_ty - p_by) - b_t * _logf(p_tx - p_bx);
928 | float f_toe = (1* _expf(a_t + b_t * _logf(1 *(input - p_bx)))) + p_by;
929 |
930 | //inverse
931 | //float f_itoe = (1* _expf(_logf(1 *(input - p_bx)) - a_t)) / b_t + p_by;
932 |
933 |
934 | //Solve Shoulder Segment
935 | float b_s = (m * (p_wx - p_sx))/ (p_wy - p_sy);
936 | float a_s = _logf(p_wy - p_sy) - b_s * _logf(p_wx - p_sx);
937 | float f_sh = (-1* _expf(a_s + b_s * _logf(-1 *(input - p_wx)))) + p_wy;
938 |
939 | //inverse
940 | //float f_ish = (-1* _expf(_logf(-1 *(input - p_wy)) - a_s)) / b_s + p_wx;
941 |
942 | //the curve
943 |
944 | if (input <= p_tx) {output = f_toe;}
945 | if (input > p_tx && input < p_sx) {output = f_lin;}
946 | if (input >= p_sx) {output = f_sh;}
947 |
948 |
949 |
950 | return output;
951 |
952 |
953 | }
954 |
955 | __DEVICE__ float3 apply_contrast_curve_f3 (float3 input, float contrast, float pivot, float white, float black, float shoulder, float toe) {
956 | float3 output = input;
957 | output.x = apply_contrast_curve (output.x, contrast, pivot, white, black, shoulder, toe);
958 | output.y = apply_contrast_curve (output.y, contrast, pivot, white, black, shoulder, toe);
959 | output.z = apply_contrast_curve (output.z, contrast, pivot, white, black, shoulder, toe);
960 | return output;
961 | }
962 |
963 |
964 | //A function that applies contrast to only the luma channel in a CHEN color model image state before mixing it with the contrast applied to RGB
965 |
966 | __DEVICE__ float3 mix_sat (float3 in_1, float3 in_2, float p_mix_sat, float contrast, float pivot, float white, float black, float shoulder, float toe) {
967 |
968 | in_2 = RGBtoCHEN(in_2);
969 | in_2.z = apply_contrast_curve (in_2.z, contrast, pivot, white, black, shoulder, toe);
970 | in_2 = CHENtoRGB(in_2);
971 |
972 | float3 new_sat = _mix(in_1, in_2, p_mix_sat);
973 | return new_sat;
974 | }
975 |
976 | __DEVICE__ float3 mix_sat_lincon (float3 in_1, float3 in_2, float p_mix_sat, float contrast, float pivot) {
977 |
978 | in_2 = RGBtoCHEN(in_2);
979 | in_2.z = apply_linear_contrast (in_2.z, contrast, pivot);
980 | in_2 = CHENtoRGB(in_2);
981 |
982 | float3 new_sat = _mix(in_1, in_2, p_mix_sat);
983 | return new_sat;
984 | }
985 |
986 |
987 |
988 |
989 |
990 |
991 | DEFINE_UI_PARAMS(contrast, Contrast 🌓 , DCTLUI_SLIDER_FLOAT, 0.0, -0.5, 2, 0.001)
992 | DEFINE_UI_PARAMS(pivot, Relative Pivot 📌, DCTLUI_SLIDER_FLOAT, 0.0, -1, 1, 0.001)
993 | DEFINE_UI_PARAMS(P_exposure, Exposure 🌞, DCTLUI_SLIDER_FLOAT, 0.0f, -0.955f, 4.0f, 0.001f)
994 | DEFINE_UI_PARAMS(p_mix_sat, Original color : 🖍️, DCTLUI_SLIDER_FLOAT, .5f, 0.0f, 1.0f, 0.01f)
995 |
996 | DEFINE_UI_PARAMS(p_white_point, ⚪ White Point :⚪, DCTLUI_SLIDER_FLOAT, 1.015f, 0.5f, 1.f, 0.0001f)
997 | DEFINE_UI_PARAMS(p_shoulder, ├ Shoulder ╭, DCTLUI_SLIDER_FLOAT, 0.1, 0, 1, 0.1)
998 | //DEFINE_UI_PARAMS(p_shoulder_str,└ Fall off ╭ , DCTLUI_SLIDER_FLOAT, 5, 0.0, 10.0, 0.001)
999 |
1000 | DEFINE_UI_PARAMS(p_black_point, ⚫ Black Point :⚫, DCTLUI_SLIDER_FLOAT, 0.0001, 0.0001, .25, 0.0001)
1001 | DEFINE_UI_PARAMS(p_toe, ├ Toe ⌣ , DCTLUI_SLIDER_FLOAT, 0.1, 0.0f, 1, 0.001)
1002 | //DEFINE_UI_PARAMS(p_toe_str, └ Fall off ⌣ , DCTLUI_SLIDER_FLOAT, 2.0, 0.0, 10.0, 0.001)
1003 |
1004 |
1005 | DEFINE_UI_PARAMS(p_mix_contrast, Linear / S curve: , DCTLUI_SLIDER_FLOAT, 1.0f, 0.0f, 1.0f, 0.01f)
1006 |
1007 |
1008 | DEFINE_UI_PARAMS(bypass, 🚫 Bypass, DCTLUI_CHECK_BOX, 0)
1009 | DEFINE_UI_PARAMS(opt_showcurve, 📈 Show Curve, DCTLUI_CHECK_BOX, 0)
1010 | DEFINE_UI_PARAMS(opt_ramp, 📏 Show Ramp, DCTLUI_CHECK_BOX, 0)
1011 | DEFINE_UI_PARAMS(opt_ramp_scope, : Wide aspect overlays :, DCTLUI_CHECK_BOX, 0)
1012 | DEFINE_UI_PARAMS(p_transfer_f, Transfer function, DCTLUI_COMBO_BOX, 2, {logc3, logc4, di, aces_cct, log3g10, slog3, bmd_f5, clog3, dlog, fLog, fLog2, vlog, g22, g24, g26, linear}, {ARRI LogC3, ARRI LogC4, DaVinci Intermediate, ACEScct, RED Log3G10, Sony S-Log3, BMD Film Gen 5, Canon Log 3, DJI D-Log, FujiFilm F-Log, FujiFilm F-Log2, Panasonic V-Log, Gamma 2.2, Gamma 2.4, Gamma 2.6, Linear})
1013 |
1014 |
1015 |
1016 |
1017 | __DEVICE__ float3 transform(int p_Width, int p_Height, int p_X, int p_Y, float p_R, float p_G, float p_B) {
1018 |
1019 | const float3 clean = make_float3(p_R, p_G, p_B);
1020 | float3 in_RGB = make_float3(p_R, p_G, p_B);
1021 | pivot = set_pivot(pivot, p_transfer_f);
1022 | float3 out;
1023 |
1024 |
1025 | //create a linear ramp to enable the view graph control
1026 | float width = (float)p_Width;
1027 | float height = (float)p_Height;
1028 | if (opt_ramp_scope) {height = height*0.64f; }
1029 | float X = (float)p_X;
1030 | float Y = height - (float)p_Y;
1031 | if (opt_ramp_scope) { Y = height*1.28f - (float)p_Y; }
1032 | //Relative X,Y
1033 | float rY = Y / height;
1034 | float rX = X / width;
1035 | float3 ramp = {rX, rX, rX};
1036 |
1037 |
1038 | //sanitize black and white points
1039 | p_white_point = _fmaxf(p_white_point, pivot*1.01f);
1040 | //p_shoulder = p_shoulder> pivot ? _fmaxf(_fminf(p_shoulder, p_white_point * .6f), pivot) :_fmaxf(p_shoulder, pivot);
1041 | p_toe = _fminf(_fmaxf(p_toe , 0.001f), pivot );
1042 | p_shoulder = _fmaxf(_fminf(p_shoulder,p_white_point * .3f) , -0.5f);
1043 |
1044 |
1045 | // p_shoulder_str= _fmaxf((10 - p_shoulder_str), 0.3f);
1046 | // p_toe_str= _fmaxf((10 - p_toe_str), 0.135f);
1047 |
1048 |
1049 |
1050 | //
1051 | // p_black_point = _fmaxf(p_black_point , 0.69f);
1052 |
1053 |
1054 | //bypass option that outputs untouched image when activated
1055 | if (bypass ==1 ) {
1056 | //float3 clean = {p_R, p_G, p_B};
1057 |
1058 | out = clean;
1059 | //Optional show curve functionality
1060 | if (opt_showcurve == 1) {
1061 |
1062 | float overlayR = ramp.x >= (Y - 5.0f) / height && ramp.x <= (Y + 5.0f) / height ? 1.0f : 0.0f;
1063 | float overlayG = ramp.y >= (Y - 5.0f) / height && ramp.y <= (Y + 5.0f) / height ? 1.0f : 0.0f;
1064 | float overlayB = ramp.z >= (Y - 5.0f) / height && ramp.z <= (Y + 5.0f) / height ? 1.0f : 0.0f;
1065 | out.x = overlayR == 0.0f ? out.x : overlayR;
1066 | out.y = overlayG == 0.0f ? out.y : overlayG;
1067 | out.z = overlayB == 0.0f ? out.z : overlayB;
1068 | //Wide aspect mode
1069 | if (opt_ramp_scope) {
1070 |
1071 | if (rX < pivot+0.0025f && rX > pivot- 0.0025f && rY > 0.0f && rY< 1.1f) {
1072 | out.x = .8f;
1073 | out.y = .8f;
1074 | out.z = .8f;
1075 | }
1076 |
1077 | if (rX < p_shoulder+.4f+0.001f && rX > p_shoulder+.4f- 0.001f && rY > 0.0f && rY< 1.1f) {
1078 | out.x = 0.8f;
1079 | out.y = 0.1f;
1080 | out.z = 0.01f;
1081 | }
1082 |
1083 | if (rX < p_toe+0.001f && rX > p_toe- 0.001f && rY > 0.0f && rY< 1.1f) {
1084 | out.x = 0.01f;
1085 | out.y = 0.3f;
1086 | out.z = 0.7f;
1087 | }
1088 |
1089 | }
1090 | //wide aspect mode off
1091 | else{
1092 |
1093 | if (rX < pivot+0.0025f && rX > pivot- 0.0025f) {
1094 | out.x = .8f;
1095 | out.y = .8f;
1096 | out.z = .8f;
1097 | }
1098 |
1099 | if (rX < p_shoulder+.4f+0.001f && rX > p_shoulder+.4f- 0.001f) {
1100 | out.x = 0.8f;
1101 | out.y = 0.1f;
1102 | out.z = 0.01f;
1103 | }
1104 |
1105 | if (rX < p_toe+0.001f && rX > p_toe- 0.001f) {
1106 | out.x = 0.01f;
1107 | out.y = 0.3f;
1108 | out.z = 0.7f;
1109 | }
1110 |
1111 | }
1112 | }
1113 |
1114 | //option to overlay a grayscale ramp on the bottom edge of the frame
1115 | if (opt_ramp) {
1116 | if (opt_ramp_scope){
1117 | if( rY < 0.05f && rY > -0.02) {out = ramp;}
1118 | return out;
1119 | }
1120 | if( rY < 0.1f) {out = ramp;}
1121 |
1122 |
1123 |
1124 | }
1125 |
1126 | return out;
1127 | }
1128 |
1129 |
1130 |
1131 |
1132 | //apply compression to the white and black points
1133 | //in_RGB = apply_white_point(in_RGB, p_white_point, p_shoulder, p_shoulder_str);
1134 | //ramp = apply_white_point(ramp, p_white_point, p_shoulder, p_shoulder_str);
1135 |
1136 | //in_RGB = apply_black_point(in_RGB, p_black_point, p_toe, p_toe_str);
1137 | //ramp = apply_black_point(ramp, p_black_point, p_toe, p_toe_str);
1138 |
1139 |
1140 | //apply contrast operations
1141 | float3 lin_contrast = apply_linear_contrastf3 (in_RGB, contrast, pivot);
1142 | float3 ramp_linear = apply_linear_contrastf3 (ramp, contrast, pivot);
1143 | lin_contrast = mix_sat_lincon (lin_contrast, in_RGB, p_mix_sat, contrast, pivot);
1144 | ramp_linear = mix_sat_lincon (ramp_linear, ramp, p_mix_sat, contrast, pivot);
1145 | //lin_contrast = HSV_sat_mixed (in_RGB, lin_contrast, p_mix_sat, p_mix_contrast);
1146 | contrast += 1.f;
1147 | float3 roll_contrast = apply_contrast_curve_f3 (in_RGB, contrast, pivot, p_white_point, p_black_point, p_shoulder, p_toe);
1148 | float3 ramp_rolling = apply_contrast_curve_f3 (ramp, contrast, pivot, p_white_point, p_black_point, p_shoulder, p_toe);
1149 | roll_contrast = mix_sat (roll_contrast, in_RGB, p_mix_sat, contrast, pivot, p_white_point, p_black_point, p_shoulder, p_toe);
1150 | ramp_rolling = mix_sat (ramp_rolling, ramp, p_mix_sat, contrast, pivot, p_white_point, p_black_point, p_shoulder, p_toe);
1151 | //roll_contrast = HSV_sat_mixed (in_RGB, roll_contrast, p_mix_sat, p_mix_contrast);
1152 |
1153 | in_RGB = _mix(lin_contrast, roll_contrast, p_mix_contrast);
1154 | ramp = _mix(ramp_linear, ramp_rolling, p_mix_contrast);
1155 |
1156 | //mix back the original saturation channel in HSV to preserve saturation
1157 | //in_RGB = HSV_sat_mixed (clean, in_RGB, p_mix_sat, p_mix_contrast);
1158 |
1159 |
1160 | // exposure slider that works in linear
1161 |
1162 | P_exposure = powf(2.0, P_exposure);
1163 | in_RGB = GammaToLin(in_RGB, p_transfer_f);
1164 | ramp = GammaToLin(ramp, p_transfer_f);
1165 |
1166 | // Apply linear gain
1167 | in_RGB = in_RGB * P_exposure;
1168 | ramp = ramp * P_exposure;
1169 |
1170 | in_RGB = LinToGamma(in_RGB, p_transfer_f);
1171 | ramp = LinToGamma(ramp, p_transfer_f);
1172 |
1173 |
1174 |
1175 | out = in_RGB;
1176 |
1177 |
1178 |
1179 |
1180 | //Optional show curve functionality
1181 | if (opt_showcurve == 1) {
1182 |
1183 | float overlayR = ramp.x >= (Y - 5.0f) / height && ramp.x <= (Y + 5.0f) / height ? 1.0f : 0.0f;
1184 | float overlayG = ramp.y >= (Y - 5.0f) / height && ramp.y <= (Y + 5.0f) / height ? 1.0f : 0.0f;
1185 | float overlayB = ramp.z >= (Y - 5.0f) / height && ramp.z <= (Y + 5.0f) / height ? 1.0f : 0.0f;
1186 | out.x = overlayR == 0.0f ? out.x : overlayR;
1187 | out.y = overlayG == 0.0f ? out.y : overlayG;
1188 | out.z = overlayB == 0.0f ? out.z : overlayB;
1189 |
1190 |
1191 | //Wide aspect mode
1192 | if (opt_ramp_scope) {
1193 |
1194 | if (rX < pivot+0.0025f && rX > pivot- 0.0025f && rY > 0.0f && rY< 1.1f) {
1195 | out.x = .8f;
1196 | out.y = .8f;
1197 | out.z = .8f;
1198 | }
1199 |
1200 | if (rX < p_shoulder+.4f+0.001f && rX > p_shoulder+.4f- 0.001f && rY > 0.0f && rY< 1.1f) {
1201 | out.x = 0.8f;
1202 | out.y = 0.1f;
1203 | out.z = 0.01f;
1204 | }
1205 |
1206 | if (rX < p_toe+0.001f && rX > p_toe- 0.001f && rY > 0.0f && rY< 1.1f) {
1207 | out.x = 0.01f;
1208 | out.y = 0.3f;
1209 | out.z = 0.7f;
1210 | }
1211 |
1212 | }
1213 | //wide aspect mode off
1214 | else{
1215 |
1216 | if (rX < pivot+0.0025f && rX > pivot- 0.0025f) {
1217 | out.x = .8f;
1218 | out.y = .8f;
1219 | out.z = .8f;
1220 | }
1221 |
1222 | if (rX < p_shoulder+.4f+0.001f && rX > p_shoulder+.4f- 0.001f) {
1223 | out.x = 0.8f;
1224 | out.y = 0.1f;
1225 | out.z = 0.01f;
1226 | }
1227 |
1228 | if (rX < p_toe+0.001f && rX > p_toe- 0.001f) {
1229 | out.x = 0.01f;
1230 | out.y = 0.3f;
1231 | out.z = 0.7f;
1232 | }
1233 |
1234 | }
1235 | }
1236 |
1237 | //option to overlay a grayscale ramp on the bottom edge of the frame
1238 | if (opt_ramp) {
1239 | if (opt_ramp_scope){
1240 | if( rY < 0.05f && rY > -0.02f) {out = ramp;}
1241 | return out;
1242 | }
1243 | if( rY < 0.1f ) {out = ramp;}
1244 |
1245 |
1246 | }
1247 |
1248 |
1249 | return out;
1250 | }
--------------------------------------------------------------------------------