ps_quad_conic_gradient.glsl (2908B)
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 /// This shader renders radial gradients in a color or alpha target. 6 7 #include ps_quad,gradient 8 9 #define PI 3.141592653589793 10 11 // x: start offset, y: offset scale, z: angle 12 // Packed in to a vector to work around bug 1630356. 13 flat varying highp vec3 v_start_offset_offset_scale_angle_vec; 14 #define v_start_offset v_start_offset_offset_scale_angle_vec.x 15 #define v_offset_scale v_start_offset_offset_scale_angle_vec.y 16 #define v_angle v_start_offset_offset_scale_angle_vec.z 17 18 varying highp vec2 v_dir; 19 20 #ifdef WR_VERTEX_SHADER 21 struct ConicGradient { 22 vec2 center; 23 vec2 scale; 24 float start_offset; 25 float end_offset; 26 float angle; 27 // 1.0 if the gradient should be repeated, 0.0 otherwise. 28 float repeat; 29 }; 30 31 ConicGradient fetch_conic_gradient(int address) { 32 vec4[2] data = fetch_from_gpu_buffer_2f(address); 33 34 return ConicGradient( 35 data[0].xy, 36 data[0].zw, 37 data[1].x, 38 data[1].y, 39 data[1].z, 40 data[1].w 41 ); 42 } 43 44 void pattern_vertex(PrimitiveInfo info) { 45 ConicGradient gradient = fetch_conic_gradient(info.pattern_input.x); 46 v_gradient_address.x = info.pattern_input.y; 47 v_gradient_repeat.x = gradient.repeat; 48 49 // Store 1/d where d = end_offset - start_offset 50 // If d = 0, we can't get its reciprocal. Instead, just use a zero scale. 51 float d = gradient.end_offset - gradient.start_offset; 52 v_offset_scale = d != 0.0 ? 1.0 / d : 0.0; 53 54 v_angle = PI / 2.0 - gradient.angle; 55 v_start_offset = gradient.start_offset * v_offset_scale; 56 v_dir = ((info.local_pos - info.local_prim_rect.p0) * gradient.scale - gradient.center); 57 } 58 59 #endif 60 61 62 #ifdef WR_FRAGMENT_SHADER 63 64 // From https://math.stackexchange.com/questions/1098487/atan2-faster-approximation 65 float approx_atan2(float y, float x) { 66 vec2 a = abs(vec2(x, y)); 67 float slope = min(a.x, a.y) / max(a.x, a.y); 68 float s2 = slope * slope; 69 float r = ((-0.0464964749 * s2 + 0.15931422) * s2 - 0.327622764) * s2 * slope + slope; 70 71 r = if_then_else(float(a.y > a.x), 1.57079637 - r, r); 72 r = if_then_else(float(x < 0.0), 3.14159274 - r, r); 73 // To match atan2's behavior, -0.0 should count as negative and flip the sign of r. 74 // Does this matter in practice in the context of conic gradients? 75 r = y < 0.0 ? -r : r; 76 77 return r; 78 } 79 80 vec4 pattern_fragment(vec4 color) { 81 // Use inverse trig to find the angle offset from the relative position. 82 vec2 current_dir = v_dir; 83 float current_angle = approx_atan2(current_dir.y, current_dir.x) + v_angle; 84 float offset = fract(current_angle / (2.0 * PI)) * v_offset_scale - v_start_offset; 85 86 color *= sample_gradient(offset); 87 return color; 88 } 89 90 #endif