[cairo] [PATCH 1/2] gl: Update radial gradient implementation
Andrea Canciani
ranma42 at gmail.com
Wed Jan 12 16:21:19 PST 2011
Cairo assumes that radial gradients are drawn as defined in ISO3200
since b661bc871220fd67d673c44a8e3cb305812d8c38.
To implement them in GLSL, three different shaders are required:
- tangent circles (a=0 in the parameter equation)
- none-extended gradient (solutions outside [0,1] must be ignored)
- extended gradient
Moreover, texcoords are used instead of gl_FragCoord, to fix the
flipping as per 31e116f084d0ff073bed9d0e9c1c6ca1e5db4843.
Fixes huge-radial, radial-gradient, radial-gradient-extend,
radial-gradient-mask, radial-gradient-source.
---
src/cairo-gl-composite.c | 219 ++++++++++++++++++++++------------------------
src/cairo-gl-private.h | 21 ++---
src/cairo-gl-shaders.c | 115 +++++++++++++++++-------
3 files changed, 193 insertions(+), 162 deletions(-)
diff --git a/src/cairo-gl-composite.c b/src/cairo-gl-composite.c
index dbd5306..afd1edb 100644
--- a/src/cairo-gl-composite.c
+++ b/src/cairo-gl-composite.c
@@ -156,19 +156,21 @@ _cairo_gl_gradient_operand_init (cairo_gl_operand_t *operand,
const cairo_gradient_pattern_t *gradient = (const cairo_gradient_pattern_t *)pattern;
cairo_status_t status;
+ assert (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR ||
+ gradient->base.type == CAIRO_PATTERN_TYPE_RADIAL);
+
if (! _cairo_gl_device_has_glsl (dst->base.device))
return CAIRO_INT_STATUS_UNSUPPORTED;
+ status = _cairo_gl_create_gradient_texture (dst,
+ gradient,
+ &operand->gradient.gradient);
+ if (unlikely (status))
+ return status;
+
if (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) gradient;
- double x0, y0;
- float dx, dy, sf, offset;
-
- status = _cairo_gl_create_gradient_texture (dst,
- gradient,
- &operand->linear.gradient);
- if (unlikely (status))
- return status;
+ double x0, y0, dx, dy, sf, offset;
dx = linear->pd2.x - linear->pd1.x;
dy = linear->pd2.y - linear->pd1.y;
@@ -180,64 +182,61 @@ _cairo_gl_gradient_operand_init (cairo_gl_operand_t *operand,
y0 = linear->pd1.y;
offset = dx * x0 + dy * y0;
- if (_cairo_matrix_is_identity (&linear->base.base.matrix)) {
- operand->linear.m.xx = dx;
- operand->linear.m.xy = dy;
- operand->linear.m.x0 = -offset;
- } else {
- cairo_matrix_t m;
+ operand->type = CAIRO_GL_OPERAND_LINEAR_GRADIENT;
- cairo_matrix_init (&m, dx, 0, dy, 0, -offset, 0);
- cairo_matrix_multiply (&operand->linear.m,
- &linear->base.base.matrix, &m);
+ cairo_matrix_init (&operand->gradient.m, dx, 0, dy, 1, -offset, 0);
+ if (! _cairo_matrix_is_identity (&pattern->matrix)) {
+ cairo_matrix_multiply (&operand->gradient.m,
+ &pattern->matrix,
+ &operand->gradient.m);
}
- operand->linear.m.yx = 0.0;
- operand->linear.m.yy = 1.0;
- operand->linear.m.y0 = 0.0;
-
- operand->linear.extend = pattern->extend;
-
- operand->type = CAIRO_GL_OPERAND_LINEAR_GRADIENT;
- return CAIRO_STATUS_SUCCESS;
} else {
- cairo_radial_pattern_t *radial = (cairo_radial_pattern_t *) gradient;
- double x0, y0, r0, x1, y1, r1;
-
- x0 = radial->cd1.center.x;
- x1 = radial->cd2.center.x;
- y0 = radial->cd1.center.y;
- y1 = radial->cd2.center.y;
- r0 = radial->cd1.radius;
- r1 = radial->cd2.radius;
-
- status = _cairo_gl_create_gradient_texture (dst,
- gradient,
- &operand->radial.gradient);
- if (unlikely (status))
- return status;
-
- /* Translation matrix from the destination fragment coordinates
- * (pixels from lower left = 0,0) to the coordinates in the
+ cairo_matrix_t m;
+ cairo_circle_double_t circles[2];
+ double x0, y0, r0, dx, dy, dr;
+
+ /*
+ * Some fragment shader implementations use half-floats to
+ * represent numbers, so the maximum number they can represent
+ * is about 2^14. Some intermediate computations used in the
+ * radial gradient shaders can produce results of up to 2*k^4.
+ * Setting k=8 makes the maximum result about 8192 (assuming
+ * that the extreme circles are not much smaller than the
+ * destination image).
*/
- cairo_matrix_init_translate (&operand->radial.m, -x0, -y0);
- cairo_matrix_multiply (&operand->radial.m,
- &pattern->matrix,
- &operand->radial.m);
- cairo_matrix_translate (&operand->radial.m, 0, dst->height);
- cairo_matrix_scale (&operand->radial.m, 1.0, -1.0);
+ _cairo_gradient_pattern_fit_to_range (gradient, 8.,
+ &operand->gradient.m, circles);
+
+ x0 = circles[0].center.x;
+ y0 = circles[0].center.y;
+ r0 = circles[0].radius;
+ dx = circles[1].center.x - x0;
+ dy = circles[1].center.y - y0;
+ dr = circles[1].radius - r0;
+
+ operand->gradient.a = dx * dx + dy * dy - dr * dr;
+ operand->gradient.radius_0 = r0;
+ operand->gradient.circle_d.center.x = dx;
+ operand->gradient.circle_d.center.y = dy;
+ operand->gradient.circle_d.radius = dr;
+
+ if (operand->gradient.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;
+
+ cairo_matrix_init_translate (&m, -x0, -y0);
+ cairo_matrix_multiply (&operand->gradient.m,
+ &operand->gradient.m,
+ &m);
+ }
- operand->radial.circle_1_x = x1 - x0;
- operand->radial.circle_1_y = y1 - y0;
- operand->radial.radius_0 = r0;
- operand->radial.radius_1 = r1;
- operand->radial.extend = pattern->extend;
+ operand->gradient.extend = pattern->extend;
- operand->type = CAIRO_GL_OPERAND_RADIAL_GRADIENT;
- return CAIRO_STATUS_SUCCESS;
- }
-
- return CAIRO_INT_STATUS_UNSUPPORTED;
+ return CAIRO_STATUS_SUCCESS;
}
static void
@@ -247,10 +246,10 @@ _cairo_gl_operand_destroy (cairo_gl_operand_t *operand)
case CAIRO_GL_OPERAND_CONSTANT:
break;
case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
- _cairo_gl_gradient_destroy (operand->linear.gradient);
- break;
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT:
- _cairo_gl_gradient_destroy (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->gradient.gradient);
break;
case CAIRO_GL_OPERAND_TEXTURE:
_cairo_pattern_release_surface (NULL, /* XXX */
@@ -376,35 +375,26 @@ _cairo_gl_operand_bind_to_shader (cairo_gl_context_t *ctx,
operand->constant.color[2],
operand->constant.color[3]);
break;
+ 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->gradient.a);
+ /* fall through */
+ case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
+ strcpy (custom_part, "_circle_d");
+ _cairo_gl_shader_bind_vec3 (ctx,
+ uniform_name,
+ operand->gradient.circle_d.center.x,
+ operand->gradient.circle_d.center.y,
+ operand->gradient.circle_d.radius);
+ strcpy (custom_part, "_radius_0");
+ _cairo_gl_shader_bind_float (ctx,
+ uniform_name,
+ operand->gradient.radius_0);
+ /* fall through */
case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
- strcpy (custom_part, "_sampler");
- _cairo_gl_shader_bind_texture(ctx,
- uniform_name,
- tex_unit);
- break;
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT:
- 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,
- uniform_name,
- operand->radial.circle_1_x,
- operand->radial.circle_1_y);
- 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,
- tex_unit);
- break;
case CAIRO_GL_OPERAND_TEXTURE:
strcpy (custom_part, "_sampler");
_cairo_gl_shader_bind_texture(ctx,
@@ -498,7 +488,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;
}
@@ -561,7 +553,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:
@@ -634,10 +628,13 @@ _cairo_gl_context_setup_operand (cairo_gl_context_t *ctx,
glEnableClientState (GL_TEXTURE_COORD_ARRAY);
break;
case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
- _cairo_gl_gradient_reference (operand->linear.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->gradient.gradient);
glActiveTexture (GL_TEXTURE0 + tex_unit);
- glBindTexture (GL_TEXTURE_1D, operand->linear.gradient->tex);
- _cairo_gl_texture_set_extend (ctx, GL_TEXTURE_1D, operand->linear.extend);
+ glBindTexture (GL_TEXTURE_1D, operand->gradient.gradient->tex);
+ _cairo_gl_texture_set_extend (ctx, GL_TEXTURE_1D, operand->gradient.extend);
_cairo_gl_texture_set_filter (ctx, GL_TEXTURE_1D, CAIRO_FILTER_BILINEAR);
glEnable (GL_TEXTURE_1D);
@@ -646,14 +643,6 @@ _cairo_gl_context_setup_operand (cairo_gl_context_t *ctx,
(void *) (uintptr_t) vertex_offset);
glEnableClientState (GL_TEXTURE_COORD_ARRAY);
break;
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT:
- _cairo_gl_gradient_reference (operand->radial.gradient);
- glActiveTexture (GL_TEXTURE0 + tex_unit);
- glBindTexture (GL_TEXTURE_1D, operand->radial.gradient->tex);
- _cairo_gl_texture_set_extend (ctx, GL_TEXTURE_1D, operand->radial.extend);
- _cairo_gl_texture_set_filter (ctx, GL_TEXTURE_1D, CAIRO_FILTER_BILINEAR);
- glEnable (GL_TEXTURE_1D);
- break;
}
if (! use_shaders)
@@ -688,17 +677,15 @@ _cairo_gl_context_destroy_operand (cairo_gl_context_t *ctx,
glDisableClientState (GL_TEXTURE_COORD_ARRAY);
break;
case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
- _cairo_gl_gradient_destroy (ctx->operands[tex_unit].linear.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].gradient.gradient);
glActiveTexture (GL_TEXTURE0 + tex_unit);
glDisable (GL_TEXTURE_1D);
glClientActiveTexture (GL_TEXTURE0 + tex_unit);
glDisableClientState (GL_TEXTURE_COORD_ARRAY);
break;
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT:
- _cairo_gl_gradient_destroy (ctx->operands[tex_unit].radial.gradient);
- glActiveTexture (GL_TEXTURE0 + tex_unit);
- glDisable (GL_TEXTURE_1D);
- break;
}
memset (&ctx->operands[tex_unit], 0, sizeof (cairo_gl_operand_t));
@@ -791,12 +778,14 @@ _cairo_gl_operand_get_vertex_size (cairo_gl_operand_type_t type)
ASSERT_NOT_REACHED;
case CAIRO_GL_OPERAND_NONE:
case CAIRO_GL_OPERAND_CONSTANT:
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT:
return 0;
case CAIRO_GL_OPERAND_SPANS:
return 4 * sizeof (GLbyte);
case CAIRO_GL_OPERAND_TEXTURE:
case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
+ case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
+ case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
+ case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
return 2 * sizeof (GLfloat);
}
}
@@ -1084,7 +1073,6 @@ _cairo_gl_operand_emit (cairo_gl_operand_t *operand,
ASSERT_NOT_REACHED;
case CAIRO_GL_OPERAND_NONE:
case CAIRO_GL_OPERAND_CONSTANT:
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT:
break;
case CAIRO_GL_OPERAND_SPANS:
{
@@ -1101,14 +1089,17 @@ _cairo_gl_operand_emit (cairo_gl_operand_t *operand,
}
break;
case CAIRO_GL_OPERAND_LINEAR_GRADIENT:
+ case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
+ case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
+ case CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT:
{
double s = x;
double t = y;
- cairo_matrix_transform_point (&operand->linear.m, &s, &t);
+ cairo_matrix_transform_point (&operand->gradient.m, &s, &t);
*(*vb)++ = s;
- *(*vb)++ = 0.0;
+ *(*vb)++ = t;
}
break;
case CAIRO_GL_OPERAND_TEXTURE:
diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index 2f47b9a..1bd3fbd 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -111,7 +111,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
@@ -158,19 +160,10 @@ typedef struct cairo_gl_operand {
struct {
cairo_gl_gradient_t *gradient;
cairo_matrix_t m;
- float x0, y0, dx, dy;
- float scale;
- cairo_extend_t extend;
- } linear;
- struct {
- cairo_gl_gradient_t *gradient;
- cairo_matrix_t m;
- float circle_1_x;
- float circle_1_y;
- float radius_0;
- float radius_1;
- cairo_extend_t extend;
- } radial;
+ cairo_circle_double_t circle_d;
+ double radius_0, a;
+ cairo_extend_t extend;
+ } gradient;
};
unsigned int vertex_offset;
} cairo_gl_operand_t;
diff --git a/src/cairo-gl-shaders.c b/src/cairo-gl-shaders.c
index f9bbc37..2b31bfc 100644
--- a/src/cairo-gl-shaders.c
+++ b/src/cairo-gl-shaders.c
@@ -422,9 +422,11 @@ cairo_gl_operand_get_var_type (cairo_gl_operand_type_t type)
ASSERT_NOT_REACHED;
case CAIRO_GL_OPERAND_NONE:
case CAIRO_GL_OPERAND_CONSTANT:
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT:
return CAIRO_GL_VAR_NONE;
case CAIRO_GL_OPERAND_LINEAR_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_TEXTURE:
return CAIRO_GL_VAR_TEXCOORDS;
case CAIRO_GL_OPERAND_SPANS:
@@ -563,39 +565,84 @@ cairo_gl_shader_emit_color (cairo_output_stream_t *stream,
"}\n",
namestr, namestr, namestr, namestr, namestr);
break;
- case CAIRO_GL_OPERAND_RADIAL_GRADIENT:
- _cairo_output_stream_printf (stream,
- "uniform sampler1D %s_sampler;\n"
- "uniform mat3 %s_matrix;\n"
- "uniform vec2 %s_circle_1;\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"
- " \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"
- " \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"
- " \n"
- " float sqrt_det = sqrt (det);\n"
- " sqrt_det *= sign(A);\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;
+ case CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0:
+ _cairo_output_stream_printf (stream,
+ "varying vec2 %s_texcoords;\n"
+ "uniform sampler1D %s_sampler;\n"
+ "uniform vec3 %s_circle_d;\n"
+ "uniform float %s_radius_0;\n"
+ "\n"
+ "vec4 get_%s()\n"
+ "{\n"
+ " vec3 pos = vec3 (%s_texcoords, %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 t = 0.5 * C / B;\n"
+ " float is_valid = step (-%s_radius_0, t * %s_circle_d.z);\n"
+ " return mix (vec4 (0.0), texture1D (%s_sampler, t), is_valid);\n"
+ "}\n",
+ namestr, namestr, namestr, namestr, namestr, namestr,
+ namestr, namestr, namestr, namestr, namestr);
+ break;
+ case CAIRO_GL_OPERAND_RADIAL_GRADIENT_NONE:
+ _cairo_output_stream_printf (stream,
+ "varying vec2 %s_texcoords;\n"
+ "uniform sampler1D %s_sampler;\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_texcoords, %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 (abs (det));\n"
+ " vec2 t = (B + vec2 (sqrtdet, -sqrtdet)) / %s_a;\n"
+ " \n"
+ " vec2 is_valid = step (vec2 (0.0), t) * step (t, vec2(1.0));\n"
+ " float has_color = step (0., det) * max (is_valid.x, is_valid.y);\n"
+ " \n"
+ " float upper_t = mix (t.y, t.x, is_valid.x);\n"
+ " return mix (vec4 (0.0), texture1D (%s_sampler, upper_t), has_color);\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,
+ "varying vec2 %s_texcoords;\n"
+ "uniform sampler1D %s_sampler;\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_texcoords, %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 (abs (det));\n"
+ " vec2 t = (B + vec2 (sqrtdet, -sqrtdet)) / %s_a;\n"
+ " \n"
+ " vec2 is_valid = step (vec2 (-%s_radius_0), t * %s_circle_d.z);\n"
+ " float has_color = step (0., det) * max (is_valid.x, is_valid.y);\n"
+ " \n"
+ " float upper_t = mix (t.y, t.x, is_valid.x);\n"
+ " return mix (vec4 (0.0), texture1D (%s_sampler, upper_t), has_color);\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"
--
1.7.1
More information about the cairo
mailing list