| @@ -0,0 +1,193 @@ | ||
| /* This Source Code Form is subject to the terms of the Mozilla Public | ||
| * License, v. 2.0. If a copy of the MPL was not distributed with this | ||
| * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||
| vec3 Multiply(vec3 Cb, vec3 Cs) { | ||
| return Cb * Cs; | ||
| } | ||
| vec3 Screen(vec3 Cb, vec3 Cs) { | ||
| return Cb + Cs - (Cb * Cs); | ||
| } | ||
| vec3 HardLight(vec3 Cb, vec3 Cs) { | ||
| vec3 m = Multiply(Cb, 2.0 * Cs); | ||
| vec3 s = Screen(Cb, 2.0 * Cs - 1.0); | ||
| vec3 edge = vec3(0.5, 0.5, 0.5); | ||
| return mix(m, s, step(edge, Cs)); | ||
| } | ||
| // TODO: Worth doing with mix/step? Check GLSL output. | ||
| float ColorDodge(float Cb, float Cs) { | ||
| if (Cb == 0.0) | ||
| return 0.0; | ||
| else if (Cs == 1.0) | ||
| return 1.0; | ||
| else | ||
| return min(1.0, Cb / (1.0 - Cs)); | ||
| } | ||
| // TODO: Worth doing with mix/step? Check GLSL output. | ||
| float ColorBurn(float Cb, float Cs) { | ||
| if (Cb == 1.0) | ||
| return 1.0; | ||
| else if (Cs == 0.0) | ||
| return 0.0; | ||
| else | ||
| return 1.0 - min(1.0, (1.0 - Cb) / Cs); | ||
| } | ||
| float SoftLight(float Cb, float Cs) { | ||
| if (Cs <= 0.5) { | ||
| return Cb - (1.0 - 2.0 * Cs) * Cb * (1.0 - Cb); | ||
| } else { | ||
| float D; | ||
| if (Cb <= 0.25) | ||
| D = ((16.0 * Cb - 12.0) * Cb + 4.0) * Cb; | ||
| else | ||
| D = sqrt(Cb); | ||
| return Cb + (2.0 * Cs - 1.0) * (D - Cb); | ||
| } | ||
| } | ||
| vec3 Difference(vec3 Cb, vec3 Cs) { | ||
| return abs(Cb - Cs); | ||
| } | ||
| vec3 Exclusion(vec3 Cb, vec3 Cs) { | ||
| return Cb + Cs - 2.0 * Cb * Cs; | ||
| } | ||
| // These functions below are taken from the spec. | ||
| // There's probably a much quicker way to implement | ||
| // them in GLSL... | ||
| float Sat(vec3 c) { | ||
| return max(c.r, max(c.g, c.b)) - min(c.r, min(c.g, c.b)); | ||
| } | ||
| float Lum(vec3 c) { | ||
| vec3 f = vec3(0.3, 0.59, 0.11); | ||
| return dot(c, f); | ||
| } | ||
| vec3 ClipColor(vec3 C) { | ||
| float L = Lum(C); | ||
| float n = min(C.r, min(C.g, C.b)); | ||
| float x = max(C.r, max(C.g, C.b)); | ||
| if (n < 0.0) | ||
| C = L + (((C - L) * L) / (L - n)); | ||
| if (x > 1.0) | ||
| C = L + (((C - L) * (1.0 - L)) / (x - L)); | ||
| return C; | ||
| } | ||
| vec3 SetLum(vec3 C, float l) { | ||
| float d = l - Lum(C); | ||
| return ClipColor(C + d); | ||
| } | ||
| void SetSatInner(inout float Cmin, inout float Cmid, inout float Cmax, float s) { | ||
| if (Cmax > Cmin) { | ||
| Cmid = (((Cmid - Cmin) * s) / (Cmax - Cmin)); | ||
| Cmax = s; | ||
| } else { | ||
| Cmid = 0.0; | ||
| Cmax = 0.0; | ||
| } | ||
| Cmin = 0.0; | ||
| } | ||
| vec3 SetSat(vec3 C, float s) { | ||
| if (C.r <= C.g) { | ||
| if (C.g <= C.b) { | ||
| SetSatInner(C.r, C.g, C.b, s); | ||
| } else { | ||
| if (C.r <= C.b) { | ||
| SetSatInner(C.r, C.b, C.g, s); | ||
| } else { | ||
| SetSatInner(C.b, C.r, C.g, s); | ||
| } | ||
| } | ||
| } else { | ||
| if (C.r <= C.b) { | ||
| SetSatInner(C.g, C.r, C.b, s); | ||
| } else { | ||
| if (C.g <= C.b) { | ||
| SetSatInner(C.g, C.b, C.r, s); | ||
| } else { | ||
| SetSatInner(C.b, C.g, C.r, s); | ||
| } | ||
| } | ||
| } | ||
| return C; | ||
| } | ||
| vec3 Hue(vec3 Cb, vec3 Cs) { | ||
| return SetLum(SetSat(Cs, Sat(Cb)), Lum(Cb)); | ||
| } | ||
| vec3 Saturation(vec3 Cb, vec3 Cs) { | ||
| return SetLum(SetSat(Cb, Sat(Cs)), Lum(Cb)); | ||
| } | ||
| vec3 Color(vec3 Cb, vec3 Cs) { | ||
| return SetLum(Cs, Lum(Cb)); | ||
| } | ||
| vec3 Luminosity(vec3 Cb, vec3 Cs) { | ||
| return SetLum(Cb, Lum(Cs)); | ||
| } | ||
| void main(void) | ||
| { | ||
| vec3 Cs = Texture(sDiffuse, vColorTexCoord).xyz; | ||
| vec3 Cb = Texture(sMask, vMaskTexCoord).xyz; | ||
| // TODO: Relies on the ordering of MixBlendMode enum! | ||
| // TODO: May be best to have separate shaders (esp. on Tegra) | ||
| int blend_mode = int(uBlendParams.x); | ||
| // Return yellow if none of the branches match (shouldn't happen). | ||
| vec3 result = vec3(1.0, 1.0, 0.0); | ||
| if (blend_mode == 2) { | ||
| result = Screen(Cb, Cs); | ||
| } else if (blend_mode == 3) { | ||
| result = HardLight(Cs, Cb); // Overlay is inverse of Hardlight | ||
| } else if (blend_mode == 6) { | ||
| result.r = ColorDodge(Cb.r, Cs.r); | ||
| result.g = ColorDodge(Cb.g, Cs.g); | ||
| result.b = ColorDodge(Cb.b, Cs.b); | ||
| } else if (blend_mode == 7) { | ||
| result.r = ColorBurn(Cb.r, Cs.r); | ||
| result.g = ColorBurn(Cb.g, Cs.g); | ||
| result.b = ColorBurn(Cb.b, Cs.b); | ||
| } else if (blend_mode == 8) { | ||
| result = HardLight(Cb, Cs); | ||
| } else if (blend_mode == 9) { | ||
| result.r = SoftLight(Cb.r, Cs.r); | ||
| result.g = SoftLight(Cb.g, Cs.g); | ||
| result.b = SoftLight(Cb.b, Cs.b); | ||
| } else if (blend_mode == 10) { | ||
| result = Difference(Cb, Cs); | ||
| } else if (blend_mode == 11) { | ||
| result = Exclusion(Cb, Cs); | ||
| } else if (blend_mode == 12) { | ||
| result = Hue(Cb, Cs); | ||
| } else if (blend_mode == 13) { | ||
| result = Saturation(Cb, Cs); | ||
| } else if (blend_mode == 14) { | ||
| result = Color(Cb, Cs); | ||
| } else if (blend_mode == 15) { | ||
| result = Luminosity(Cb, Cs); | ||
| } | ||
| // TODO: Handle output alpha correctly. | ||
| SetFragColor(vec4(result, 1.0)); | ||
| } | ||
| @@ -0,0 +1,10 @@ | ||
| /* This Source Code Form is subject to the terms of the Mozilla Public | ||
| * License, v. 2.0. If a copy of the MPL was not distributed with this | ||
| * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||
| void main(void) | ||
| { | ||
| vColorTexCoord = aColorTexCoordRectTop.xy; | ||
| vMaskTexCoord = aMaskTexCoordRectTop.xy / 65535.0; | ||
| gl_Position = uTransform * vec4(aPosition, 1.0); | ||
| } |
| @@ -0,0 +1,9 @@ | ||
| /* This Source Code Form is subject to the terms of the Mozilla Public | ||
| * License, v. 2.0. If a copy of the MPL was not distributed with this | ||
| * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||
| void main(void) | ||
| { | ||
| vec4 diffuse = Texture(sDiffuse, vColorTexCoord); | ||
| SetFragColor(diffuse * vColor); | ||
| } |
| @@ -0,0 +1,12 @@ | ||
| /* This Source Code Form is subject to the terms of the Mozilla Public | ||
| * License, v. 2.0. If a copy of the MPL was not distributed with this | ||
| * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||
| void main(void) | ||
| { | ||
| vColor = aColorRectTL / 255.0; | ||
| vColorTexCoord = aColorTexCoordRectTop.xy; | ||
| vec4 pos = vec4(aPosition, 1.0); | ||
| pos.xy = SnapToPixels(pos.xy); | ||
| gl_Position = uTransform * pos; | ||
| } |
| @@ -0,0 +1,44 @@ | ||
| /* This Source Code Form is subject to the terms of the Mozilla Public | ||
| * License, v. 2.0. If a copy of the MPL was not distributed with this | ||
| * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||
| // `vBorderPosition` is the position of the source texture in the atlas. | ||
| float gauss(float x, float sigma) { | ||
| return (1.0 / sqrt(6.283185307179586 * sigma * sigma)) * exp(-(x * x) / (2.0 * sigma * sigma)); | ||
| } | ||
| void main(void) { | ||
| #ifdef SERVO_ES2 | ||
| // TODO(gw): for loops have to be unrollable on es2. | ||
| SetFragColor(vec4(1.0, 0.0, 0.0, 1.0)); | ||
| #else | ||
| vec2 sideOffsets = (vDestTextureSize - vSourceTextureSize) / 2.0; | ||
| int range = int(vBlurRadius) * 3; | ||
| float sigma = vBlurRadius / 2.0; | ||
| vec4 value = vec4(0.0); | ||
| vec2 sourceTextureUvOrigin = vBorderPosition.xy; | ||
| vec2 sourceTextureUvSize = vBorderPosition.zw - sourceTextureUvOrigin; | ||
| for (int offset = -range; offset <= range; offset++) { | ||
| float offsetF = float(offset); | ||
| vec2 lColorTexCoord = (vColorTexCoord.xy * vDestTextureSize - sideOffsets) / | ||
| vSourceTextureSize; | ||
| lColorTexCoord += vec2(offsetF) / vSourceTextureSize * uDirection; | ||
| vec4 x = lColorTexCoord.x >= 0.0 && | ||
| lColorTexCoord.x <= 1.0 && | ||
| lColorTexCoord.y >= 0.0 && | ||
| lColorTexCoord.y <= 1.0 ? | ||
| Texture(sDiffuse, lColorTexCoord * sourceTextureUvSize + sourceTextureUvOrigin) : | ||
| vec4(0.0); | ||
| // Alpha must be premultiplied in order to properly blur the alpha channel. | ||
| value += vec4(x.rgb * x.a, x.a) * gauss(offsetF, sigma); | ||
| } | ||
| // Unpremultiply the alpha. | ||
| value = vec4(value.rgb / value.a, value.a); | ||
| SetFragColor(value); | ||
| #endif | ||
| } | ||
| @@ -0,0 +1,14 @@ | ||
| /* This Source Code Form is subject to the terms of the Mozilla Public | ||
| * License, v. 2.0. If a copy of the MPL was not distributed with this | ||
| * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||
| void main(void) | ||
| { | ||
| vColorTexCoord = aColorTexCoordRectTop.xy; | ||
| vBorderPosition = aBorderPosition; | ||
| vBlurRadius = aBlurRadius; | ||
| vDestTextureSize = aDestTextureSize; | ||
| vSourceTextureSize = aSourceTextureSize; | ||
| gl_Position = uTransform * vec4(aPosition, 1.0); | ||
| } | ||
| @@ -0,0 +1,41 @@ | ||
| /* This Source Code Form is subject to the terms of the Mozilla Public | ||
| * License, v. 2.0. If a copy of the MPL was not distributed with this | ||
| * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||
| /* | ||
| Ellipse equation: | ||
| (x-h)^2 (y-k)^2 | ||
| ------- + ------- <= 1 | ||
| rx^2 ry^2 | ||
| */ | ||
| float Value(vec2 position) { | ||
| float outer_rx = vBorderRadii.x; | ||
| float outer_ry = vBorderRadii.y; | ||
| float outer_dx = position.x * position.x / (outer_rx * outer_rx); | ||
| float outer_dy = position.y * position.y / (outer_ry * outer_ry); | ||
| if (outer_dx + outer_dy > 1.0) | ||
| return 0.0; | ||
| float inner_rx = vBorderRadii.z; | ||
| float inner_ry = vBorderRadii.w; | ||
| if (inner_rx == 0.0 || inner_ry == 0.0) | ||
| return 1.0; | ||
| float inner_dx = position.x * position.x / (inner_rx * inner_rx); | ||
| float inner_dy = position.y * position.y / (inner_ry * inner_ry); | ||
| return inner_dx + inner_dy >= 1.0 ? 1.0 : 0.0; | ||
| } | ||
| void main(void) | ||
| { | ||
| vec2 position = vPosition - vBorderPosition.xy; | ||
| vec4 pixelBounds = vec4(floor(position.x), floor(position.y), | ||
| ceil(position.x), ceil(position.y)); | ||
| float value = (Value(pixelBounds.xy) + Value(pixelBounds.zy) + | ||
| Value(pixelBounds.xw) + Value(pixelBounds.zw)) / 4.0; | ||
| SetFragColor(vec4(vColor.rgb, mix(1.0 - vColor.a, vColor.a, value))); | ||
| } | ||
| @@ -0,0 +1,12 @@ | ||
| /* This Source Code Form is subject to the terms of the Mozilla Public | ||
| * License, v. 2.0. If a copy of the MPL was not distributed with this | ||
| * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||
| void main(void) | ||
| { | ||
| vColor = aColorRectTL; | ||
| vPosition = aPosition.xy; | ||
| vBorderPosition = aBorderPosition; | ||
| vBorderRadii = aBorderRadii; | ||
| gl_Position = uTransform * vec4(aPosition, 1.0); | ||
| } |
| @@ -0,0 +1,146 @@ | ||
| /* This Source Code Form is subject to the terms of the Mozilla Public | ||
| * License, v. 2.0. If a copy of the MPL was not distributed with this | ||
| * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||
| // See http://asciimath.org to render the equations here. | ||
| // The Gaussian function used for blurring: | ||
| // | ||
| // G_sigma(x) = 1/sqrt(2 pi sigma^2) e^(-x^2/(2 sigma^2)) | ||
| float gauss(float x, float sigma) { | ||
| float sigmaPow2 = sigma * sigma; | ||
| return 1.0 / sqrt(6.283185307179586 * sigmaPow2) * exp(-(x * x) / (2.0 * sigmaPow2)); | ||
| } | ||
| // An approximation of the error function, which is related to the integral of the Gaussian | ||
| // function: | ||
| // | ||
| // "erf"(x) = 2/sqrt(pi) int_0^x e^(-t^2) dt | ||
| // ~~ 1 - 1 / (1 + a_1 x + a_2 x^2 + a_3 x^3 + a_4 x^4)^4 | ||
| // | ||
| // where: | ||
| // | ||
| // a_1 = 0.278393, a_2 = 0.230389, a_3 = 0.000972, a_4 = 0.078108 | ||
| // | ||
| // This approximation is accurate to `5 xx 10^-4`, more than accurate enough for our purposes. | ||
| // | ||
| // See: https://en.wikipedia.org/wiki/Error_function#Approximation_with_elementary_functions | ||
| float erf(float x) { | ||
| bool negative = x < 0.0; | ||
| if (negative) | ||
| x = -x; | ||
| float x2 = x * x; | ||
| float x3 = x2 * x; | ||
| float x4 = x2 * x2; | ||
| float denom = 1.0 + 0.278393 * x + 0.230389 * x2 + 0.000972 * x3 + 0.078108 * x4; | ||
| float result = 1.0 - 1.0 / (denom * denom * denom * denom); | ||
| return negative ? -result : result; | ||
| } | ||
| // A useful helper for calculating integrals of the Gaussian function via the error function: | ||
| // | ||
| // "erf"_sigma(x) = 2 int 1/sqrt(2 pi sigma^2) e^(-x^2/(2 sigma^2)) dx | ||
| // = "erf"(x/(sigma sqrt(2))) | ||
| float erfSigma(float x, float sigma) { | ||
| return erf(x / (sigma * 1.4142135623730951)); | ||
| } | ||
| // Returns the blurred color value from the box itself (not counting any rounded corners). `p_0` is | ||
| // the vector distance to the top left corner of the box; `p_1` is the vector distance to its | ||
| // bottom right corner. | ||
| // | ||
| // "colorFromRect"_sigma(p_0, p_1) | ||
| // = int_{p_{0_y}}^{p_{1_y}} int_{p_{1_x}}^{p_{0_x}} G_sigma(y) G_sigma(x) dx dy | ||
| // = 1/4 ("erf"_sigma(p_{1_x}) - "erf"_sigma(p_{0_x})) | ||
| // ("erf"_sigma(p_{1_y}) - "erf"_sigma(p_{0_y})) | ||
| float colorFromRect(vec2 p0, vec2 p1, float sigma) { | ||
| return (erfSigma(p1.x, sigma) - erfSigma(p0.x, sigma)) * | ||
| (erfSigma(p1.y, sigma) - erfSigma(p0.y, sigma)) / 4.0; | ||
| } | ||
| // Returns the `x` coordinate on the ellipse with the given radii for the given `y` coordinate: | ||
| // | ||
| // "ellipsePoint"(y, y_0, a, b) = a sqrt(1 - ((y - y_0) / b)^2) | ||
| float ellipsePoint(float y, float y0, vec2 radii) { | ||
| float bStep = (y - y0) / radii.y; | ||
| return radii.x * sqrt(1.0 - bStep * bStep); | ||
| } | ||
| // A helper function to compute the value that needs to be subtracted to accommodate the border | ||
| // corners. | ||
| // | ||
| // "colorCutout"_sigma(x_{0_l}, x_{0_r}, y_0, y_{min}, y_{max}, a, b) | ||
| // = int_{y_{min}}^{y_{max}} | ||
| // int_{x_{0_r} + "ellipsePoint"(y, y_0, a, b)}^{x_{0_r} + a} G_sigma(y) G_sigma(x) dx | ||
| // + int_{x_{0_l} - a}^{x_{0_l} - "ellipsePoint"(y, y_0, a, b)} G_sigma(y) G_sigma(x) | ||
| // dx dy | ||
| // = int_{y_{min}}^{y_{max}} 1/2 G_sigma(y) | ||
| // ("erf"_sigma(x_{0_r} + a) - "erf"_sigma(x_{0_r} + "ellipsePoint"(y, y_0, a, b)) + | ||
| // "erf"_sigma(x_{0_l} - "ellipsePoint"(y, y_0, a, b)) - "erf"_sigma(x_{0_l} - a)) | ||
| // | ||
| // with the outer integral evaluated numerically. | ||
| float colorCutoutGeneral(float x0l, | ||
| float x0r, | ||
| float y0, | ||
| float yMin, | ||
| float yMax, | ||
| vec2 radii, | ||
| float sigma) { | ||
| float sum = 0.0; | ||
| for (float y = yMin; y <= yMax; y += 1.0) { | ||
| float xEllipsePoint = ellipsePoint(y, y0, radii); | ||
| sum += gauss(y, sigma) * | ||
| (erfSigma(x0r + radii.x, sigma) - erfSigma(x0r + xEllipsePoint, sigma) + | ||
| erfSigma(x0l - xEllipsePoint, sigma) - erfSigma(x0l - radii.x, sigma)); | ||
| } | ||
| return sum / 2.0; | ||
| } | ||
| // The value that needs to be subtracted to accommodate the top border corners. | ||
| float colorCutoutTop(float x0l, float x0r, float y0, vec2 radii, float sigma) { | ||
| return colorCutoutGeneral(x0l, x0r, y0, y0, y0 + radii.y, radii, sigma); | ||
| } | ||
| // The value that needs to be subtracted to accommodate the bottom border corners. | ||
| float colorCutoutBottom(float x0l, float x0r, float y0, vec2 radii, float sigma) { | ||
| return colorCutoutGeneral(x0l, x0r, y0, y0 - radii.y, y0, radii, sigma); | ||
| } | ||
| // The blurred color value for the point at `pos` with the top left corner of the box at | ||
| // `p_{0_"rect"}` and the bottom right corner of the box at `p_{1_"rect"}`. | ||
| float color(vec2 pos, vec2 p0Rect, vec2 p1Rect, vec2 radii, float sigma) { | ||
| // Compute the vector distances `p_0` and `p_1`. | ||
| vec2 p0 = p0Rect - pos, p1 = p1Rect - pos; | ||
| // Compute the basic color `"colorFromRect"_sigma(p_0, p_1)`. This is all we have to do if | ||
| // the box is unrounded. | ||
| float cRect = colorFromRect(p0, p1, sigma); | ||
| if (radii.x == 0.0 || radii.y == 0.0) | ||
| return cRect; | ||
| // Compute the inner corners of the box, taking border radii into account: `x_{0_l}`, | ||
| // `y_{0_t}`, `x_{0_r}`, and `y_{0_b}`. | ||
| float x0l = p0.x + radii.x; | ||
| float y0t = p1.y - radii.y; | ||
| float x0r = p1.x - radii.x; | ||
| float y0b = p0.y + radii.y; | ||
| // Compute the final color: | ||
| // | ||
| // "colorFromRect"_sigma(p_0, p_1) - | ||
| // ("colorCutoutTop"_sigma(x_{0_l}, x_{0_r}, y_{0_t}, a, b) + | ||
| // "colorCutoutBottom"_sigma(x_{0_l}, x_{0_r}, y_{0_b}, a, b)) | ||
| float cCutoutTop = colorCutoutTop(x0l, x0r, y0t, radii, sigma); | ||
| float cCutoutBottom = colorCutoutBottom(x0l, x0r, y0b, radii, sigma); | ||
| return cRect - (cCutoutTop + cCutoutBottom); | ||
| } | ||
| void main(void) { | ||
| vec2 pos = vPosition.xy; | ||
| vec2 p0Rect = vBorderPosition.xy, p1Rect = vBorderPosition.zw; | ||
| vec2 radii = vBorderRadii.xy; | ||
| float sigma = vBlurRadius / 2.0; | ||
| float value = color(pos, p0Rect, p1Rect, radii, sigma); | ||
| SetFragColor(vec4(vColor.rgb, max(value, 0.0))); | ||
| } | ||
| @@ -0,0 +1,14 @@ | ||
| /* This Source Code Form is subject to the terms of the Mozilla Public | ||
| * License, v. 2.0. If a copy of the MPL was not distributed with this | ||
| * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||
| void main(void) | ||
| { | ||
| vPosition = aPosition.xy; | ||
| vColor = aColorRectTL; | ||
| vBorderPosition = aBorderPosition; | ||
| vBorderRadii = aBorderRadii; | ||
| vBlurRadius = aBlurRadius; | ||
| gl_Position = uTransform * vec4(aPosition, 1.0); | ||
| } | ||
| @@ -0,0 +1,8 @@ | ||
| /* This Source Code Form is subject to the terms of the Mozilla Public | ||
| * License, v. 2.0. If a copy of the MPL was not distributed with this | ||
| * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||
| void main(void) | ||
| { | ||
| SetFragColor(vColor); | ||
| } |
| @@ -0,0 +1,9 @@ | ||
| /* This Source Code Form is subject to the terms of the Mozilla Public | ||
| * License, v. 2.0. If a copy of the MPL was not distributed with this | ||
| * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||
| void main(void) | ||
| { | ||
| vColor = aColorRectTL / 255.0; | ||
| gl_Position = uTransform * vec4(aPosition, 1.0); | ||
| } |
| @@ -0,0 +1,8 @@ | ||
| /* This Source Code Form is subject to the terms of the Mozilla Public | ||
| * License, v. 2.0. If a copy of the MPL was not distributed with this | ||
| * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||
| void main(void) | ||
| { | ||
| SetFragColor(vColor); | ||
| } |
| @@ -0,0 +1,11 @@ | ||
| /* This Source Code Form is subject to the terms of the Mozilla Public | ||
| * License, v. 2.0. If a copy of the MPL was not distributed with this | ||
| * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||
| void main(void) | ||
| { | ||
| vColor = aColorRectTL; | ||
| vec4 pos = vec4(aPosition, 1.0); | ||
| pos.xy = floor(pos.xy * uDevicePixelRatio + 0.5) / uDevicePixelRatio; | ||
| gl_Position = uTransform * pos; | ||
| } |
| @@ -0,0 +1,13 @@ | ||
| /* This Source Code Form is subject to the terms of the Mozilla Public | ||
| * License, v. 2.0. If a copy of the MPL was not distributed with this | ||
| * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||
| void main(void) | ||
| { | ||
| #ifdef SERVO_ES2 | ||
| float alpha = Texture(sDiffuse, vColorTexCoord.xy).a; | ||
| #else | ||
| float alpha = Texture(sDiffuse, vColorTexCoord.xy).r; | ||
| #endif | ||
| SetFragColor(vec4(vColor.xyz, vColor.w * alpha)); | ||
| } |
| @@ -0,0 +1,12 @@ | ||
| /* This Source Code Form is subject to the terms of the Mozilla Public | ||
| * License, v. 2.0. If a copy of the MPL was not distributed with this | ||
| * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||
| void main(void) | ||
| { | ||
| vColor = aColorRectTL; | ||
| vColorTexCoord = aColorTexCoordRectTop.xy; | ||
| vec4 pos = vec4(aPosition, 1.0); | ||
| pos.xy = floor(pos.xy * uDevicePixelRatio + 0.5) / uDevicePixelRatio; | ||
| gl_Position = uTransform * pos; | ||
| } |
| @@ -0,0 +1,42 @@ | ||
| /* This Source Code Form is subject to the terms of the Mozilla Public | ||
| * License, v. 2.0. If a copy of the MPL was not distributed with this | ||
| * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||
| #version 110 | ||
| #define SERVO_ES2 | ||
| precision highp float; | ||
| uniform sampler2D sDiffuse; | ||
| uniform sampler2D sMask; | ||
| uniform vec4 uBlendParams; | ||
| uniform vec4 uAtlasParams; | ||
| uniform vec2 uDirection; | ||
| uniform vec4 uFilterParams; | ||
| varying vec2 vPosition; | ||
| varying vec4 vColor; | ||
| varying vec2 vColorTexCoord; | ||
| varying vec2 vMaskTexCoord; | ||
| varying vec4 vBorderPosition; | ||
| varying vec4 vBorderRadii; | ||
| varying vec2 vDestTextureSize; | ||
| varying vec2 vSourceTextureSize; | ||
| varying float vBlurRadius; | ||
| varying vec4 vTileParams; | ||
| varying vec4 vClipInRect; | ||
| varying vec4 vClipOutRect; | ||
| vec4 Texture(sampler2D sampler, vec2 texCoord) { | ||
| return texture2D(sampler, texCoord); | ||
| } | ||
| float GetAlphaFromMask(vec4 mask) { | ||
| return mask.a; | ||
| } | ||
| void SetFragColor(vec4 color) { | ||
| gl_FragColor = color; | ||
| } | ||
| @@ -0,0 +1,70 @@ | ||
| /* This Source Code Form is subject to the terms of the Mozilla Public | ||
| * License, v. 2.0. If a copy of the MPL was not distributed with this | ||
| * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||
| #version 110 | ||
| #define SERVO_ES2 | ||
| uniform mat4 uTransform; | ||
| uniform vec4 uOffsets[32]; | ||
| uniform vec4 uClipRects[64]; | ||
| uniform mat4 uMatrixPalette[32]; | ||
| uniform vec2 uDirection; | ||
| uniform vec4 uBlendParams; | ||
| uniform vec4 uFilterParams; | ||
| uniform float uDevicePixelRatio; | ||
| uniform vec4 uTileParams[64]; | ||
| attribute vec3 aPosition; | ||
| attribute vec4 aPositionRect; // Width can be negative to flip horizontally (for border corners). | ||
| attribute vec4 aColorRectTL; | ||
| attribute vec4 aColorRectTR; | ||
| attribute vec4 aColorRectBR; | ||
| attribute vec4 aColorRectBL; | ||
| attribute vec4 aColorTexCoordRectTop; | ||
| attribute vec4 aColorTexCoordRectBottom; | ||
| attribute vec4 aMaskTexCoordRectTop; | ||
| attribute vec4 aMaskTexCoordRectBottom; | ||
| attribute vec4 aBorderPosition; | ||
| attribute vec4 aBorderRadii; | ||
| attribute vec2 aSourceTextureSize; | ||
| attribute vec2 aDestTextureSize; | ||
| attribute float aBlurRadius; | ||
| // x = matrix index; y = clip-in rect; z = clip-out rect; w = tile params index. | ||
| // | ||
| // A negative w value activates border corner mode. In this mode, the TR and BL colors are ignored, | ||
| // the color of the top left corner applies to all vertices of the top left triangle, and the color | ||
| // of the bottom right corner applies to all vertices of the bottom right triangle. | ||
| attribute vec4 aMisc; | ||
| varying vec2 vPosition; | ||
| varying vec4 vColor; | ||
| varying vec2 vColorTexCoord; | ||
| varying vec2 vMaskTexCoord; | ||
| varying vec4 vBorderPosition; | ||
| varying vec4 vBorderRadii; | ||
| varying vec2 vDestTextureSize; | ||
| varying vec2 vSourceTextureSize; | ||
| varying float vBlurRadius; | ||
| varying vec4 vTileParams; | ||
| varying vec4 vClipInRect; | ||
| varying vec4 vClipOutRect; | ||
| int Bottom7Bits(int value) { | ||
| return value % 0x80; | ||
| } | ||
| bool IsBottomTriangle() { | ||
| // FIXME(pcwalton): No gl_VertexID in OpenGL ES 2. We'll need some extra data. | ||
| return false; | ||
| } | ||
| vec2 SnapToPixels(vec2 pos) | ||
| { | ||
| // Snap the vertex to pixel position to guarantee correct texture | ||
| // sampling when using bilinear filtering. | ||
| // TODO(gw): ES2 doesn't have round(). Do we ever get negative coords here? | ||
| return floor(0.5 + pos * uDevicePixelRatio) / uDevicePixelRatio; | ||
| } |
| @@ -0,0 +1,148 @@ | ||
| /* This Source Code Form is subject to the terms of the Mozilla Public | ||
| * License, v. 2.0. If a copy of the MPL was not distributed with this | ||
| * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||
| vec3 rgbToHsv(vec3 c) { | ||
| float value = max(max(c.r, c.g), c.b); | ||
| float chroma = value - min(min(c.r, c.g), c.b); | ||
| if (chroma == 0.0) { | ||
| return vec3(0.0); | ||
| } | ||
| float saturation = chroma / value; | ||
| float hue; | ||
| if (c.r == value) | ||
| hue = (c.g - c.b) / chroma; | ||
| else if (c.g == value) | ||
| hue = 2.0 + (c.b - c.r) / chroma; | ||
| else // if (c.b == value) | ||
| hue = 4.0 + (c.r - c.g) / chroma; | ||
| hue *= 1.0/6.0; | ||
| if (hue < 0.0) | ||
| hue += 1.0; | ||
| return vec3(hue, saturation, value); | ||
| } | ||
| vec3 hsvToRgb(vec3 c) { | ||
| if (c.s == 0.0) { | ||
| return vec3(c.z); | ||
| } | ||
| float hue = c.x * 6.0; | ||
| int sector = int(hue); | ||
| float residualHue = hue - float(sector); | ||
| vec3 pqt = c.z * vec3(1.0 - c.y, 1.0 - c.y * residualHue, 1.0 - c.y * (1.0 - residualHue)); | ||
| if (sector == 0) | ||
| return vec3(c.z, pqt.z, pqt.x); | ||
| if (sector == 1) | ||
| return vec3(pqt.y, c.z, pqt.x); | ||
| if (sector == 2) | ||
| return vec3(pqt.x, c.z, pqt.z); | ||
| if (sector == 3) | ||
| return vec3(pqt.x, pqt.y, c.z); | ||
| if (sector == 4) | ||
| return vec3(pqt.z, pqt.x, c.z); | ||
| return vec3(c.z, pqt.x, pqt.y); | ||
| } | ||
| float gauss(float x, float sigma) { | ||
| if (sigma == 0.0) | ||
| return 1.0; | ||
| return (1.0 / sqrt(6.283185307179586 * sigma * sigma)) * exp(-(x * x) / (2.0 * sigma * sigma)); | ||
| } | ||
| vec4 Blur(float radius, vec2 direction) { | ||
| #ifdef SERVO_ES2 | ||
| // TODO(gw): for loops have to be unrollable on es2. | ||
| return vec4(1.0, 0.0, 0.0, 1.0); | ||
| #else | ||
| int range = int(radius) * 3; | ||
| float sigma = radius / 2.0; | ||
| vec4 color = vec4(0.0); | ||
| for (int offset = -range; offset <= range; offset++) { | ||
| float offsetF = float(offset); | ||
| // Here, we use the vMaskTexCoord.xy (i.e. the muv) to store the texture size. | ||
| vec2 texCoord = vColorTexCoord.xy + vec2(offsetF) / vMaskTexCoord.xy * direction; | ||
| vec4 x = texCoord.x >= 0.0 && | ||
| texCoord.x <= 1.0 && | ||
| texCoord.y >= 0.0 && | ||
| texCoord.y <= 1.0 ? | ||
| Texture(sDiffuse, texCoord) : | ||
| vec4(0.0); | ||
| color += x * gauss(offsetF, sigma); | ||
| } | ||
| return color; | ||
| #endif | ||
| } | ||
| vec4 Contrast(vec4 Cs, float amount) { | ||
| return vec4(Cs.rgb * amount - 0.5 * amount + 0.5, 1.0); | ||
| } | ||
| vec4 Grayscale(vec4 Cs, float amount) { | ||
| float ia = 1.0 - amount; | ||
| return mat4(vec4(0.2126 + 0.7874 * ia, 0.2126 - 0.2126 * ia, 0.2126 - 0.2126 * ia, 0.0), | ||
| vec4(0.7152 - 0.7152 * ia, 0.7152 + 0.2848 * ia, 0.7152 - 0.7152 * ia, 0.0), | ||
| vec4(0.0722 - 0.0722 * ia, 0.0722 - 0.0722 * ia, 0.0722 + 0.9278 * ia, 0.0), | ||
| vec4(0.0, 0.0, 0.0, 1.0)) * Cs; | ||
| } | ||
| vec4 HueRotate(vec4 Cs, float amount) { | ||
| vec3 CsHsv = rgbToHsv(Cs.rgb); | ||
| CsHsv.x = mod(CsHsv.x + amount / 6.283185307179586, 1.0); | ||
| return vec4(hsvToRgb(CsHsv), Cs.a); | ||
| } | ||
| vec4 Invert(vec4 Cs, float amount) { | ||
| return mix(Cs, vec4(1.0, 1.0, 1.0, Cs.a) - vec4(Cs.rgb, 0.0), amount); | ||
| } | ||
| vec4 Saturate(vec4 Cs, float amount) { | ||
| return vec4(hsvToRgb(min(vec3(1.0, amount, 1.0) * rgbToHsv(Cs.rgb), vec3(1.0))), Cs.a); | ||
| } | ||
| vec4 Sepia(vec4 Cs, float amount) { | ||
| float ia = 1.0 - amount; | ||
| return mat4(vec4(0.393 + 0.607 * ia, 0.349 - 0.349 * ia, 0.272 - 0.272 * ia, 0.0), | ||
| vec4(0.769 - 0.769 * ia, 0.686 + 0.314 * ia, 0.534 - 0.534 * ia, 0.0), | ||
| vec4(0.189 - 0.189 * ia, 0.168 - 0.168 * ia, 0.131 + 0.869 * ia, 0.0), | ||
| vec4(0.0, 0.0, 0.0, 1.0)) * Cs; | ||
| } | ||
| void main(void) | ||
| { | ||
| // TODO: May be best to have separate shaders (esp. on Tegra) | ||
| int filterOp = int(uFilterParams.x); | ||
| float amount = uFilterParams.y; | ||
| // Return yellow if none of the branches match (shouldn't happen). | ||
| vec4 result = vec4(1.0, 1.0, 0.0, 1.0); | ||
| if (filterOp == 0) { | ||
| // Gaussian blur is specially handled: | ||
| result = Blur(amount, uFilterParams.zw); | ||
| } else { | ||
| vec4 Cs = Texture(sDiffuse, vColorTexCoord); | ||
| if (filterOp == 1) { | ||
| result = Contrast(Cs, amount); | ||
| } else if (filterOp == 2) { | ||
| result = Grayscale(Cs, amount); | ||
| } else if (filterOp == 3) { | ||
| result = HueRotate(Cs, amount); | ||
| } else if (filterOp == 4) { | ||
| result = Invert(Cs, amount); | ||
| } else if (filterOp == 5) { | ||
| result = Saturate(Cs, amount); | ||
| } else if (filterOp == 6) { | ||
| result = Sepia(Cs, amount); | ||
| } | ||
| } | ||
| SetFragColor(result); | ||
| } | ||
| @@ -0,0 +1,12 @@ | ||
| /* This Source Code Form is subject to the terms of the Mozilla Public | ||
| * License, v. 2.0. If a copy of the MPL was not distributed with this | ||
| * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||
| void main(void) | ||
| { | ||
| vColorTexCoord = aColorTexCoordRectTop.xy; | ||
| vMaskTexCoord = aMaskTexCoordRectTop.xy; | ||
| vec4 pos = vec4(aPosition, 1.0); | ||
| pos.xy = SnapToPixels(pos.xy); | ||
| gl_Position = uTransform * pos; | ||
| } |
| @@ -0,0 +1,41 @@ | ||
| /* This Source Code Form is subject to the terms of the Mozilla Public | ||
| * License, v. 2.0. If a copy of the MPL was not distributed with this | ||
| * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||
| #version 150 | ||
| #define SERVO_GL3 | ||
| uniform sampler2D sDiffuse; | ||
| uniform sampler2D sMask; | ||
| uniform vec4 uBlendParams; | ||
| uniform vec2 uDirection; | ||
| uniform vec4 uFilterParams; | ||
| in vec2 vPosition; | ||
| in vec4 vColor; | ||
| in vec2 vColorTexCoord; | ||
| in vec2 vMaskTexCoord; | ||
| in vec4 vBorderPosition; | ||
| in vec4 vBorderRadii; | ||
| in vec2 vDestTextureSize; | ||
| in vec2 vSourceTextureSize; | ||
| in float vBlurRadius; | ||
| in vec4 vTileParams; | ||
| in vec4 vClipInRect; | ||
| in vec4 vClipOutRect; | ||
| out vec4 oFragColor; | ||
| vec4 Texture(sampler2D sampler, vec2 texCoord) { | ||
| return texture(sampler, texCoord); | ||
| } | ||
| float GetAlphaFromMask(vec4 mask) { | ||
| return mask.r; | ||
| } | ||
| void SetFragColor(vec4 color) { | ||
| oFragColor = color; | ||
| } | ||
| @@ -0,0 +1,68 @@ | ||
| /* This Source Code Form is subject to the terms of the Mozilla Public | ||
| * License, v. 2.0. If a copy of the MPL was not distributed with this | ||
| * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||
| #version 150 | ||
| #define SERVO_GL3 | ||
| uniform mat4 uTransform; | ||
| uniform vec4 uOffsets[32]; | ||
| uniform vec4 uClipRects[64]; | ||
| uniform mat4 uMatrixPalette[32]; | ||
| uniform vec2 uDirection; | ||
| uniform vec4 uBlendParams; | ||
| uniform vec4 uFilterParams; | ||
| uniform float uDevicePixelRatio; | ||
| uniform vec4 uTileParams[64]; | ||
| uniform vec4 uAtlasParams; | ||
| in vec3 aPosition; | ||
| in vec4 aPositionRect; // Width can be negative to flip horizontally (for border corners). | ||
| in vec4 aColorRectTL; | ||
| in vec4 aColorRectTR; | ||
| in vec4 aColorRectBR; | ||
| in vec4 aColorRectBL; | ||
| in vec4 aColorTexCoordRectTop; | ||
| in vec4 aColorTexCoordRectBottom; | ||
| in vec4 aMaskTexCoordRectTop; | ||
| in vec4 aMaskTexCoordRectBottom; | ||
| in vec4 aBorderPosition; | ||
| in vec4 aBorderRadii; | ||
| in vec2 aSourceTextureSize; | ||
| in vec2 aDestTextureSize; | ||
| in float aBlurRadius; | ||
| // x = matrix index; y = clip-in rect; z = clip-out rect; w = tile params index. | ||
| // | ||
| // A negative w value activates border corner mode. In this mode, the TR and BL colors are ignored, | ||
| // the color of the top left corner applies to all vertices of the top left triangle, and the color | ||
| // of the bottom right corner applies to all vertices of the bottom right triangle. | ||
| in vec4 aMisc; | ||
| out vec2 vPosition; | ||
| out vec4 vColor; | ||
| out vec2 vColorTexCoord; | ||
| out vec2 vMaskTexCoord; | ||
| out vec4 vBorderPosition; | ||
| out vec4 vBorderRadii; | ||
| out vec2 vDestTextureSize; | ||
| out vec2 vSourceTextureSize; | ||
| out float vBlurRadius; | ||
| out vec4 vTileParams; | ||
| out vec4 vClipInRect; | ||
| out vec4 vClipOutRect; | ||
| int Bottom7Bits(int value) { | ||
| return value & 0x7f; | ||
| } | ||
| bool IsBottomTriangle() { | ||
| return gl_VertexID > 2; | ||
| } | ||
| vec2 SnapToPixels(vec2 pos) | ||
| { | ||
| // Snap the vertex to pixel position to guarantee correct texture | ||
| // sampling when using bilinear filtering. | ||
| return round(pos * uDevicePixelRatio) / uDevicePixelRatio; | ||
| } |
| @@ -0,0 +1,8 @@ | ||
| /* This Source Code Form is subject to the terms of the Mozilla Public | ||
| * License, v. 2.0. If a copy of the MPL was not distributed with this | ||
| * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||
| void main(void) | ||
| { | ||
| SetFragColor(vColor); | ||
| } |
| @@ -0,0 +1,9 @@ | ||
| /* This Source Code Form is subject to the terms of the Mozilla Public | ||
| * License, v. 2.0. If a copy of the MPL was not distributed with this | ||
| * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||
| void main(void) | ||
| { | ||
| vColor = aColorRectTL / 255.0; | ||
| gl_Position = uTransform * vec4(aPosition, 1.0); | ||
| } |
| @@ -0,0 +1,38 @@ | ||
| /* This Source Code Form is subject to the terms of the Mozilla Public | ||
| * License, v. 2.0. If a copy of the MPL was not distributed with this | ||
| * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||
| // GLSL point in rect test. | ||
| // See: https://stackoverflow.com/questions/12751080/glsl-point-inside-box-test | ||
| bool PointInRect(vec2 p, vec2 p0, vec2 p1) | ||
| { | ||
| vec2 s = step(p0, p) - step(p1, p); | ||
| return s.x * s.y != 0.0; | ||
| } | ||
| void main(void) | ||
| { | ||
| // Clip out. | ||
| if (PointInRect(vPosition, vClipOutRect.xy, vClipOutRect.zw)) { | ||
| discard; | ||
| } | ||
| // Clip in. | ||
| if (!PointInRect(vPosition, vClipInRect.xy, vClipInRect.zw)) { | ||
| discard; | ||
| } | ||
| // Apply image tiling parameters (offset and scale) to color UVs. | ||
| vec2 colorTexCoord = vTileParams.xy + fract(vColorTexCoord.xy) * vTileParams.zw; | ||
| vec2 maskTexCoord = vMaskTexCoord.xy; | ||
| // Fetch the diffuse and mask texels. | ||
| vec4 diffuse = Texture(sDiffuse, colorTexCoord); | ||
| vec4 mask = Texture(sMask, maskTexCoord); | ||
| // Extract alpha from the mask (component depends on platform) | ||
| float alpha = GetAlphaFromMask(mask); | ||
| // Write the final fragment color. | ||
| SetFragColor(diffuse * vec4(vColor.rgb, vColor.a * alpha)); | ||
| } |
| @@ -0,0 +1,112 @@ | ||
| /* This Source Code Form is subject to the terms of the Mozilla Public | ||
| * License, v. 2.0. If a copy of the MPL was not distributed with this | ||
| * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||
| vec2 Bilerp2(vec2 tl, vec2 tr, vec2 br, vec2 bl, vec2 st) { | ||
| return mix(mix(tl, bl, st.y), mix(tr, br, st.y), st.x); | ||
| } | ||
| vec4 Bilerp4(vec4 tl, vec4 tr, vec4 br, vec4 bl, vec2 st) { | ||
| return mix(mix(tl, bl, st.y), mix(tr, br, st.y), st.x); | ||
| } | ||
| void main(void) | ||
| { | ||
| // Extract the image tiling parameters. | ||
| // These are passed to the fragment shader, since | ||
| // the uv interpolation must be done per-fragment. | ||
| vTileParams = uTileParams[Bottom7Bits(int(aMisc.w))]; | ||
| // Determine clip rects. | ||
| vClipOutRect = uClipRects[int(aMisc.z)]; | ||
| vec4 clipInRect = uClipRects[int(aMisc.y)]; | ||
| // Extract the complete (stacking context + css transform) transform | ||
| // for this vertex. Transform the position by it. | ||
| vec2 offsetParams = uOffsets[Bottom7Bits(int(aMisc.x))].xy; | ||
| mat4 matrix = uMatrixPalette[Bottom7Bits(int(aMisc.x))]; | ||
| vec2 p0 = aPositionRect.xy + offsetParams; | ||
| vec2 p1 = p0 + aPositionRect.zw; | ||
| vec2 rect_origin = SnapToPixels(p0); | ||
| vec2 rect_size = SnapToPixels(p1) - rect_origin; | ||
| // Determine the position, color, and mask texture coordinates of this vertex. | ||
| vec4 localPos = vec4(0.0, 0.0, 0.0, 1.0); | ||
| bool isBorderCorner = int(aMisc.w) >= 0x80; | ||
| bool isBottomTriangle = IsBottomTriangle(); | ||
| if (aPosition.y == 0.0) { | ||
| localPos.y = rect_origin.y; | ||
| if (aPosition.x == 0.0) { | ||
| localPos.x = rect_origin.x; | ||
| if (isBorderCorner) { | ||
| vColor = isBottomTriangle ? aColorRectBL : aColorRectTR; | ||
| } | ||
| } else { | ||
| localPos.x = rect_origin.x + rect_size.x; | ||
| if (isBorderCorner) { | ||
| vColor = aColorRectTR; | ||
| } | ||
| } | ||
| } else { | ||
| localPos.y = rect_origin.y + rect_size.y; | ||
| if (aPosition.x == 0.0) { | ||
| localPos.x = rect_origin.x; | ||
| if (isBorderCorner) { | ||
| vColor = aColorRectBL; | ||
| } | ||
| } else { | ||
| localPos.x = rect_origin.x + rect_size.x; | ||
| if (isBorderCorner) { | ||
| vColor = isBottomTriangle ? aColorRectBL : aColorRectTR; | ||
| } | ||
| } | ||
| } | ||
| // Rotate or clip as necessary. If there is no rotation, we can clip here in the vertex shader | ||
| // and save a whole bunch of fragment shader invocations. If there is a rotation, we fall back | ||
| // to FS clipping. | ||
| // | ||
| // The rotation angle is encoded as a negative bottom left u coordinate. (uv coordinates should | ||
| // always be nonnegative normally, and gradients don't use color textures, so this is fine.) | ||
| vec4 colorTexCoordRectBottom = aColorTexCoordRectBottom; | ||
| vec2 localST; | ||
| if (colorTexCoordRectBottom.z < 0.0) { | ||
| float angle = -colorTexCoordRectBottom.z; | ||
| vec2 center = rect_origin + rect_size / 2.0; | ||
| vec2 translatedPos = localPos.xy - center; | ||
| localST = (localPos.xy - rect_origin) / rect_size; | ||
| localPos.xy = vec2(translatedPos.x * cos(angle) - translatedPos.y * sin(angle), | ||
| translatedPos.x * sin(angle) + translatedPos.y * cos(angle)) + center; | ||
| colorTexCoordRectBottom.z = aColorTexCoordRectTop.x; | ||
| vClipInRect = clipInRect; | ||
| } else { | ||
| localPos.x = clamp(localPos.x, clipInRect.x, clipInRect.z); | ||
| localPos.y = clamp(localPos.y, clipInRect.y, clipInRect.w); | ||
| localST = (localPos.xy - rect_origin) / rect_size; | ||
| vClipInRect = vec4(-1e37, -1e37, 1e38, 1e38); | ||
| } | ||
| vColorTexCoord = Bilerp2(aColorTexCoordRectTop.xy, aColorTexCoordRectTop.zw, | ||
| colorTexCoordRectBottom.xy, colorTexCoordRectBottom.zw, | ||
| localST); | ||
| vMaskTexCoord = Bilerp2(aMaskTexCoordRectTop.xy, aMaskTexCoordRectTop.zw, | ||
| aMaskTexCoordRectBottom.xy, aMaskTexCoordRectBottom.zw, | ||
| localST); | ||
| if (!isBorderCorner) { | ||
| vColor = Bilerp4(aColorRectTL, aColorRectTR, aColorRectBR, aColorRectBL, localST); | ||
| } | ||
| // Normalize the vertex color and mask texture coordinates. | ||
| vColor /= 255.0; | ||
| vMaskTexCoord /= uAtlasParams.zw; | ||
| vPosition = localPos.xy; | ||
| vec4 worldPos = matrix * localPos; | ||
| // Transform by the orthographic projection into clip space. | ||
| gl_Position = uTransform * worldPos; | ||
| } | ||
| @@ -0,0 +1,11 @@ | ||
| /* This Source Code Form is subject to the terms of the Mozilla Public | ||
| * License, v. 2.0. If a copy of the MPL was not distributed with this | ||
| * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||
| void main(void) { | ||
| vec2 textureSize = vBorderPosition.zw - vBorderPosition.xy; | ||
| vec2 colorTexCoord = vBorderPosition.xy + mod(vColorTexCoord.xy, 1.0) * textureSize; | ||
| vec4 diffuse = Texture(sDiffuse, colorTexCoord); | ||
| SetFragColor(diffuse); | ||
| } | ||
| @@ -0,0 +1,11 @@ | ||
| /* This Source Code Form is subject to the terms of the Mozilla Public | ||
| * License, v. 2.0. If a copy of the MPL was not distributed with this | ||
| * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||
| void main(void) | ||
| { | ||
| vColorTexCoord = aBorderRadii.xy; | ||
| vBorderPosition = aBorderPosition; | ||
| gl_Position = uTransform * vec4(aPosition, 1.0); | ||
| } | ||