summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEmmanuele Bassi <ebassi@gnome.org>2015-07-07 09:23:42 +0100
committerEmmanuele Bassi <ebassi@gnome.org>2015-07-07 16:03:31 +0100
commit6cd24faaa54de3246ca45d1c7426d8b7a74f71db (patch)
tree940b879fbf119701faf4a225216313c7086de44d
parent4b9e672bc18e80c541138743c19c9229764c20e9 (diff)
downloadclutter-6cd24faaa54de3246ca45d1c7426d8b7a74f71db.tar.gz
actor: Clean up transform_stage_point()
Use double precision floats for the intermediate computations, to avoid loss of precision, and don't convert too integer when unnecessary, to avoid rounding errors.
-rw-r--r--clutter/clutter-actor.c107
1 files changed, 49 insertions, 58 deletions
diff --git a/clutter/clutter-actor.c b/clutter/clutter-actor.c
index fc2995b98..d6dd4f947 100644
--- a/clutter/clutter-actor.c
+++ b/clutter/clutter-actor.c
@@ -15112,11 +15112,12 @@ clutter_actor_transform_stage_point (ClutterActor *self,
gfloat *y_out)
{
ClutterVertex v[4];
- float ST[3][3];
- float RQ[3][3];
- int du, dv, xi, yi;
- float px, py;
- float xf, yf, wf, det;
+ double ST[3][3];
+ double RQ[3][3];
+ int du, dv;
+ double px, py;
+ double det;
+ float xf, yf, wf;
ClutterActorPrivate *priv;
g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
@@ -15137,20 +15138,18 @@ clutter_actor_transform_stage_point (ClutterActor *self,
* function calls have been unrolled, and most of the math is done in fixed
* point.
*/
-
clutter_actor_get_abs_allocation_vertices (self, v);
/* Keeping these as ints simplifies the multiplication (no significant
* loss of precision here).
*/
- du = (int) (priv->allocation.x2 - priv->allocation.x1);
- dv = (int) (priv->allocation.y2 - priv->allocation.y1);
+ du = ceilf (priv->allocation.x2 - priv->allocation.x1);
+ dv = ceilf (priv->allocation.y2 - priv->allocation.y1);
- if (!du || !dv)
+ if (du == 0 || dv == 0)
return FALSE;
-#define UX2FP(x) (x)
-#define DET2FP(a,b,c,d) (((a) * (d)) - ((b) * (c)))
+#define DET(a,b,c,d) (((a) * (d)) - ((b) * (c)))
/* First, find mapping from unit uv square to xy quadrilateral; this
* equivalent to the pmap_square_quad() functions in the sample
@@ -15160,47 +15159,43 @@ clutter_actor_transform_stage_point (ClutterActor *self,
px = v[0].x - v[1].x + v[3].x - v[2].x;
py = v[0].y - v[1].y + v[3].y - v[2].y;
- if (!px && !py)
+ if ((int) px == 0 && (int) py == 0)
{
/* affine transform */
- RQ[0][0] = UX2FP (v[1].x - v[0].x);
- RQ[1][0] = UX2FP (v[3].x - v[1].x);
- RQ[2][0] = UX2FP (v[0].x);
- RQ[0][1] = UX2FP (v[1].y - v[0].y);
- RQ[1][1] = UX2FP (v[3].y - v[1].y);
- RQ[2][1] = UX2FP (v[0].y);
- RQ[0][2] = 0;
- RQ[1][2] = 0;
+ RQ[0][0] = v[1].x - v[0].x;
+ RQ[1][0] = v[3].x - v[1].x;
+ RQ[2][0] = v[0].x;
+ RQ[0][1] = v[1].y - v[0].y;
+ RQ[1][1] = v[3].y - v[1].y;
+ RQ[2][1] = v[0].y;
+ RQ[0][2] = 0.0;
+ RQ[1][2] = 0.0;
RQ[2][2] = 1.0;
}
else
{
/* projective transform */
- double dx1, dx2, dy1, dy2, del;
+ double dx1, dx2, dy1, dy2;
- dx1 = UX2FP (v[1].x - v[3].x);
- dx2 = UX2FP (v[2].x - v[3].x);
- dy1 = UX2FP (v[1].y - v[3].y);
- dy2 = UX2FP (v[2].y - v[3].y);
+ dx1 = v[1].x - v[3].x;
+ dx2 = v[2].x - v[3].x;
+ dy1 = v[1].y - v[3].y;
+ dy2 = v[2].y - v[3].y;
- del = DET2FP (dx1, dx2, dy1, dy2);
- if (!del)
+ det = DET (dx1, dx2, dy1, dy2);
+ if ((int) det == 0)
return FALSE;
- /*
- * The division here needs to be done in floating point for
- * precisions reasons.
- */
- RQ[0][2] = (DET2FP (UX2FP (px), dx2, UX2FP (py), dy2) / del);
- RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
- RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
+ RQ[0][2] = DET (px, dx2, py, dy2) / det;
+ RQ[1][2] = DET (dx1, px, dy1, py) / det;
+ RQ[1][2] = DET (dx1, px, dy1, py) / det;
RQ[2][2] = 1.0;
- RQ[0][0] = UX2FP (v[1].x - v[0].x) + (RQ[0][2] * UX2FP (v[1].x));
- RQ[1][0] = UX2FP (v[2].x - v[0].x) + (RQ[1][2] * UX2FP (v[2].x));
- RQ[2][0] = UX2FP (v[0].x);
- RQ[0][1] = UX2FP (v[1].y - v[0].y) + (RQ[0][2] * UX2FP (v[1].y));
- RQ[1][1] = UX2FP (v[2].y - v[0].y) + (RQ[1][2] * UX2FP (v[2].y));
- RQ[2][1] = UX2FP (v[0].y);
+ RQ[0][0] = v[1].x - v[0].x + (RQ[0][2] * v[1].x);
+ RQ[1][0] = v[2].x - v[0].x + (RQ[1][2] * v[2].x);
+ RQ[2][0] = v[0].x;
+ RQ[0][1] = v[1].y - v[0].y + (RQ[0][2] * v[1].y);
+ RQ[1][1] = v[2].y - v[0].y + (RQ[1][2] * v[2].y);
+ RQ[2][1] = v[0].y;
}
/*
@@ -15218,15 +15213,15 @@ clutter_actor_transform_stage_point (ClutterActor *self,
* Now RQ is transform from uv rectangle to xy quadrilateral; we need an
* inverse of that.
*/
- ST[0][0] = DET2FP (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
- ST[1][0] = DET2FP (RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
- ST[2][0] = DET2FP (RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
- ST[0][1] = DET2FP (RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
- ST[1][1] = DET2FP (RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
- ST[2][1] = DET2FP (RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
- ST[0][2] = DET2FP (RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
- ST[1][2] = DET2FP (RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
- ST[2][2] = DET2FP (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
+ ST[0][0] = DET (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
+ ST[1][0] = DET (RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
+ ST[2][0] = DET (RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
+ ST[0][1] = DET (RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
+ ST[1][1] = DET (RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
+ ST[2][1] = DET (RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
+ ST[0][2] = DET (RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
+ ST[1][2] = DET (RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
+ ST[2][2] = DET (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
/*
* Check the resulting matrix is OK.
@@ -15234,19 +15229,16 @@ clutter_actor_transform_stage_point (ClutterActor *self,
det = (RQ[0][0] * ST[0][0])
+ (RQ[0][1] * ST[0][1])
+ (RQ[0][2] * ST[0][2]);
- if (!det)
+ if ((int) det == 0)
return FALSE;
/*
* Now transform our point with the ST matrix; the notional w
* coordinate is 1, hence the last part is simply added.
*/
- xi = (int) x;
- yi = (int) y;
-
- xf = xi * ST[0][0] + yi * ST[1][0] + ST[2][0];
- yf = xi * ST[0][1] + yi * ST[1][1] + ST[2][1];
- wf = xi * ST[0][2] + yi * ST[1][2] + ST[2][2];
+ xf = x * ST[0][0] + y * ST[1][0] + ST[2][0];
+ yf = x * ST[0][1] + y * ST[1][1] + ST[2][1];
+ wf = x * ST[0][2] + y * ST[1][2] + ST[2][2];
if (x_out)
*x_out = xf / wf;
@@ -15254,8 +15246,7 @@ clutter_actor_transform_stage_point (ClutterActor *self,
if (y_out)
*y_out = yf / wf;
-#undef UX2FP
-#undef DET2FP
+#undef DET
return TRUE;
}