1/* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5#define VECS_PER_SPECIFIC_BRUSH 3 6#define WR_FEATURE_TEXTURE_2D 7 8#include shared,prim_shared,brush 9 10// UV and bounds for the source image 11varying vec2 v_src_uv; 12flat varying vec4 v_src_uv_sample_bounds; 13 14// UV and bounds for the backdrop image 15varying vec2 v_backdrop_uv; 16flat varying vec4 v_backdrop_uv_sample_bounds; 17 18#if defined(PLATFORM_ANDROID) && !defined(SWGL) 19// Work around Adreno 3xx driver bug. See the v_perspective comment in 20// brush_image or bug 1630356 for details. 21flat varying vec2 v_perspective_vec; 22#define v_perspective v_perspective_vec.x 23#else 24// Flag to allow perspective interpolation of UV. 25flat varying float v_perspective; 26#endif 27 28// mix-blend op 29flat varying int v_op; 30 31#ifdef WR_VERTEX_SHADER 32 33void get_uv( 34 int res_address, 35 vec2 f, 36 ivec2 texture_size, 37 float perspective_f, 38 out vec2 out_uv, 39 out vec4 out_uv_sample_bounds 40) { 41 ImageSource res = fetch_image_source(res_address); 42 vec2 uv0 = res.uv_rect.p0; 43 vec2 uv1 = res.uv_rect.p1; 44 45 vec2 inv_texture_size = vec2(1.0) / vec2(texture_size); 46 f = get_image_quad_uv(res_address, f); 47 vec2 uv = mix(uv0, uv1, f); 48 49 out_uv = uv * inv_texture_size * perspective_f; 50 out_uv_sample_bounds = vec4(uv0 + vec2(0.5), uv1 - vec2(0.5)) * inv_texture_size.xyxy; 51} 52 53void brush_vs( 54 VertexInfo vi, 55 int prim_address, 56 RectWithEndpoint local_rect, 57 RectWithEndpoint segment_rect, 58 ivec4 prim_user_data, 59 int specific_resource_address, 60 mat4 transform, 61 PictureTask pic_task, 62 int brush_flags, 63 vec4 unused 64) { 65 vec2 f = (vi.local_pos - local_rect.p0) / rect_size(local_rect); 66 float perspective_interpolate = (brush_flags & BRUSH_FLAG_PERSPECTIVE_INTERPOLATION) != 0 ? 1.0 : 0.0; 67 float perspective_f = mix(vi.world_pos.w, 1.0, perspective_interpolate); 68 v_perspective = perspective_interpolate; 69 v_op = prim_user_data.x; 70 71 get_uv( 72 prim_user_data.y, 73 f, 74 TEX_SIZE(sColor0).xy, 75 1.0, 76 v_backdrop_uv, 77 v_backdrop_uv_sample_bounds 78 ); 79 80 get_uv( 81 prim_user_data.z, 82 f, 83 TEX_SIZE(sColor1).xy, 84 perspective_f, 85 v_src_uv, 86 v_src_uv_sample_bounds 87 ); 88} 89#endif 90 91#ifdef WR_FRAGMENT_SHADER 92vec3 Multiply(vec3 Cb, vec3 Cs) { 93 return Cb * Cs; 94} 95 96vec3 Screen(vec3 Cb, vec3 Cs) { 97 return Cb + Cs - (Cb * Cs); 98} 99 100vec3 HardLight(vec3 Cb, vec3 Cs) { 101 vec3 m = Multiply(Cb, 2.0 * Cs); 102 vec3 s = Screen(Cb, 2.0 * Cs - 1.0); 103 vec3 edge = vec3(0.5, 0.5, 0.5); 104 return mix(m, s, step(edge, Cs)); 105} 106 107// TODO: Worth doing with mix/step? Check GLSL output. 108float ColorDodge(float Cb, float Cs) { 109 if (Cb == 0.0) 110 return 0.0; 111 else if (Cs == 1.0) 112 return 1.0; 113 else 114 return min(1.0, Cb / (1.0 - Cs)); 115} 116 117// TODO: Worth doing with mix/step? Check GLSL output. 118float ColorBurn(float Cb, float Cs) { 119 if (Cb == 1.0) 120 return 1.0; 121 else if (Cs == 0.0) 122 return 0.0; 123 else 124 return 1.0 - min(1.0, (1.0 - Cb) / Cs); 125} 126 127float SoftLight(float Cb, float Cs) { 128 if (Cs <= 0.5) { 129 return Cb - (1.0 - 2.0 * Cs) * Cb * (1.0 - Cb); 130 } else { 131 float D; 132 133 if (Cb <= 0.25) 134 D = ((16.0 * Cb - 12.0) * Cb + 4.0) * Cb; 135 else 136 D = sqrt(Cb); 137 138 return Cb + (2.0 * Cs - 1.0) * (D - Cb); 139 } 140} 141 142vec3 Difference(vec3 Cb, vec3 Cs) { 143 return abs(Cb - Cs); 144} 145 146vec3 Exclusion(vec3 Cb, vec3 Cs) { 147 return Cb + Cs - 2.0 * Cb * Cs; 148} 149 150// These functions below are taken from the spec. 151// There's probably a much quicker way to implement 152// them in GLSL... 153float Sat(vec3 c) { 154 return max(c.r, max(c.g, c.b)) - min(c.r, min(c.g, c.b)); 155} 156 157float Lum(vec3 c) { 158 vec3 f = vec3(0.3, 0.59, 0.11); 159 return dot(c, f); 160} 161 162vec3 ClipColor(vec3 C) { 163 float L = Lum(C); 164 float n = min(C.r, min(C.g, C.b)); 165 float x = max(C.r, max(C.g, C.b)); 166 167 if (n < 0.0) 168 C = L + (((C - L) * L) / (L - n)); 169 170 if (x > 1.0) 171 C = L + (((C - L) * (1.0 - L)) / (x - L)); 172 173 return C; 174} 175 176vec3 SetLum(vec3 C, float l) { 177 float d = l - Lum(C); 178 return ClipColor(C + d); 179} 180 181void SetSatInner(inout float Cmin, inout float Cmid, inout float Cmax, float s) { 182 if (Cmax > Cmin) { 183 Cmid = (((Cmid - Cmin) * s) / (Cmax - Cmin)); 184 Cmax = s; 185 } else { 186 Cmid = 0.0; 187 Cmax = 0.0; 188 } 189 Cmin = 0.0; 190} 191 192vec3 SetSat(vec3 C, float s) { 193 if (C.r <= C.g) { 194 if (C.g <= C.b) { 195 SetSatInner(C.r, C.g, C.b, s); 196 } else { 197 if (C.r <= C.b) { 198 SetSatInner(C.r, C.b, C.g, s); 199 } else { 200 SetSatInner(C.b, C.r, C.g, s); 201 } 202 } 203 } else { 204 if (C.r <= C.b) { 205 SetSatInner(C.g, C.r, C.b, s); 206 } else { 207 if (C.g <= C.b) { 208 SetSatInner(C.g, C.b, C.r, s); 209 } else { 210 SetSatInner(C.b, C.g, C.r, s); 211 } 212 } 213 } 214 return C; 215} 216 217vec3 Hue(vec3 Cb, vec3 Cs) { 218 return SetLum(SetSat(Cs, Sat(Cb)), Lum(Cb)); 219} 220 221vec3 Saturation(vec3 Cb, vec3 Cs) { 222 return SetLum(SetSat(Cb, Sat(Cs)), Lum(Cb)); 223} 224 225vec3 Color(vec3 Cb, vec3 Cs) { 226 return SetLum(Cs, Lum(Cb)); 227} 228 229vec3 Luminosity(vec3 Cb, vec3 Cs) { 230 return SetLum(Cb, Lum(Cs)); 231} 232 233const int MixBlendMode_Multiply = 1; 234const int MixBlendMode_Screen = 2; 235const int MixBlendMode_Overlay = 3; 236const int MixBlendMode_Darken = 4; 237const int MixBlendMode_Lighten = 5; 238const int MixBlendMode_ColorDodge = 6; 239const int MixBlendMode_ColorBurn = 7; 240const int MixBlendMode_HardLight = 8; 241const int MixBlendMode_SoftLight = 9; 242const int MixBlendMode_Difference = 10; 243const int MixBlendMode_Exclusion = 11; 244const int MixBlendMode_Hue = 12; 245const int MixBlendMode_Saturation = 13; 246const int MixBlendMode_Color = 14; 247const int MixBlendMode_Luminosity = 15; 248 249Fragment brush_fs() { 250 float perspective_divisor = mix(gl_FragCoord.w, 1.0, v_perspective); 251 252 vec2 src_uv = v_src_uv * perspective_divisor; 253 src_uv = clamp(src_uv, v_src_uv_sample_bounds.xy, v_src_uv_sample_bounds.zw); 254 255 vec2 backdrop_uv = clamp(v_backdrop_uv, v_backdrop_uv_sample_bounds.xy, v_backdrop_uv_sample_bounds.zw); 256 257 vec4 Cb = texture(sColor0, backdrop_uv); 258 vec4 Cs = texture(sColor1, src_uv); 259 260 // The mix-blend-mode functions assume no premultiplied alpha 261 if (Cb.a != 0.0) { 262 Cb.rgb /= Cb.a; 263 } 264 265 if (Cs.a != 0.0) { 266 Cs.rgb /= Cs.a; 267 } 268 269 // Return yellow if none of the branches match (shouldn't happen). 270 vec4 result = vec4(1.0, 1.0, 0.0, 1.0); 271 272 switch (v_op) { 273 case MixBlendMode_Multiply: 274 result.rgb = Multiply(Cb.rgb, Cs.rgb); 275 break; 276 case MixBlendMode_Screen: 277 result.rgb = Screen(Cb.rgb, Cs.rgb); 278 break; 279 case MixBlendMode_Overlay: 280 // Overlay is inverse of Hardlight 281 result.rgb = HardLight(Cs.rgb, Cb.rgb); 282 break; 283 case MixBlendMode_Darken: 284 result.rgb = min(Cs.rgb, Cb.rgb); 285 break; 286 case MixBlendMode_Lighten: 287 result.rgb = max(Cs.rgb, Cb.rgb); 288 break; 289 case MixBlendMode_ColorDodge: 290 result.r = ColorDodge(Cb.r, Cs.r); 291 result.g = ColorDodge(Cb.g, Cs.g); 292 result.b = ColorDodge(Cb.b, Cs.b); 293 break; 294 case MixBlendMode_ColorBurn: 295 result.r = ColorBurn(Cb.r, Cs.r); 296 result.g = ColorBurn(Cb.g, Cs.g); 297 result.b = ColorBurn(Cb.b, Cs.b); 298 break; 299 case MixBlendMode_HardLight: 300 result.rgb = HardLight(Cb.rgb, Cs.rgb); 301 break; 302 case MixBlendMode_SoftLight: 303 result.r = SoftLight(Cb.r, Cs.r); 304 result.g = SoftLight(Cb.g, Cs.g); 305 result.b = SoftLight(Cb.b, Cs.b); 306 break; 307 case MixBlendMode_Difference: 308 result.rgb = Difference(Cb.rgb, Cs.rgb); 309 break; 310 case MixBlendMode_Exclusion: 311 result.rgb = Exclusion(Cb.rgb, Cs.rgb); 312 break; 313 case MixBlendMode_Hue: 314 result.rgb = Hue(Cb.rgb, Cs.rgb); 315 break; 316 case MixBlendMode_Saturation: 317 result.rgb = Saturation(Cb.rgb, Cs.rgb); 318 break; 319 case MixBlendMode_Color: 320 result.rgb = Color(Cb.rgb, Cs.rgb); 321 break; 322 case MixBlendMode_Luminosity: 323 result.rgb = Luminosity(Cb.rgb, Cs.rgb); 324 break; 325 default: break; 326 } 327 328 result.rgb = (1.0 - Cb.a) * Cs.rgb + Cb.a * result.rgb; 329 result.a = Cs.a; 330 331 result.rgb *= result.a; 332 333 return Fragment(result); 334} 335#endif 336