Hi Marco,
> "Soeren Sandmann" <[email protected]> writes:
> >
> > There used to be a bug where pixman would miscalculate the
> > angle. Maybe that's what you are seeing? That bug is fixed in 0.18.0.
>
> I've now upgraded to 0.18.2 but I'm afraid the problem is still there. I'm
> not sure whether this is actually a bug or whether it is a feature :) I'm
> attaching a small example source code that shows what I mean. The 45 degree
> rotated conical gradient generated by my example looks like this:
>
> http://i45.tinypic.com/2cpq435.png
>
> But I think this look is wrong. Instead, 45 degree rotation should look like
> this: (generated in CorelDraw)
>
> http://i45.tinypic.com/x0xjef.png
>
> But I'm unable to achieve this look with the conical gradient
> functions in pixman. Is it really intended this way or is this a bug
> in pixman?
[adding the X and pixman mailing lists]
The gradients were added to the X Render extension several years ago,
but the Render specification doesn't say anything about how they
should actually be rendered, so what is intended is somewhat difficult
to say. The radial gradients were pretty broken until cairo started
using them and Carl had to actually make them work. So it's not too
surprising if the conical gradients don't work.
The current behavior pretty clearly is just plain buggy. What is going
on is that the output of atan2() is in the range of [-pi, pi] and we
never correct for that, which means we get a discontinuity at pi,
where the angle, and therefore the parameter, suddenly becomes
negative. That cannot possibly be right.
If we simply fix that, then we get something more plausible where the
gradient starts at the given angle and is interpolated 360 degrees
clockwise around the center.
However, the conical gradients were (I suppose, since the code was
written by TrollTech people) intended to match what Qt does:
http://doc.trolltech.com/4.4/qconicalgradient.html
which uses a counter-clockwise interpolation. Given how we normally
measure angles, that makes sense to me.
The appended patch makes the pixman conical gradients match what
QConicalGradient is documented to do. With that applied, you can
achieve something similar to the Corel Draw output by using three
color stops. See this modified version of your test program:
http://www.daimi.au.dk/~sandmann/gradient-test.c
However, since clearly no one has actually used the conical gradients
before, we are not really constrained in what they can be made to do,
so I'm open to other interpretations.
The patch is available in a git repository here:
http://cgit.freedesktop.org/~sandmann/pixman/log/?h=conical
Søren
>From 392b15909d8aa9d66fb92b205276df4057a346b6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?S=C3=B8ren=20Sandmann=20Pedersen?= <[email protected]>
Date: Sat, 19 Jun 2010 18:57:45 -0400
Subject: [PATCH] Fix conical gradients to match QConicalGradient from Qt
Under the assumption that pixman gradients are supposed to match
QConicalgradient, described here:
http://doc.trolltech.com/4.4/qconicalgradient.html
this patch fixes two separate bugs in pixman-conical-gradient.c.
The first bug is that the output of atan2() is in the range of [-pi,
pi], which means the parameter into the gradient can be negative. This
is wrong since a QConicalGradient always interpolates around the
center from 0 to 1. The fix for that is to simply to add 2*pi to the
parameter, and then use fmod() to make sure we didn't end up outside
the [0, 2*pi] range.
The other bug is that we were interpolating clockwise, whereas
QConicalGradient calls for a counter-clockwise interpolation. This is
easily fixed by subtracting the parameter from 1.
Finally, this patch encapsulates the computation in a new force-inline
function so that it can be reused in both the affine and non-affine
case.
---
pixman/pixman-conical-gradient.c | 35 +++++++++++++++++++++--------------
1 files changed, 21 insertions(+), 14 deletions(-)
diff --git a/pixman/pixman-conical-gradient.c b/pixman/pixman-conical-gradient.c
index 1c8ddba..7d368dc 100644
--- a/pixman/pixman-conical-gradient.c
+++ b/pixman/pixman-conical-gradient.c
@@ -32,6 +32,18 @@
#include <math.h>
#include "pixman-private.h"
+static force_inline double
+coordinates_to_parameter (double x, double y, double angle)
+{
+ double t;
+
+ t = atan2 (y, x) + 2 * M_PI; /* Add 2 * M_PI to make it positive */
+ t += angle; /* Add the rotation */
+ t = fmod (t, 2 * M_PI); /* Make sure t is within [0, 2 * pi] */
+
+ return 1 - t / (2 * M_PI); /* Scale t to [0, 1] and make the
rotation CCW */
+}
+
static void
conical_gradient_get_scanline_32 (pixman_image_t *image,
int x,
@@ -52,7 +64,7 @@ conical_gradient_get_scanline_32 (pixman_image_t *image,
double rx = x + 0.5;
double ry = y + 0.5;
double rz = 1.;
- double a = (conical->angle * M_PI) / (180. * 65536);
+ double a = pixman_fixed_to_double ((conical->angle * M_PI) / 180.0);
_pixman_gradient_walker_init (&walker, gradient, source->common.repeat);
@@ -88,16 +100,12 @@ conical_gradient_get_scanline_32 (pixman_image_t *image,
while (buffer < end)
{
- double angle;
-
if (!mask || *mask++)
{
- pixman_fixed_48_16_t t;
+ double t = coordinates_to_parameter (rx, ry, a);
- angle = atan2 (ry, rx) + a;
- t = (pixman_fixed_48_16_t) (angle * (65536. / (2 * M_PI)));
-
- *buffer = _pixman_gradient_walker_pixel (&walker, t);
+ *buffer = _pixman_gradient_walker_pixel (
+ &walker, (pixman_fixed_48_16_t)pixman_double_to_fixed (t));
}
++buffer;
@@ -111,11 +119,10 @@ conical_gradient_get_scanline_32 (pixman_image_t *image,
while (buffer < end)
{
double x, y;
- double angle;
if (!mask || *mask++)
{
- pixman_fixed_48_16_t t;
+ double t;
if (rz != 0)
{
@@ -129,11 +136,11 @@ conical_gradient_get_scanline_32 (pixman_image_t *image,
x -= conical->center.x / 65536.;
y -= conical->center.y / 65536.;
-
- angle = atan2 (y, x) + a;
- t = (pixman_fixed_48_16_t) (angle * (65536. / (2 * M_PI)));
- *buffer = _pixman_gradient_walker_pixel (&walker, t);
+ t = coordinates_to_parameter (x, y, a);
+
+ *buffer = _pixman_gradient_walker_pixel (
+ &walker, (pixman_fixed_48_16_t)pixman_double_to_fixed (t));
}
++buffer;
--
1.7.0.1
_______________________________________________
Pixman mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/pixman