mirror of
https://github.com/brl/mutter.git
synced 2025-02-18 06:04:10 +00:00
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.
This commit is contained in:
parent
4b9e672bc1
commit
6cd24faaa5
@ -15112,11 +15112,12 @@ clutter_actor_transform_stage_point (ClutterActor *self,
|
|||||||
gfloat *y_out)
|
gfloat *y_out)
|
||||||
{
|
{
|
||||||
ClutterVertex v[4];
|
ClutterVertex v[4];
|
||||||
float ST[3][3];
|
double ST[3][3];
|
||||||
float RQ[3][3];
|
double RQ[3][3];
|
||||||
int du, dv, xi, yi;
|
int du, dv;
|
||||||
float px, py;
|
double px, py;
|
||||||
float xf, yf, wf, det;
|
double det;
|
||||||
|
float xf, yf, wf;
|
||||||
ClutterActorPrivate *priv;
|
ClutterActorPrivate *priv;
|
||||||
|
|
||||||
g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
|
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
|
* function calls have been unrolled, and most of the math is done in fixed
|
||||||
* point.
|
* point.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
clutter_actor_get_abs_allocation_vertices (self, v);
|
clutter_actor_get_abs_allocation_vertices (self, v);
|
||||||
|
|
||||||
/* Keeping these as ints simplifies the multiplication (no significant
|
/* Keeping these as ints simplifies the multiplication (no significant
|
||||||
* loss of precision here).
|
* loss of precision here).
|
||||||
*/
|
*/
|
||||||
du = (int) (priv->allocation.x2 - priv->allocation.x1);
|
du = ceilf (priv->allocation.x2 - priv->allocation.x1);
|
||||||
dv = (int) (priv->allocation.y2 - priv->allocation.y1);
|
dv = ceilf (priv->allocation.y2 - priv->allocation.y1);
|
||||||
|
|
||||||
if (!du || !dv)
|
if (du == 0 || dv == 0)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
#define UX2FP(x) (x)
|
#define DET(a,b,c,d) (((a) * (d)) - ((b) * (c)))
|
||||||
#define DET2FP(a,b,c,d) (((a) * (d)) - ((b) * (c)))
|
|
||||||
|
|
||||||
/* First, find mapping from unit uv square to xy quadrilateral; this
|
/* First, find mapping from unit uv square to xy quadrilateral; this
|
||||||
* equivalent to the pmap_square_quad() functions in the sample
|
* 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;
|
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;
|
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 */
|
/* affine transform */
|
||||||
RQ[0][0] = UX2FP (v[1].x - v[0].x);
|
RQ[0][0] = v[1].x - v[0].x;
|
||||||
RQ[1][0] = UX2FP (v[3].x - v[1].x);
|
RQ[1][0] = v[3].x - v[1].x;
|
||||||
RQ[2][0] = UX2FP (v[0].x);
|
RQ[2][0] = v[0].x;
|
||||||
RQ[0][1] = UX2FP (v[1].y - v[0].y);
|
RQ[0][1] = v[1].y - v[0].y;
|
||||||
RQ[1][1] = UX2FP (v[3].y - v[1].y);
|
RQ[1][1] = v[3].y - v[1].y;
|
||||||
RQ[2][1] = UX2FP (v[0].y);
|
RQ[2][1] = v[0].y;
|
||||||
RQ[0][2] = 0;
|
RQ[0][2] = 0.0;
|
||||||
RQ[1][2] = 0;
|
RQ[1][2] = 0.0;
|
||||||
RQ[2][2] = 1.0;
|
RQ[2][2] = 1.0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* projective transform */
|
/* projective transform */
|
||||||
double dx1, dx2, dy1, dy2, del;
|
double dx1, dx2, dy1, dy2;
|
||||||
|
|
||||||
dx1 = UX2FP (v[1].x - v[3].x);
|
dx1 = v[1].x - v[3].x;
|
||||||
dx2 = UX2FP (v[2].x - v[3].x);
|
dx2 = v[2].x - v[3].x;
|
||||||
dy1 = UX2FP (v[1].y - v[3].y);
|
dy1 = v[1].y - v[3].y;
|
||||||
dy2 = UX2FP (v[2].y - v[3].y);
|
dy2 = v[2].y - v[3].y;
|
||||||
|
|
||||||
del = DET2FP (dx1, dx2, dy1, dy2);
|
det = DET (dx1, dx2, dy1, dy2);
|
||||||
if (!del)
|
if ((int) det == 0)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
/*
|
RQ[0][2] = DET (px, dx2, py, dy2) / det;
|
||||||
* The division here needs to be done in floating point for
|
RQ[1][2] = DET (dx1, px, dy1, py) / det;
|
||||||
* precisions reasons.
|
RQ[1][2] = DET (dx1, px, dy1, py) / det;
|
||||||
*/
|
|
||||||
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[2][2] = 1.0;
|
RQ[2][2] = 1.0;
|
||||||
RQ[0][0] = UX2FP (v[1].x - v[0].x) + (RQ[0][2] * UX2FP (v[1].x));
|
RQ[0][0] = v[1].x - v[0].x + (RQ[0][2] * v[1].x);
|
||||||
RQ[1][0] = UX2FP (v[2].x - v[0].x) + (RQ[1][2] * UX2FP (v[2].x));
|
RQ[1][0] = v[2].x - v[0].x + (RQ[1][2] * v[2].x);
|
||||||
RQ[2][0] = UX2FP (v[0].x);
|
RQ[2][0] = v[0].x;
|
||||||
RQ[0][1] = UX2FP (v[1].y - v[0].y) + (RQ[0][2] * UX2FP (v[1].y));
|
RQ[0][1] = v[1].y - v[0].y + (RQ[0][2] * v[1].y);
|
||||||
RQ[1][1] = UX2FP (v[2].y - v[0].y) + (RQ[1][2] * UX2FP (v[2].y));
|
RQ[1][1] = v[2].y - v[0].y + (RQ[1][2] * v[2].y);
|
||||||
RQ[2][1] = UX2FP (v[0].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
|
* Now RQ is transform from uv rectangle to xy quadrilateral; we need an
|
||||||
* inverse of that.
|
* inverse of that.
|
||||||
*/
|
*/
|
||||||
ST[0][0] = DET2FP (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
|
ST[0][0] = DET (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[1][0] = DET (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[2][0] = DET (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[0][1] = DET (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[1][1] = DET (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[2][1] = DET (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[0][2] = DET (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[1][2] = DET (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[2][2] = DET (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check the resulting matrix is OK.
|
* Check the resulting matrix is OK.
|
||||||
@ -15234,19 +15229,16 @@ clutter_actor_transform_stage_point (ClutterActor *self,
|
|||||||
det = (RQ[0][0] * ST[0][0])
|
det = (RQ[0][0] * ST[0][0])
|
||||||
+ (RQ[0][1] * ST[0][1])
|
+ (RQ[0][1] * ST[0][1])
|
||||||
+ (RQ[0][2] * ST[0][2]);
|
+ (RQ[0][2] * ST[0][2]);
|
||||||
if (!det)
|
if ((int) det == 0)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now transform our point with the ST matrix; the notional w
|
* Now transform our point with the ST matrix; the notional w
|
||||||
* coordinate is 1, hence the last part is simply added.
|
* coordinate is 1, hence the last part is simply added.
|
||||||
*/
|
*/
|
||||||
xi = (int) x;
|
xf = x * ST[0][0] + y * ST[1][0] + ST[2][0];
|
||||||
yi = (int) y;
|
yf = x * ST[0][1] + y * ST[1][1] + ST[2][1];
|
||||||
|
wf = x * ST[0][2] + y * ST[1][2] + ST[2][2];
|
||||||
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];
|
|
||||||
|
|
||||||
if (x_out)
|
if (x_out)
|
||||||
*x_out = xf / wf;
|
*x_out = xf / wf;
|
||||||
@ -15254,8 +15246,7 @@ clutter_actor_transform_stage_point (ClutterActor *self,
|
|||||||
if (y_out)
|
if (y_out)
|
||||||
*y_out = yf / wf;
|
*y_out = yf / wf;
|
||||||
|
|
||||||
#undef UX2FP
|
#undef DET
|
||||||
#undef DET2FP
|
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user