diff options
-rw-r--r-- | src/cairo-gl-composite.c | 83 | ||||
-rw-r--r-- | src/cairo-gl-private.h | 11 | ||||
-rw-r--r-- | src/cairo-gl-shaders.c | 92 |
3 files changed, 128 insertions, 58 deletions
diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c index 147c1b849..efbb7225c 100644 --- a/src/cairo-gl-composite.c +++ b/src/cairo-gl-composite.c @@ -195,14 +195,7 @@ _cairo_gl_gradient_operand_init (cairo_gl_operand_t *operand, return CAIRO_STATUS_SUCCESS; } else { cairo_radial_pattern_t *radial = (cairo_radial_pattern_t *) gradient; - double x0, y0, r0, x1, y1, r1; - - x0 = _cairo_fixed_to_double (radial->c1.x); - x1 = _cairo_fixed_to_double (radial->c2.x); - y0 = _cairo_fixed_to_double (radial->c1.y); - y1 = _cairo_fixed_to_double (radial->c2.y); - r0 = _cairo_fixed_to_double (radial->r1); - r1 = _cairo_fixed_to_double (radial->r2); + double x0, y0, r0, dx, dy, dr; status = _cairo_gl_create_gradient_texture (dst, gradient, @@ -210,6 +203,13 @@ _cairo_gl_gradient_operand_init (cairo_gl_operand_t *operand, if (unlikely (status)) return status; + x0 = _cairo_fixed_to_double (radial->c1.x); + y0 = _cairo_fixed_to_double (radial->c1.y); + r0 = _cairo_fixed_to_double (radial->r1); + dx = _cairo_fixed_to_double (radial->c2.x) - x0; + dy = _cairo_fixed_to_double (radial->c2.y) - y0; + dr = _cairo_fixed_to_double (radial->r2) - r0; + /* Translation matrix from the destination fragment coordinates * (pixels from lower left = 0,0) to the coordinates in the */ @@ -218,14 +218,23 @@ _cairo_gl_gradient_operand_init (cairo_gl_operand_t *operand, &pattern->matrix, &operand->radial.m); - operand->radial.circle_1_x = x1 - x0; - operand->radial.circle_1_y = y1 - y0; + operand->radial.circle_d_x = dx; + operand->radial.circle_d_y = dy; + operand->radial.circle_d_r = dr; + operand->radial.radius_0 = r0; - operand->radial.radius_1 = r1; + + operand->radial.a = dx * dx + dy * dy - dr * dr; operand->radial.extend = pattern->extend; - operand->type = CAIRO_GL_OPERAND_RADIAL_GRADIENT; + if (operand->radial.a == 0) + operand->type = CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0; + else if (pattern->extend == CAIRO_EXTEND_NONE) + operand->type = CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE; + else + operand->type = CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT; + return CAIRO_STATUS_SUCCESS; } @@ -241,7 +250,9 @@ _cairo_gl_operand_destroy (cairo_gl_operand_t *operand) case CAIRO_GL_OPERAND_LINEAR_GRADIENT: _cairo_gl_gradient_destroy (operand->linear.gradient); break; - case CAIRO_GL_OPERAND_RADIAL_GRADIENT: + case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0: + case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE: + case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT: _cairo_gl_gradient_destroy (operand->radial.gradient); break; case CAIRO_GL_OPERAND_TEXTURE: @@ -379,24 +390,28 @@ _cairo_gl_operand_bind_to_shader (cairo_gl_context_t *ctx, uniform_name, tex_unit); break; - case CAIRO_GL_OPERAND_RADIAL_GRADIENT: + case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE: + case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT: + strcpy (custom_part, "_a"); + _cairo_gl_shader_bind_float (ctx, + uniform_name, + operand->radial.a); + /* fall through */ + case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0: strcpy (custom_part, "_matrix"); _cairo_gl_shader_bind_matrix (ctx, uniform_name, &operand->radial.m); - strcpy (custom_part, "_circle_1"); - _cairo_gl_shader_bind_vec2 (ctx, + strcpy (custom_part, "_circle_d"); + _cairo_gl_shader_bind_vec3 (ctx, uniform_name, - operand->radial.circle_1_x, - operand->radial.circle_1_y); + operand->radial.circle_d_x, + operand->radial.circle_d_y, + operand->radial.circle_d_r); strcpy (custom_part, "_radius_0"); _cairo_gl_shader_bind_float (ctx, uniform_name, operand->radial.radius_0); - strcpy (custom_part, "_radius_1"); - _cairo_gl_shader_bind_float (ctx, - uniform_name, - operand->radial.radius_1); strcpy (custom_part, "_sampler"); _cairo_gl_shader_bind_texture(ctx, uniform_name, @@ -495,7 +510,9 @@ _cairo_gl_operand_setup_fixed (cairo_gl_operand_t *operand, default: ASSERT_NOT_REACHED; case CAIRO_GL_OPERAND_LINEAR_GRADIENT: - case CAIRO_GL_OPERAND_RADIAL_GRADIENT: + case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0: + case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE: + case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT: case CAIRO_GL_OPERAND_NONE: return; } @@ -558,7 +575,9 @@ _cairo_gl_operand_needs_setup (cairo_gl_operand_t *dest, dest->texture.attributes.filter != source->texture.attributes.filter || dest->texture.attributes.has_component_alpha != source->texture.attributes.has_component_alpha; case CAIRO_GL_OPERAND_LINEAR_GRADIENT: - case CAIRO_GL_OPERAND_RADIAL_GRADIENT: + case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0: + case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE: + case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT: /* XXX: improve this */ return TRUE; default: @@ -638,7 +657,9 @@ _cairo_gl_context_setup_operand (cairo_gl_context_t *ctx, _cairo_gl_texture_set_filter (ctx, GL_TEXTURE_1D, CAIRO_FILTER_BILINEAR); glEnable (GL_TEXTURE_1D); break; - case CAIRO_GL_OPERAND_RADIAL_GRADIENT: + case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0: + case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE: + case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT: _cairo_gl_gradient_reference (operand->radial.gradient); glActiveTexture (GL_TEXTURE0 + tex_unit); glBindTexture (GL_TEXTURE_1D, operand->radial.gradient->tex); @@ -684,7 +705,9 @@ _cairo_gl_context_destroy_operand (cairo_gl_context_t *ctx, glActiveTexture (GL_TEXTURE0 + tex_unit); glDisable (GL_TEXTURE_1D); break; - case CAIRO_GL_OPERAND_RADIAL_GRADIENT: + case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0: + case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE: + case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT: _cairo_gl_gradient_destroy (ctx->operands[tex_unit].radial.gradient); glActiveTexture (GL_TEXTURE0 + tex_unit); glDisable (GL_TEXTURE_1D); @@ -782,7 +805,9 @@ _cairo_gl_operand_get_vertex_size (cairo_gl_operand_type_t type) case CAIRO_GL_OPERAND_NONE: case CAIRO_GL_OPERAND_CONSTANT: case CAIRO_GL_OPERAND_LINEAR_GRADIENT: - case CAIRO_GL_OPERAND_RADIAL_GRADIENT: + case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0: + case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE: + case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT: return 0; case CAIRO_GL_OPERAND_SPANS: return 4 * sizeof (GLbyte); @@ -1073,7 +1098,9 @@ _cairo_gl_operand_emit (cairo_gl_operand_t *operand, case CAIRO_GL_OPERAND_NONE: case CAIRO_GL_OPERAND_CONSTANT: case CAIRO_GL_OPERAND_LINEAR_GRADIENT: - case CAIRO_GL_OPERAND_RADIAL_GRADIENT: + case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0: + case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE: + case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT: break; case CAIRO_GL_OPERAND_SPANS: { diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h index 8d79cdfda..710ac246f 100644 --- a/src/cairo-gl-private.h +++ b/src/cairo-gl-private.h @@ -107,7 +107,9 @@ typedef enum cairo_gl_operand_type { CAIRO_GL_OPERAND_CONSTANT, CAIRO_GL_OPERAND_TEXTURE, CAIRO_GL_OPERAND_LINEAR_GRADIENT, - CAIRO_GL_OPERAND_RADIAL_GRADIENT, + CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0, + CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE, + CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT, CAIRO_GL_OPERAND_SPANS, CAIRO_GL_OPERAND_COUNT @@ -161,10 +163,11 @@ typedef struct cairo_gl_operand { struct { cairo_gl_gradient_t *gradient; cairo_matrix_t m; - float circle_1_x; - float circle_1_y; + float circle_d_x; + float circle_d_y; + float circle_d_r; float radius_0; - float radius_1; + float a; cairo_extend_t extend; } radial; }; diff --git a/src/cairo-gl-shaders.c b/src/cairo-gl-shaders.c index 02f1ea7d6..af81463a4 100644 --- a/src/cairo-gl-shaders.c +++ b/src/cairo-gl-shaders.c @@ -569,7 +569,9 @@ cairo_gl_operand_get_var_type (cairo_gl_operand_type_t type) case CAIRO_GL_OPERAND_NONE: case CAIRO_GL_OPERAND_CONSTANT: case CAIRO_GL_OPERAND_LINEAR_GRADIENT: - case CAIRO_GL_OPERAND_RADIAL_GRADIENT: + case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0: + case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE: + case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT: return CAIRO_GL_VAR_NONE; case CAIRO_GL_OPERAND_TEXTURE: return CAIRO_GL_VAR_TEXCOORDS; @@ -708,42 +710,80 @@ cairo_gl_shader_emit_color (cairo_output_stream_t *stream, " float t = dot (vec3 (gl_FragCoord.xy, 1.0), %s_weights);" " return texture1D (%s_sampler, t);\n" "}\n", - namestr, namestr, namestr, namestr, namestr, - namestr, namestr, namestr, namestr); + namestr, namestr, namestr, namestr, namestr); break; - case CAIRO_GL_OPERAND_RADIAL_GRADIENT: - _cairo_output_stream_printf (stream, + case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0: + _cairo_output_stream_printf (stream, "uniform sampler1D %s_sampler;\n" "uniform mat3 %s_matrix;\n" - "uniform vec2 %s_circle_1;\n" + "uniform vec3 %s_circle_d;\n" "uniform float %s_radius_0;\n" - "uniform float %s_radius_1;\n" "\n" "vec4 get_%s()\n" "{\n" - " vec2 pos = (%s_matrix * vec3 (gl_FragCoord.xy, 1.0)).xy;\n" + " vec3 pos = vec3 ((%s_matrix * vec3 (gl_FragCoord.xy, 1.0)).xy, %s_radius_0);\n" " \n" - " float dr = %s_radius_1 - %s_radius_0;\n" - " float dot_circle_1 = dot (%s_circle_1, %s_circle_1);\n" - " float dot_pos_circle_1 = dot (pos, %s_circle_1);\n" + " float B = dot (pos, %s_circle_d);\n" + " float C = dot (pos, vec3 (pos.xy, -pos.z));\n" " \n" - " float A = dot_circle_1 - dr * dr;\n" - " float B = -2.0 * (dot_pos_circle_1 + %s_radius_0 * dr);\n" - " float C = dot (pos, pos) - %s_radius_0 * %s_radius_0;\n" - " float det = B * B - 4.0 * A * C;\n" - " det = max (det, 0.0);\n" + " float t = 0.5 * C / B;\n" + " return texture1D (%s_sampler, t);\n" + "}\n", + namestr, namestr, namestr, namestr, namestr, + namestr, namestr, namestr, namestr, namestr); + break; + case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE: + _cairo_output_stream_printf (stream, + "uniform sampler1D %s_sampler;\n" + "uniform mat3 %s_matrix;\n" + "uniform vec3 %s_circle_d;\n" + "uniform float %s_a;\n" + "uniform float %s_radius_0;\n" + "\n" + "vec4 get_%s()\n" + "{\n" + " vec3 pos = vec3 ((%s_matrix * vec3 (gl_FragCoord.xy, 1.0)).xy, %s_radius_0);\n" " \n" - " float sqrt_det = sqrt (det);\n" - " sqrt_det *= sign(A);\n" + " float B = dot (pos, %s_circle_d);\n" + " float C = dot (pos, vec3 (pos.xy, -pos.z));\n" " \n" - " float t = (-B + sqrt_det) / (2.0 * A);\n" - " return texture1D (%s_sampler, t);\n" - "}\n", - namestr, namestr, namestr, namestr, namestr, - namestr, namestr, namestr, namestr, namestr, - namestr, namestr, namestr, namestr, namestr, - namestr); - break; + " float det = dot (vec2 (B, %s_a), vec2 (B, -C));\n" + " float sqrtdet = sqrt (det);\n" + " vec2 t = (B + vec2 (sqrtdet, -sqrtdet)) / %s_a;\n" + " vec2 cond = 1. - step (vec2 (0.0), t) * step (t, vec2(1.0));\n" + " float realt = mix (t.x, t.y, cond.x);\n" + " return mix (texture1D (%s_sampler, realt), vec4 (0.0), cond.x * cond.y);\n" + "}\n", + namestr, namestr, namestr, namestr, + namestr, namestr, namestr, namestr, + namestr, namestr, namestr, namestr); + break; + case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT: + _cairo_output_stream_printf (stream, + "uniform sampler1D %s_sampler;\n" + "uniform mat3 %s_matrix;\n" + "uniform vec3 %s_circle_d;\n" + "uniform float %s_a;\n" + "uniform float %s_radius_0;\n" + "\n" + "vec4 get_%s()\n" + "{\n" + " vec3 pos = vec3 ((%s_matrix * vec3 (gl_FragCoord.xy, 1.0)).xy, %s_radius_0);\n" + " \n" + " float B = dot (pos, %s_circle_d);\n" + " float C = dot (pos, vec3 (pos.xy, -pos.z));\n" + " \n" + " float det = dot (vec2 (B, %s_a), vec2 (B, -C));\n" + " float sqrtdet = sqrt (det);\n" + " vec2 t = (B + vec2 (sqrtdet, -sqrtdet)) / %s_a;\n" + " vec2 cond = 1. - step (vec2 (-%s_radius_0), t * %s_circle_d.z);\n" + " float realt = mix (t.x, t.y, cond.x);\n" + " return mix (texture1D (%s_sampler, realt), vec4 (0.0), cond.x * cond.y);\n" + "}\n", + namestr, namestr, namestr, namestr, namestr, + namestr, namestr, namestr, namestr, namestr, + namestr, namestr, namestr, namestr); + break; case CAIRO_GL_OPERAND_SPANS: _cairo_output_stream_printf (stream, "varying float %s_coverage;\n" |