Compare commits

...

2 Commits

Author SHA1 Message Date
Benjamin Otte
3a8db343b8 wip: Add a cube stack transition 2019-03-05 20:44:45 +01:00
Benjamin Otte
08d904a732 transform: Add perspective()
This commit adds gsk_transform_perspective() as well ass support for
perspective() in the CSS syntax.
2019-03-05 20:44:41 +01:00
12 changed files with 347 additions and 25 deletions

View File

@@ -48,7 +48,7 @@ change_transition_state (GSimpleAction *action,
GtkStackTransitionType transition;
if (g_variant_get_boolean (state))
transition = GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT_RIGHT;
transition = GTK_STACK_TRANSITION_TYPE_CUBE;
else
transition = GTK_STACK_TRANSITION_TYPE_NONE;

View File

@@ -429,7 +429,7 @@ Suspendisse feugiat quam quis dolor accumsan cursus.</property>
<property name="margin">10</property>
<child>
<object class="GtkStack" id="toplevel_stack">
<property name="transition-duration">30000</property>
<property name="transition-duration">3000</property>
<child>
<object class="GtkStackPage">
<property name="name">page1</property>

View File

@@ -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>

View File

@@ -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

View File

@@ -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

View File

@@ -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,

View File

@@ -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");

View File

@@ -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)

View File

@@ -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

View File

