forked from AuroraMiddleware/gtk
transform: Add perspective()
This commit adds gsk_transform_perspective(), gtk_snapshot_perspective() and support for perspective() in the CSS syntax.
This commit is contained in:
parent
dbe58452d7
commit
3a3b325f8e
@ -171,6 +171,7 @@ gsk_transform_rotate
|
||||
gsk_transform_rotate_3d
|
||||
gsk_transform_scale
|
||||
gsk_transform_scale_3d
|
||||
gsk_transform_perspective
|
||||
<SUBSECTION>
|
||||
gsk_transform_equal
|
||||
<SUBSECTION>
|
||||
|
@ -4388,6 +4388,7 @@ gtk_snapshot_rotate
|
||||
gtk_snapshot_rotate_3d
|
||||
gtk_snapshot_scale
|
||||
gtk_snapshot_scale_3d
|
||||
gtk_snapshot_perspective
|
||||
gtk_snapshot_append_node
|
||||
gtk_snapshot_append_cairo
|
||||
gtk_snapshot_append_texture
|
||||
|
@ -1095,6 +1095,120 @@ gsk_transform_scale_3d (GskTransform *next,
|
||||
return &result->parent;
|
||||
}
|
||||
|
||||
/*** PERSPECTIVE ***/
|
||||
|
||||
typedef struct _GskPerspectiveTransform GskPerspectiveTransform;
|
||||
|
||||
struct _GskPerspectiveTransform
|
||||
{
|
||||
GskTransform parent;
|
||||
|
||||
float depth;
|
||||
};
|
||||
|
||||
static void
|
||||
gsk_perspective_transform_finalize (GskTransform *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_perspective_transform_to_matrix (GskTransform *transform,
|
||||
graphene_matrix_t *out_matrix)
|
||||
{
|
||||
GskPerspectiveTransform *self = (GskPerspectiveTransform *) transform;
|
||||
float f[16] = { 1.f, 0.f, 0.f, 0.f,
|
||||
0.f, 1.f, 0.f, 0.f,
|
||||
0.f, 0.f, 1.f, -1.f / self->depth,
|
||||
0.f, 0.f, 0.f, 1.f };
|
||||
|
||||
graphene_matrix_init_from_float (out_matrix, f);
|
||||
}
|
||||
|
||||
|
||||
static GskTransform *
|
||||
gsk_perspective_transform_apply (GskTransform *transform,
|
||||
GskTransform *apply_to)
|
||||
{
|
||||
GskPerspectiveTransform *self = (GskPerspectiveTransform *) transform;
|
||||
|
||||
return gsk_transform_perspective (apply_to, self->depth);
|
||||
}
|
||||
|
||||
static GskTransform *
|
||||
gsk_perspective_transform_invert (GskTransform *transform,
|
||||
GskTransform *next)
|
||||
{
|
||||
GskPerspectiveTransform *self = (GskPerspectiveTransform *) transform;
|
||||
|
||||
return gsk_transform_perspective (next, - self->depth);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gsk_perspective_transform_equal (GskTransform *first_transform,
|
||||
GskTransform *second_transform)
|
||||
{
|
||||
GskPerspectiveTransform *first = (GskPerspectiveTransform *) first_transform;
|
||||
GskPerspectiveTransform *second = (GskPerspectiveTransform *) second_transform;
|
||||
|
||||
return first->depth == second->depth;
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_perspective_transform_print (GskTransform *transform,
|
||||
GString *string)
|
||||
{
|
||||
GskPerspectiveTransform *self = (GskPerspectiveTransform *) transform;
|
||||
|
||||
g_string_append (string, "perspective(");
|
||||
string_append_double (string, self->depth);
|
||||
g_string_append (string, ")");
|
||||
}
|
||||
|
||||
static const GskTransformClass GSK_PERSPECTIVE_TRANSFORM_CLASS =
|
||||
{
|
||||
sizeof (GskPerspectiveTransform),
|
||||
"GskPerspectiveTransform",
|
||||
gsk_perspective_transform_finalize,
|
||||
gsk_perspective_transform_to_matrix,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
gsk_perspective_transform_print,
|
||||
gsk_perspective_transform_apply,
|
||||
gsk_perspective_transform_invert,
|
||||
gsk_perspective_transform_equal,
|
||||
};
|
||||
|
||||
/**
|
||||
* gsk_transform_perspective:
|
||||
* @next: (allow-none): the next transform
|
||||
* @depth: distance of the z=0 plane. Lower values give a more
|
||||
* flattened pyramid and therefore a more pronounced
|
||||
* perspective effect.
|
||||
*
|
||||
* Applies a perspective projection transform. This transform
|
||||
* scales points in X and Y based on their Z value, scaling
|
||||
* points with positive Z values away from the origin, and
|
||||
* those with negative Z values towards the origin. Points
|
||||
* on the z=0 plane are unchanged.
|
||||
*
|
||||
* Returns: The new matrix
|
||||
**/
|
||||
GskTransform *
|
||||
gsk_transform_perspective (GskTransform *next,
|
||||
float depth)
|
||||
{
|
||||
GskPerspectiveTransform *result;
|
||||
|
||||
result = gsk_transform_alloc (&GSK_PERSPECTIVE_TRANSFORM_CLASS,
|
||||
GSK_TRANSFORM_CATEGORY_ANY,
|
||||
next);
|
||||
|
||||
result->depth = depth;
|
||||
|
||||
return &result->parent;
|
||||
}
|
||||
|
||||
/*** PUBLIC API ***/
|
||||
|
||||
static void
|
||||
|
@ -105,6 +105,9 @@ GskTransform * gsk_transform_scale_3d (GskTransform
|
||||
float factor_x,
|
||||
float factor_y,
|
||||
float factor_z);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GskTransform * gsk_transform_perspective (GskTransform *next,
|
||||
float depth);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gsk_transform_transform_bounds (GskTransform *self,
|
||||
|
@ -35,7 +35,8 @@ typedef enum {
|
||||
GTK_CSS_TRANSFORM_SCALE,
|
||||
GTK_CSS_TRANSFORM_SKEW,
|
||||
GTK_CSS_TRANSFORM_SKEW_X,
|
||||
GTK_CSS_TRANSFORM_SKEW_Y
|
||||
GTK_CSS_TRANSFORM_SKEW_Y,
|
||||
GTK_CSS_TRANSFORM_PERSPECTIVE
|
||||
} GtkCssTransformType;
|
||||
|
||||
union _GtkCssTransform {
|
||||
@ -66,6 +67,10 @@ union _GtkCssTransform {
|
||||
GtkCssTransformType type;
|
||||
GtkCssValue *skew;
|
||||
} skew_x, skew_y;
|
||||
struct {
|
||||
GtkCssTransformType type;
|
||||
GtkCssValue *depth;
|
||||
} perspective;
|
||||
};
|
||||
|
||||
struct _GtkCssValue {
|
||||
@ -110,6 +115,9 @@ gtk_css_transform_clear (GtkCssTransform *transform)
|
||||
case GTK_CSS_TRANSFORM_SKEW_Y:
|
||||
_gtk_css_value_unref (transform->skew_y.skew);
|
||||
break;
|
||||
case GTK_CSS_TRANSFORM_PERSPECTIVE:
|
||||
_gtk_css_value_unref (transform->perspective.depth);
|
||||
break;
|
||||
case GTK_CSS_TRANSFORM_NONE:
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
@ -117,7 +125,7 @@ gtk_css_transform_clear (GtkCssTransform *transform)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
static gboolean
|
||||
gtk_css_transform_init_identity (GtkCssTransform *transform,
|
||||
GtkCssTransformType type)
|
||||
{
|
||||
@ -152,13 +160,18 @@ gtk_css_transform_init_identity (GtkCssTransform *transform,
|
||||
case GTK_CSS_TRANSFORM_SKEW_Y:
|
||||
transform->skew_y.skew = _gtk_css_number_value_new (0, GTK_CSS_DEG);
|
||||
break;
|
||||
case GTK_CSS_TRANSFORM_PERSPECTIVE:
|
||||
return FALSE;
|
||||
|
||||
case GTK_CSS_TRANSFORM_NONE:
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
break;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
transform->type = type;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static GskTransform *
|
||||
@ -198,7 +211,7 @@ gtk_css_transform_apply (const GtkCssTransform *transform,
|
||||
_gtk_css_number_value_get (transform->scale.x, 1),
|
||||
_gtk_css_number_value_get (transform->scale.y, 1),
|
||||
_gtk_css_number_value_get (transform->scale.z, 1));
|
||||
break;
|
||||
|
||||
case GTK_CSS_TRANSFORM_SKEW:
|
||||
graphene_matrix_init_skew (&skew,
|
||||
_gtk_css_number_value_get (transform->skew.x, 100) / 180.0f * G_PI,
|
||||
@ -217,6 +230,10 @@ gtk_css_transform_apply (const GtkCssTransform *transform,
|
||||
_gtk_css_number_value_get (transform->skew_y.skew, 100) / 180.0f * G_PI);
|
||||
return gsk_transform_matrix (next, &skew);
|
||||
|
||||
case GTK_CSS_TRANSFORM_PERSPECTIVE:
|
||||
return gsk_transform_perspective (next,
|
||||
_gtk_css_number_value_get (transform->perspective.depth, 100));
|
||||
|
||||
case GTK_CSS_TRANSFORM_NONE:
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
@ -303,6 +320,9 @@ gtk_css_transform_compute (GtkCssTransform *dest,
|
||||
case GTK_CSS_TRANSFORM_SKEW_Y:
|
||||
dest->skew_y.skew = _gtk_css_value_compute (src->skew_y.skew, property_id, provider, style, parent_style);
|
||||
return dest->skew_y.skew == src->skew_y.skew;
|
||||
case GTK_CSS_TRANSFORM_PERSPECTIVE:
|
||||
dest->perspective.depth = _gtk_css_value_compute (src->perspective.depth, property_id, provider, style, parent_style);
|
||||
return dest->perspective.depth == src->perspective.depth;
|
||||
case GTK_CSS_TRANSFORM_NONE:
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
@ -389,6 +409,8 @@ gtk_css_transform_equal (const GtkCssTransform *transform1,
|
||||
return _gtk_css_value_equal (transform1->skew_x.skew, transform2->skew_x.skew);
|
||||
case GTK_CSS_TRANSFORM_SKEW_Y:
|
||||
return _gtk_css_value_equal (transform1->skew_y.skew, transform2->skew_y.skew);
|
||||
case GTK_CSS_TRANSFORM_PERSPECTIVE:
|
||||
return _gtk_css_value_equal (transform1->perspective.depth, transform2->perspective.depth);
|
||||
case GTK_CSS_TRANSFORM_NONE:
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
@ -416,7 +438,8 @@ gtk_css_value_transform_equal (const GtkCssValue *value1,
|
||||
{
|
||||
GtkCssTransform transform;
|
||||
|
||||
gtk_css_transform_init_identity (&transform, larger->transforms[i].type);
|
||||
if (!gtk_css_transform_init_identity (&transform, larger->transforms[i].type))
|
||||
return FALSE;
|
||||
|
||||
if (!gtk_css_transform_equal (&larger->transforms[i], &transform))
|
||||
{
|
||||
@ -430,6 +453,38 @@ gtk_css_value_transform_equal (const GtkCssValue *value1,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_css_transform_transition_default (GtkCssTransform *result,
|
||||
const GtkCssTransform *start,
|
||||
const GtkCssTransform *end,
|
||||
guint property_id,
|
||||
double progress)
|
||||
{
|
||||
graphene_matrix_t start_mat, end_mat;
|
||||
GskTransform *trans;
|
||||
|
||||
result->type = GTK_CSS_TRANSFORM_MATRIX;
|
||||
|
||||
if (start)
|
||||
trans = gtk_css_transform_apply (start, NULL);
|
||||
else
|
||||
trans = NULL;
|
||||
gsk_transform_to_matrix (trans, &start_mat);
|
||||
gsk_transform_unref (trans);
|
||||
|
||||
if (end)
|
||||
trans = gtk_css_transform_apply (end, NULL);
|
||||
else
|
||||
trans = NULL;
|
||||
gsk_transform_to_matrix (trans, &end_mat);
|
||||
gsk_transform_unref (trans);
|
||||
|
||||
graphene_matrix_interpolate (&start_mat,
|
||||
&end_mat,
|
||||
progress,
|
||||
&result->matrix.matrix);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_css_transform_transition (GtkCssTransform *result,
|
||||
const GtkCssTransform *start,
|
||||
@ -473,6 +528,9 @@ gtk_css_transform_transition (GtkCssTransform *result,
|
||||
case GTK_CSS_TRANSFORM_SKEW_Y:
|
||||
result->skew_y.skew = _gtk_css_value_transition (start->skew_y.skew, end->skew_y.skew, property_id, progress);
|
||||
break;
|
||||
case GTK_CSS_TRANSFORM_PERSPECTIVE:
|
||||
gtk_css_transform_transition_default (result, start, end, property_id, progress);
|
||||
break;
|
||||
case GTK_CSS_TRANSFORM_NONE:
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
@ -546,25 +604,45 @@ gtk_css_value_transform_transition (GtkCssValue *start,
|
||||
{
|
||||
GtkCssTransform transform;
|
||||
|
||||
gtk_css_transform_init_identity (&transform, start->transforms[i].type);
|
||||
gtk_css_transform_transition (&result->transforms[i],
|
||||
&start->transforms[i],
|
||||
&transform,
|
||||
property_id,
|
||||
progress);
|
||||
gtk_css_transform_clear (&transform);
|
||||
if (gtk_css_transform_init_identity (&transform, start->transforms[i].type))
|
||||
{
|
||||
gtk_css_transform_transition (&result->transforms[i],
|
||||
&start->transforms[i],
|
||||
&transform,
|
||||
property_id,
|
||||
progress);
|
||||
gtk_css_transform_clear (&transform);
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_css_transform_transition_default (&result->transforms[i],
|
||||
&start->transforms[i],
|
||||
NULL,
|
||||
property_id,
|
||||
progress);
|
||||
}
|
||||
}
|
||||
for (; i < end->n_transforms; i++)
|
||||
{
|
||||
GtkCssTransform transform;
|
||||
|
||||
gtk_css_transform_init_identity (&transform, end->transforms[i].type);
|
||||
gtk_css_transform_transition (&result->transforms[i],
|
||||
&transform,
|
||||
&end->transforms[i],
|
||||
property_id,
|
||||
progress);
|
||||
gtk_css_transform_clear (&transform);
|
||||
if (gtk_css_transform_init_identity (&transform, end->transforms[i].type))
|
||||
{
|
||||
gtk_css_transform_transition (&result->transforms[i],
|
||||
&transform,
|
||||
&end->transforms[i],
|
||||
property_id,
|
||||
progress);
|
||||
gtk_css_transform_clear (&transform);
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_css_transform_transition_default (&result->transforms[i],
|
||||
NULL,
|
||||
&end->transforms[i],
|
||||
property_id,
|
||||
progress);
|
||||
}
|
||||
}
|
||||
|
||||
g_assert (i == MAX (start->n_transforms, end->n_transforms));
|
||||
@ -678,6 +756,11 @@ gtk_css_transform_print (const GtkCssTransform *transform,
|
||||
_gtk_css_value_print (transform->skew_y.skew, string);
|
||||
g_string_append (string, ")");
|
||||
break;
|
||||
case GTK_CSS_TRANSFORM_PERSPECTIVE:
|
||||
g_string_append (string, "perspective(");
|
||||
_gtk_css_value_print (transform->perspective.depth, string);
|
||||
g_string_append (string, ")");
|
||||
break;
|
||||
case GTK_CSS_TRANSFORM_NONE:
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
@ -1046,6 +1129,14 @@ gtk_css_transform_parse (GtkCssTransform *transform,
|
||||
if (transform->skew_y.skew == NULL)
|
||||
return FALSE;
|
||||
}
|
||||
else if (_gtk_css_parser_try (parser, "perspective(", TRUE))
|
||||
{
|
||||
transform->type = GTK_CSS_TRANSFORM_PERSPECTIVE;
|
||||
|
||||
transform->perspective.depth = _gtk_css_number_value_parse (parser, GTK_CSS_PARSE_LENGTH);
|
||||
if (transform->perspective.depth == NULL)
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
_gtk_css_parser_error (parser, "unknown syntax for transform");
|
||||
|
@ -1354,7 +1354,7 @@ gtk_snapshot_rotate_3d (GtkSnapshot *snapshot,
|
||||
* @factor_x: scaling factor on the X axis
|
||||
* @factor_y: scaling factor on the Y axis
|
||||
*
|
||||
* Scales @@snapshot's coordinate system in 2-dimensional space by
|
||||
* Scales @snapshot's coordinate system in 2-dimensional space by
|
||||
* the given factors.
|
||||
*
|
||||
* Use gtk_snapshot_scale_3d() to scale in all 3 dimensions.
|
||||
@ -1379,7 +1379,7 @@ gtk_snapshot_scale (GtkSnapshot *snapshot,
|
||||
* @factor_y: scaling factor on the Y axis
|
||||
* @factor_z: scaling factor on the Z axis
|
||||
*
|
||||
* Scales @@snapshot's coordinate system by the given factors.
|
||||
* Scales @snapshot's coordinate system by the given factors.
|
||||
*/
|
||||
void
|
||||
gtk_snapshot_scale_3d (GtkSnapshot *snapshot,
|
||||
@ -1395,6 +1395,27 @@ gtk_snapshot_scale_3d (GtkSnapshot *snapshot,
|
||||
state->transform = gsk_transform_scale_3d (state->transform, factor_x, factor_y, factor_z);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_snapshot_perspective:
|
||||
* @snapshot: a #GtkSnapshot
|
||||
* @depth: distance of the z=0 plane
|
||||
*
|
||||
* Applies a perspective projection transform.
|
||||
*
|
||||
* See gsk_transform_perspective() for a discussion on the details.
|
||||
*/
|
||||
void
|
||||
gtk_snapshot_perspective (GtkSnapshot *snapshot,
|
||||
float depth)
|
||||
{
|
||||
GtkSnapshotState *state;
|
||||
|
||||
g_return_if_fail (GTK_IS_SNAPSHOT (snapshot));
|
||||
|
||||
state = gtk_snapshot_get_current_state (snapshot);
|
||||
state->transform = gsk_transform_perspective (state->transform, depth);
|
||||
}
|
||||
|
||||
void
|
||||
gtk_snapshot_append_node_internal (GtkSnapshot *snapshot,
|
||||
GskRenderNode *node)
|
||||
|
@ -134,6 +134,9 @@ void gtk_snapshot_scale_3d (GtkSnapshot
|
||||
float factor_y,
|
||||
float factor_z);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_snapshot_perspective (GtkSnapshot *snapshot,
|
||||
float depth);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_snapshot_append_node (GtkSnapshot *snapshot,
|
||||
GskRenderNode *node);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
|
@ -85,6 +85,7 @@ static struct {
|
||||
{ GSK_TRANSFORM_CATEGORY_3D },
|
||||
{ GSK_TRANSFORM_CATEGORY_2D_AFFINE },
|
||||
{ GSK_TRANSFORM_CATEGORY_3D },
|
||||
{ GSK_TRANSFORM_CATEGORY_ANY },
|
||||
};
|
||||
|
||||
static GskTransform *
|
||||
@ -117,6 +118,9 @@ apply_test_transform (GskTransform *transform,
|
||||
case 7:
|
||||
return gsk_transform_scale_3d (transform, 2, 3, 5);
|
||||
|
||||
case 8:
|
||||
return gsk_transform_perspective (transform, 5);
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
return NULL;
|
||||
|
Loading…
Reference in New Issue
Block a user