[cairo] [patch] gl: use original data to compute gradient uniforms

Henry (Yu) Song - SISA hsong at sisa.samsung.com
Wed Feb 6 10:14:44 PST 2013


>From 29e62f9edce2ee5a19f878b46e26e385c4b0e467 Mon Sep 17 00:00:00 2001
From: Henry Song <henry.song at samsung.com>
Date: Wed, 2 Jan 2013 17:57:34 +0100
Subject: [PATCH] gl: Scale radial gradient parameters down may introduce
 rounding error.

gl: Use original data to compute gradient uniforms.

Instead of using scaled parametes to generate uniform values, we
compute them from origin radial gradient pattern. Scaled
data may introduce rounding error.  For example,
operand->gradient.a may not be exactly 0 when using scaled
data.  This causes operand type to use
CAIRO_GL_OPERAND_RADIAL_GRADIENT_EXT/NONE instead of
CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0, which produces different image.
---
 src/cairo-gl-operand.c |   33 ++++++++++++++++++++++++++-------
 1 file changed, 26 insertions(+), 7 deletions(-)

diff --git a/src/cairo-gl-operand.c b/src/cairo-gl-operand.c
index 502737a..1ef2cd5 100644
--- a/src/cairo-gl-operand.c
+++ b/src/cairo-gl-operand.c
@@ -682,6 +682,8 @@ _cairo_gl_gradient_operand_init (cairo_gl_operand_t *operand,
 	cairo_matrix_t m;
 	cairo_circle_double_t circles[2];
 	double x0, y0, r0, dx, dy, dr;
+	double scale = 1.0;
+	cairo_radial_pattern_t *radial_pattern = (cairo_radial_pattern_t *)gradient;
 
 	/*
 	 * Some fragment shader implementations use half-floats to
@@ -695,18 +697,35 @@ _cairo_gl_gradient_operand_init (cairo_gl_operand_t *operand,
 	_cairo_gradient_pattern_fit_to_range (gradient, 8.,
 					      &operand->gradient.m, circles);
 
+	/*
+	 * Instead of using scaled data that might introducing rounding
+	 * errors, we use original data directly
+	 */
+	if (circles[0].center.x)
+		scale = radial_pattern->cd1.center.x / circles[0].center.x;
+	else if (circles[0].center.y)
+		scale = radial_pattern->cd1.center.y / circles[0].center.y;
+	else if (circles[0].radius)
+		scale = radial_pattern->cd1.radius / circles[0].radius;
+	else if (circles[1].center.x)
+		scale = radial_pattern->cd2.center.x / circles[1].center.x;
+	else if (circles[1].center.y)
+		scale = radial_pattern->cd2.center.y / circles[1].center.y;
+	else if (circles[1].radius)
+		scale = radial_pattern->cd2.radius / circles[1].radius;
+
 	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;
+	dx = radial_pattern->cd2.center.x - radial_pattern->cd1.center.x;
+	dy = radial_pattern->cd2.center.y - radial_pattern->cd1.center.y;
+	dr = radial_pattern->cd2.radius	  - radial_pattern->cd1.radius;
 
-	operand->gradient.a = dx * dx + dy * dy - dr * dr;
+	operand->gradient.a = (dx * dx + dy * dy - dr * dr)/(scale * scale);
 	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;
+	operand->gradient.circle_d.center.x = dx / scale;
+	operand->gradient.circle_d.center.y = dy / scale;
+	operand->gradient.circle_d.radius	= dr / scale;
 
 	if (operand->gradient.a == 0)
 	    operand->type = CAIRO_GL_OPERAND_RADIAL_GRADIENT_A0;
-- 
1.7.9.5


More information about the cairo mailing list