@@ -104,6 +104,7 @@
* @GTK_STACK_TRANSITION_TYPE_OVER_DOWN_UP: Cover the old page sliding down or uncover the new page sliding up, according to order
* @GTK_STACK_TRANSITION_TYPE_OVER_LEFT_RIGHT: Cover the old page sliding left or uncover the new page sliding right, according to order
* @GTK_STACK_TRANSITION_TYPE_OVER_RIGHT_LEFT: Cover the old page sliding right or uncover the new page sliding left, according to order
* @GTK_STACK_TRANSITION_TYPE_CUBE: Pretend the pages are sides of a cube and rotate that cube
*
* These enumeration values describe the possible transitions
* between pages in a #GtkStack widget.
@@ -911,6 +912,7 @@ get_simple_transition_type (gboolean new_child_first,
case GTK_STACK_TRANSITION_TYPE_UNDER_LEFT:
case GTK_STACK_TRANSITION_TYPE_UNDER_RIGHT:
case GTK_STACK_TRANSITION_TYPE_CROSSFADE:
case GTK_STACK_TRANSITION_TYPE_CUBE:
default:
return transition_type;
}
@@ -1071,6 +1073,7 @@ effective_transition_type (GtkStack *stack,
case GTK_STACK_TRANSITION_TYPE_OVER_LEFT_RIGHT:
case GTK_STACK_TRANSITION_TYPE_OVER_RIGHT_LEFT:
case GTK_STACK_TRANSITION_TYPE_CROSSFADE:
case GTK_STACK_TRANSITION_TYPE_CUBE:
default:
return transition_type;
}
@@ -2047,7 +2050,6 @@ gtk_stack_forall (GtkContainer *container,
}
}
#include <gsk/gskrendernodeprivate.h>
static void
gtk_stack_compute_expand (GtkWidget *widget,
gboolean *hexpand_p,
@@ -2169,6 +2171,84 @@ gtk_stack_snapshot_under (GtkWidget *widget,
}
}
static void
gtk_stack_snapshot_cube (GtkWidget *widget,
GtkSnapshot *snapshot)
{
GtkStack *stack = GTK_STACK (widget);
GtkStackPrivate *priv = gtk_stack_get_instance_private (stack);
double progress = gtk_progress_tracker_get_progress (&priv->tracker, FALSE);
if (priv->last_visible_node && progress > 0.5)
{
gtk_snapshot_save (snapshot);
gtk_snapshot_translate_3d (snapshot, &GRAPHENE_POINT3D_INIT (
gtk_widget_get_width (widget) / 2.f,
gtk_widget_get_height (widget) / 2.f,
0));
gtk_snapshot_perspective (snapshot, 2 * gtk_widget_get_width (widget) / 1.f);
gtk_snapshot_translate_3d (snapshot, &GRAPHENE_POINT3D_INIT (
0, 0,
- gtk_widget_get_width (widget) / 2.f));
gtk_snapshot_rotate_3d (snapshot, -90 * progress, graphene_vec3_y_axis());
gtk_snapshot_translate_3d (snapshot, &GRAPHENE_POINT3D_INIT (
- gtk_widget_get_width (widget) / 2.f,
- gtk_widget_get_height (widget) / 2.f,
gtk_widget_get_width (widget) / 2.f));
gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (
priv->last_visible_surface_allocation.x,
priv->last_visible_surface_allocation.y));
gtk_snapshot_append_node (snapshot, priv->last_visible_node);
gtk_snapshot_restore (snapshot);
}
gtk_snapshot_save (snapshot);
gtk_snapshot_translate_3d (snapshot, &GRAPHENE_POINT3D_INIT (
gtk_widget_get_width (widget) / 2.f,
gtk_widget_get_height (widget) / 2.f,
0));
gtk_snapshot_perspective (snapshot, 2 * gtk_widget_get_width (widget) / 1.f);
gtk_snapshot_translate_3d (snapshot, &GRAPHENE_POINT3D_INIT (
0, 0,
- gtk_widget_get_width (widget) / 2.f));
gtk_snapshot_rotate_3d (snapshot, 90 * (1.0 - progress), graphene_vec3_y_axis());
gtk_snapshot_translate_3d (snapshot, &GRAPHENE_POINT3D_INIT (
- gtk_widget_get_width (widget) / 2.f,
- gtk_widget_get_height (widget) / 2.f,
gtk_widget_get_width (widget) / 2.f));
gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (
priv->last_visible_surface_allocation.x,
priv->last_visible_surface_allocation.y));
gtk_widget_snapshot_child (widget,
priv->visible_child->widget,
snapshot);
gtk_snapshot_restore (snapshot);
if (priv->last_visible_node && progress <= 0.5)
{
gtk_snapshot_save (snapshot);
gtk_snapshot_translate_3d (snapshot, &GRAPHENE_POINT3D_INIT (
gtk_widget_get_width (widget) / 2.f,
gtk_widget_get_height (widget) / 2.f,
0));
gtk_snapshot_perspective (snapshot, 2 * gtk_widget_get_width (widget) / 1.f);
gtk_snapshot_translate_3d (snapshot, &GRAPHENE_POINT3D_INIT (
0, 0,
- gtk_widget_get_width (widget) / 2.f));
gtk_snapshot_rotate_3d (snapshot, -90 * progress, graphene_vec3_y_axis());
gtk_snapshot_translate_3d (snapshot, &GRAPHENE_POINT3D_INIT (
- gtk_widget_get_width (widget) / 2.f,
- gtk_widget_get_height (widget) / 2.f,
gtk_widget_get_width (widget) / 2.f));
gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (
priv->last_visible_surface_allocation.x,
priv->last_visible_surface_allocation.y));
gtk_snapshot_append_node (snapshot, priv->last_visible_node);
gtk_snapshot_restore (snapshot);
}
}
static void
gtk_stack_snapshot_slide (GtkWidget *widget,
GtkSnapshot *snapshot)
@@ -2285,6 +2365,9 @@ gtk_stack_snapshot (GtkWidget *widget,
case GTK_STACK_TRANSITION_TYPE_UNDER_RIGHT:
gtk_stack_snapshot_under (widget, snapshot);
break;
case GTK_STACK_TRANSITION_TYPE_CUBE:
gtk_stack_snapshot_cube (widget, snapshot);
break;
case GTK_STACK_TRANSITION_TYPE_NONE:
case GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT_RIGHT:
case GTK_STACK_TRANSITION_TYPE_SLIDE_UP_DOWN:

View File

@@ -72,7 +72,8 @@ typedef enum {
GTK_STACK_TRANSITION_TYPE_OVER_UP_DOWN,
GTK_STACK_TRANSITION_TYPE_OVER_DOWN_UP,
GTK_STACK_TRANSITION_TYPE_OVER_LEFT_RIGHT,
GTK_STACK_TRANSITION_TYPE_OVER_RIGHT_LEFT
GTK_STACK_TRANSITION_TYPE_OVER_RIGHT_LEFT,
GTK_STACK_TRANSITION_TYPE_CUBE
} GtkStackTransitionType;
struct _GtkStack {

View File

@@ -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;