├── .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 | } --------------------------------------------------------------------------------