Geometry Nodes: Curve Parameter Node
[blender.git] / intern / opencolorio / gpu_shader_display_transform.glsl
1 /* Blender OpenColorIO implementation */
2
3 uniform sampler2D image_texture;
4 uniform sampler2D overlay_texture;
5
6 uniform float dither;
7 uniform float scale;
8 uniform float exponent;
9 uniform bool predivide;
10 uniform bool overlay;
11
12 #ifdef USE_CURVE_MAPPING
13 uniform sampler1D curve_mapping_texture;
14
15 layout(std140) uniform OCIO_GPUCurveMappingParameters
16 {
17   /* Curve mapping parameters
18    *
19    * See documentation for OCIO_CurveMappingSettings to get fields descriptions.
20    * (this ones pretty much copies stuff from C structure.)
21    */
22   vec4 curve_mapping_mintable;
23   vec4 curve_mapping_range;
24   vec4 curve_mapping_ext_in_x;
25   vec4 curve_mapping_ext_in_y;
26   vec4 curve_mapping_ext_out_x;
27   vec4 curve_mapping_ext_out_y;
28   vec4 curve_mapping_first_x;
29   vec4 curve_mapping_first_y;
30   vec4 curve_mapping_last_x;
31   vec4 curve_mapping_last_y;
32   vec4 curve_mapping_black;
33   vec4 curve_mapping_bwmul;
34   int curve_mapping_lut_size;
35   int curve_mapping_use_extend_extrapolate;
36 };
37
38 float read_curve_mapping(int table, int index)
39 {
40   return texelFetch(curve_mapping_texture, index, 0)[table];
41 }
42
43 float curvemap_calc_extend(int table, float x, vec2 first, vec2 last)
44 {
45   if (x <= first[0]) {
46     if (curve_mapping_use_extend_extrapolate == 0) {
47       /* horizontal extrapolation */
48       return first[1];
49     }
50     else {
51       float fac = (curve_mapping_ext_in_x[table] != 0.0) ?
52                       ((x - first[0]) / curve_mapping_ext_in_x[table]) :
53                       10000.0;
54       return first[1] + curve_mapping_ext_in_y[table] * fac;
55     }
56   }
57   else if (x >= last[0]) {
58     if (curve_mapping_use_extend_extrapolate == 0) {
59       /* horizontal extrapolation */
60       return last[1];
61     }
62     else {
63       float fac = (curve_mapping_ext_out_x[table] != 0.0) ?
64                       ((x - last[0]) / curve_mapping_ext_out_x[table]) :
65                       -10000.0;
66       return last[1] + curve_mapping_ext_out_y[table] * fac;
67     }
68   }
69   return 0.0;
70 }
71
72 float curvemap_evaluateF(int table, float value)
73 {
74   float mintable_ = curve_mapping_mintable[table];
75   float range = curve_mapping_range[table];
76   float mintable = 0.0;
77   int CM_TABLE = curve_mapping_lut_size - 1;
78
79   float fi;
80   int i;
81
82   /* index in table */
83   fi = (value - mintable) * range;
84   i = int(fi);
85
86   /* fi is table float index and should check against table range i.e. [0.0 CM_TABLE] */
87   if (fi < 0.0 || fi > float(CM_TABLE)) {
88     return curvemap_calc_extend(table,
89                                 value,
90                                 vec2(curve_mapping_first_x[table], curve_mapping_first_y[table]),
91                                 vec2(curve_mapping_last_x[table], curve_mapping_last_y[table]));
92   }
93   else {
94     if (i < 0) {
95       return read_curve_mapping(table, 0);
96     }
97     if (i >= CM_TABLE) {
98       return read_curve_mapping(table, CM_TABLE);
99     }
100     fi = fi - float(i);
101     float cm1 = read_curve_mapping(table, i);
102     float cm2 = read_curve_mapping(table, i + 1);
103     return mix(cm1, cm2, fi);
104   }
105 }
106
107 vec4 curvemapping_evaluate_premulRGBF(vec4 col)
108 {
109   col.rgb = (col.rgb - curve_mapping_black.rgb) * curve_mapping_bwmul.rgb;
110
111   vec4 result;
112   result.r = curvemap_evaluateF(0, col.r);
113   result.g = curvemap_evaluateF(1, col.g);
114   result.b = curvemap_evaluateF(2, col.b);
115   result.a = col.a;
116   return result;
117 }
118 #endif /* USE_CURVE_MAPPING */
119
120 /* Using a triangle distribution which gives a more final uniform noise.
121  * See Banding in Games:A Noisy Rant(revision 5) Mikkel Gjøl, Playdead (slide 27) */
122 /* GPUs are rounding before writting to framebuffer so we center the distribution around 0.0. */
123 /* Return triangle noise in [-1..1[ range */
124 float dither_random_value(vec2 co)
125 {
126   /* Original code from https://www.shadertoy.com/view/4t2SDh */
127   /* Uniform noise in [0..1[ range */
128   float nrnd0 = fract(sin(dot(co.xy, vec2(12.9898, 78.233))) * 43758.5453);
129   /* Convert uniform distribution into triangle-shaped distribution. */
130   float orig = nrnd0 * 2.0 - 1.0;
131   nrnd0 = orig * inversesqrt(abs(orig));
132   nrnd0 = max(-1.0, nrnd0); /* Removes nan's */
133   return nrnd0 - sign(orig);
134 }
135
136 vec2 round_to_pixel(sampler2D tex, vec2 uv)
137 {
138   vec2 size = textureSize(tex, 0);
139   return vec2(ivec2(uv * size)) / size;
140 }
141
142 vec4 apply_dither(vec4 col, vec2 uv)
143 {
144   col.rgb += dither_random_value(uv) * 0.0033 * dither;
145   return col;
146 }
147
148 vec4 OCIO_ProcessColor(vec4 col, vec4 col_overlay, vec2 noise_uv)
149 {
150 #ifdef USE_CURVE_MAPPING
151   col = curvemapping_evaluate_premulRGBF(col);
152 #endif
153
154   if (predivide) {
155     if (col.a > 0.0 && col.a < 1.0) {
156       col.rgb *= 1.0 / col.a;
157     }
158   }
159
160   /* NOTE: This is true we only do de-premul here and NO premul
161    *       and the reason is simple -- opengl is always configured
162    *       for straight alpha at this moment
163    */
164
165   /* Convert to scene linear (usually a no-op). */
166   col = OCIO_to_scene_linear(col);
167
168   /* Apply exposure in scene linear. */
169   col.rgb *= scale;
170
171   /* Convert to display space. */
172   col = OCIO_to_display(col);
173
174   /* Blend with overlay in UI colorspace.
175    *
176    * UI colorspace here refers to the display linear color space,
177    * i.e: The linear color space w.r.t. display chromaticity and radiometry.
178    * We separate the colormanagement process into two steps to be able to
179    * merge UI using alpha blending in the correct color space. */
180   if (overlay) {
181     col.rgb = pow(col.rgb, vec3(exponent * 2.2));
182     col = clamp(col, 0.0, 1.0);
183     col *= 1.0 - col_overlay.a;
184     col += col_overlay; /* Assumed unassociated alpha. */
185     col.rgb = pow(col.rgb, vec3(1.0 / 2.2));
186   }
187   else {
188     col.rgb = pow(col.rgb, vec3(exponent));
189   }
190
191   if (dither > 0.0) {
192     col = apply_dither(col, noise_uv);
193   }
194
195   return col;
196 }
197
198 /* ------------------------------------------------------------------------ */
199
200 in vec2 texCoord_interp;
201 out vec4 fragColor;
202
203 void main()
204 {
205   vec4 col = texture(image_texture, texCoord_interp.st);
206   vec4 col_overlay = texture(overlay_texture, texCoord_interp.st);
207   vec2 noise_uv = round_to_pixel(image_texture, texCoord_interp.st);
208
209   fragColor = OCIO_ProcessColor(col, col_overlay, noise_uv);
210 }