forked from AuroraMiddleware/gtk
900a4e4d31
Move the resources of each renderer to its subdirectory. We've previously done that for the ngl renderer, but it is better to be consistent and do it for all the renderers.
96 lines
2.8 KiB
GLSL
96 lines
2.8 KiB
GLSL
// VERTEX_SHADER
|
|
uniform vec4 u_points;
|
|
|
|
_NOPERSPECTIVE_ _OUT_ vec4 info;
|
|
|
|
void main() {
|
|
gl_Position = u_projection * (u_modelview * vec4(aPosition, 0.0, 1.0));
|
|
|
|
vec2 mv0 = u_modelview[0].xy;
|
|
vec2 mv1 = u_modelview[1].xy;
|
|
vec2 offset = aPosition - u_points.xy;
|
|
vec2 coord = vec2(dot(mv0, offset),
|
|
dot(mv1, offset));
|
|
|
|
// Original equation:
|
|
// VS | maxDist = length(end - start);
|
|
// VS | gradient = end - start;
|
|
// VS | gradientLength = length(gradient);
|
|
// FS | pos = frag_coord - start
|
|
// FS | proj = (dot(gradient, pos) / (gradientLength * gradientLength)) * gradient
|
|
// FS | offset = length(proj) / maxDist
|
|
|
|
// Simplified formula derivation:
|
|
// 1. Notice that maxDist = gradientLength:
|
|
// offset = length(proj) / gradientLength
|
|
// 2. Let gnorm = gradient / gradientLength, then:
|
|
// proj = (dot(gnorm * gradientLength, pos) / (gradientLength * gradientLength)) * (gnorm * gradientLength) =
|
|
// = dot(gnorm, pos) * gnorm
|
|
// 3. Since gnorm is unit length then:
|
|
// length(proj) = length(dot(gnorm, pos) * gnorm) = dot(gnorm, pos)
|
|
// 4. We can avoid the FS division by passing a scaled pos from the VS:
|
|
// offset = dot(gnorm, pos) / gradientLength = dot(gnorm, pos / gradientLength)
|
|
// 5. 1.0 / length(gradient) is inversesqrt(dot(gradient, gradient)) in GLSL
|
|
vec2 gradient = vec2(dot(mv0, u_points.zw),
|
|
dot(mv1, u_points.zw));
|
|
float rcp_gradient_length = inversesqrt(dot(gradient, gradient));
|
|
|
|
info = rcp_gradient_length * vec4(coord, gradient);
|
|
}
|
|
|
|
// FRAGMENT_SHADER:
|
|
#ifdef GSK_LEGACY
|
|
uniform int u_num_color_stops;
|
|
#else
|
|
uniform highp int u_num_color_stops; // Why? Because it works like this.
|
|
#endif
|
|
|
|
uniform float u_color_stops[6 * 5];
|
|
uniform bool u_repeat;
|
|
|
|
_NOPERSPECTIVE_ _IN_ vec4 info;
|
|
|
|
float get_offset(int index) {
|
|
return u_color_stops[5 * index];
|
|
}
|
|
|
|
vec4 get_color(int index) {
|
|
int base = 5 * index + 1;
|
|
|
|
return vec4(u_color_stops[base],
|
|
u_color_stops[base + 1],
|
|
u_color_stops[base + 2],
|
|
u_color_stops[base + 3]);
|
|
}
|
|
|
|
void main() {
|
|
float offset = dot(info.xy, info.zw);
|
|
|
|
if (u_repeat) {
|
|
offset = fract(offset);
|
|
}
|
|
|
|
if (offset < get_offset(0)) {
|
|
gskSetOutputColor(gsk_scaled_premultiply(get_color(0), u_alpha));
|
|
return;
|
|
}
|
|
|
|
int n = u_num_color_stops - 1;
|
|
for (int i = 0; i < n; i++) {
|
|
float curr_offset = get_offset(i);
|
|
float next_offset = get_offset(i + 1);
|
|
|
|
if (offset >= curr_offset && offset < next_offset) {
|
|
float f = (offset - curr_offset) / (next_offset - curr_offset);
|
|
vec4 curr_color = gsk_premultiply(get_color(i));
|
|
vec4 next_color = gsk_premultiply(get_color(i + 1));
|
|
vec4 color = mix(curr_color, next_color, f);
|
|
|
|
gskSetOutputColor(color * u_alpha);
|
|
return;
|
|
}
|
|
}
|
|
|
|
gskSetOutputColor(gsk_scaled_premultiply(get_color(n), u_alpha));
|
|
}
|