summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrea Canciani <ranma42@gmail.com>2010-10-13 19:22:15 +0200
committerAndrea Canciani <ranma42@gmail.com>2010-11-02 20:24:03 +0100
commit5814ec1c2cec04c4e6cbb70ff2b24d8e157ff321 (patch)
tree270036a9f7edc443cad279fa72876656cafbc8ca
parent360ce9d4d83c08dad5a4b1759ac8d2ddbd6ed7f9 (diff)
gl: Update radial gradients
-rw-r--r--src/cairo-gl-composite.c83
-rw-r--r--src/cairo-gl-private.h11
-rw-r--r--src/cairo-gl-shaders.c92
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"