From 3bcfc5539cff5e8d0b1cbec8d5c89787165eeb59 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Tue, 9 Jul 2024 10:33:55 +0200 Subject: [PATCH] transform: Add gsk_transform_to_dihedral() I hate everything about this. Is is xy or yx now? Do I need to combine(a, b) or combine(b, a)? --- gdk/gdkdihedral.c | 61 ++++++++++++ gdk/gdkdihedralprivate.h | 9 ++ gdk/meson.build | 1 + gsk/gsktransform.c | 198 +++++++++++++++++++++++++++++++++++++- gsk/gsktransformprivate.h | 10 ++ 5 files changed, 278 insertions(+), 1 deletion(-) create mode 100644 gdk/gdkdihedral.c diff --git a/gdk/gdkdihedral.c b/gdk/gdkdihedral.c new file mode 100644 index 0000000000..74f5f8b280 --- /dev/null +++ b/gdk/gdkdihedral.c @@ -0,0 +1,61 @@ + +#include "config.h" + +#include "gdkdihedralprivate.h" + +void +gdk_dihedral_get_mat2 (GdkDihedral transform, + float *xx, + float *xy, + float *yx, + float *yy) +{ + const float mat[8][2][2] = { + [GDK_DIHEDRAL_NORMAL] = { + { 1.0, 0.0 }, + { 0.0, 1.0 } + }, + [GDK_DIHEDRAL_90] = { + { 0.0, 1.0 }, + { -1.0, 0.0 } + }, + [GDK_DIHEDRAL_180] = { + { -1.0, 0.0 }, + { 0.0, -1.0 } + }, + [GDK_DIHEDRAL_270] = { + { 0.0, -1.0 }, + { 1.0, 0.0 } + }, + [GDK_DIHEDRAL_FLIPPED] = { + { -1.0, 0.0 }, + { 0.0, 1.0 } + }, + [GDK_DIHEDRAL_FLIPPED_90] = { + { 0.0, -1.0 }, + { -1.0, 0.0 } + }, + [GDK_DIHEDRAL_FLIPPED_180] = { + { 1.0, 0.0 }, + { 0.0, -1.0 } + }, + [GDK_DIHEDRAL_FLIPPED_270] = { + { 0.0, 1.0 }, + { 1.0, 0.0 } + }, + }; + + *xx = mat[transform][0][0]; + *xy = mat[transform][1][0]; + *yx = mat[transform][0][1]; + *yy = mat[transform][1][1]; +} + +GdkDihedral +gdk_dihedral_combine (GdkDihedral first, + GdkDihedral second) +{ + return ((first & 4) ^ (second & 4)) | + ((((first & 3) * (((second & 4) >> 1) + 1)) + second) & 3); +} + diff --git a/gdk/gdkdihedralprivate.h b/gdk/gdkdihedralprivate.h index 8b6765f762..a754401fd5 100644 --- a/gdk/gdkdihedralprivate.h +++ b/gdk/gdkdihedralprivate.h @@ -32,5 +32,14 @@ typedef enum { GDK_DIHEDRAL_FLIPPED_270, } GdkDihedral; +void gdk_dihedral_get_mat2 (GdkDihedral transform, + float *xx, + float *xy, + float *yx, + float *yy); + +GdkDihedral gdk_dihedral_combine (GdkDihedral first, + GdkDihedral second); + G_END_DECLS diff --git a/gdk/meson.build b/gdk/meson.build index 1e00cd6764..290e4f71d6 100644 --- a/gdk/meson.build +++ b/gdk/meson.build @@ -15,6 +15,7 @@ gdk_public_sources = files([ 'gdkdevice.c', 'gdkdevicepad.c', 'gdkdevicetool.c', + 'gdkdihedral.c', 'gdkdisplay.c', 'gdkdisplaymanager.c', 'gdkdmabuf.c', diff --git a/gsk/gsktransform.c b/gsk/gsktransform.c index 27ab162e84..d4309da32f 100644 --- a/gsk/gsktransform.c +++ b/gsk/gsktransform.c @@ -53,6 +53,12 @@ struct _GskTransformClass float *out_yy, float *out_dx, float *out_dy); + void (* apply_dihedral) (GskTransform *transform, + GdkDihedral *dihedral, + float *out_scale_x, + float *out_scale_y, + float *out_dx, + float *out_dy); void (* apply_affine) (GskTransform *transform, float *out_scale_x, float *out_scale_y, @@ -72,7 +78,6 @@ struct _GskTransformClass GskTransform *second_transform); }; - G_DEFINE_BOXED_TYPE (GskTransform, gsk_transform, gsk_transform_ref, gsk_transform_unref) @@ -155,6 +160,16 @@ gsk_identity_transform_apply_2d (GskTransform *transform, { } +static void +gsk_identity_transform_apply_dihedral (GskTransform *transform, + GdkDihedral *dihedral, + float *out_scale_x, + float *out_scale_y, + float *out_dx, + float *out_dy) +{ +} + static void gsk_identity_transform_apply_affine (GskTransform *transform, float *out_scale_x, @@ -218,6 +233,7 @@ static const GskTransformClass GSK_IDENTITY_TRANSFORM_CLASS = gsk_identity_transform_finalize, gsk_identity_transform_to_matrix, gsk_identity_transform_apply_2d, + gsk_identity_transform_apply_dihedral, gsk_identity_transform_apply_affine, gsk_identity_transform_apply_translate, gsk_identity_transform_print, @@ -300,6 +316,45 @@ gsk_matrix_transform_apply_2d (GskTransform *transform, *out_dy = graphene_matrix_get_value (&mat, 3, 1); } +static void +gsk_matrix_transform_apply_dihedral (GskTransform *transform, + GdkDihedral *out_dihedral, + float *out_scale_x, + float *out_scale_y, + float *out_dx, + float *out_dy) +{ + GskMatrixTransform *self = (GskMatrixTransform *) transform; + + switch (transform->category) + { + case GSK_FINE_TRANSFORM_CATEGORY_UNKNOWN: + case GSK_FINE_TRANSFORM_CATEGORY_ANY: + case GSK_FINE_TRANSFORM_CATEGORY_3D: + case GSK_FINE_TRANSFORM_CATEGORY_2D: + case GSK_FINE_TRANSFORM_CATEGORY_2D_DIHEDRAL: + default: + g_assert_not_reached (); + break; + + case GSK_FINE_TRANSFORM_CATEGORY_2D_NEGATIVE_AFFINE: + case GSK_FINE_TRANSFORM_CATEGORY_2D_AFFINE: + *out_dx += *out_scale_x * graphene_matrix_get_x_translation (&self->matrix); + *out_dy += *out_scale_y * graphene_matrix_get_y_translation (&self->matrix); + *out_scale_x *= graphene_matrix_get_x_scale (&self->matrix); + *out_scale_y *= graphene_matrix_get_y_scale (&self->matrix); + break; + + case GSK_FINE_TRANSFORM_CATEGORY_2D_TRANSLATE: + *out_dx += *out_scale_x * graphene_matrix_get_x_translation (&self->matrix); + *out_dy += *out_scale_y * graphene_matrix_get_y_translation (&self->matrix); + break; + + case GSK_FINE_TRANSFORM_CATEGORY_IDENTITY: + break; + } +} + static void gsk_matrix_transform_apply_affine (GskTransform *transform, float *out_scale_x, @@ -466,6 +521,7 @@ static const GskTransformClass GSK_TRANSFORM_TRANSFORM_CLASS = gsk_matrix_transform_finalize, gsk_matrix_transform_to_matrix, gsk_matrix_transform_apply_2d, + gsk_matrix_transform_apply_dihedral, gsk_matrix_transform_apply_affine, gsk_matrix_transform_apply_translate, gsk_matrix_transform_print, @@ -481,6 +537,9 @@ gsk_transform_matrix_with_category (GskTransform *next, { GskMatrixTransform *result = gsk_transform_alloc (&GSK_TRANSFORM_TRANSFORM_CLASS, category, next); + /* We can't deal with these yet - also because lots of code gets transposing wrong */ + g_assert (category != GSK_FINE_TRANSFORM_CATEGORY_2D_DIHEDRAL); + graphene_matrix_init_from_matrix (&result->matrix, matrix); return &result->parent; @@ -548,6 +607,25 @@ gsk_translate_transform_apply_2d (GskTransform *transform, *out_dy += *out_yx * self->point.x + *out_yy * self->point.y; } +static void +gsk_translate_transform_apply_dihedral (GskTransform *transform, + GdkDihedral *out_dihedral, + float *out_scale_x, + float *out_scale_y, + float *out_dx, + float *out_dy) +{ + GskTranslateTransform *self = (GskTranslateTransform *) transform; + float xx, xy, yx, yy; + + g_assert (self->point.z == 0.0); + + gdk_dihedral_get_mat2 (*out_dihedral, &xx, &xy, &yx, &yy); + + *out_dx += *out_scale_x * (xx * self->point.x + xy * self->point.y); + *out_dy += *out_scale_y * (yx * self->point.x + yy * self->point.y); +} + static void gsk_translate_transform_apply_affine (GskTransform *transform, float *out_scale_x, @@ -635,6 +713,7 @@ static const GskTransformClass GSK_TRANSLATE_TRANSFORM_CLASS = gsk_translate_transform_finalize, gsk_translate_transform_to_matrix, gsk_translate_transform_apply_2d, + gsk_translate_transform_apply_dihedral, gsk_translate_transform_apply_affine, gsk_translate_transform_apply_translate, gsk_translate_transform_print, @@ -804,6 +883,23 @@ gsk_rotate_transform_apply_2d (GskTransform *transform, *out_yy = yy; } +static void +gsk_rotate_transform_apply_dihedral (GskTransform *transform, + GdkDihedral *out_dihedral, + float *out_scale_x, + float *out_scale_y, + float *out_dx, + float *out_dy) +{ + GskRotateTransform *self = (GskRotateTransform *) transform; + GdkDihedral dihedral; + + dihedral = (int) self->angle / 90; + g_assert (dihedral >= GDK_DIHEDRAL_NORMAL && dihedral < GDK_DIHEDRAL_FLIPPED); + + *out_dihedral = gdk_dihedral_combine (dihedral, *out_dihedral); +} + static GskTransform * gsk_rotate_transform_apply (GskTransform *transform, GskTransform *apply_to) @@ -850,6 +946,7 @@ static const GskTransformClass GSK_ROTATE_TRANSFORM_CLASS = gsk_rotate_transform_finalize, gsk_rotate_transform_to_matrix, gsk_rotate_transform_apply_2d, + gsk_rotate_transform_apply_dihedral, NULL, NULL, gsk_rotate_transform_print, @@ -1009,6 +1106,7 @@ static const GskTransformClass GSK_ROTATE3D_TRANSFORM_CLASS = NULL, NULL, NULL, + NULL, gsk_rotate3d_transform_print, gsk_rotate3d_transform_apply, gsk_rotate3d_transform_invert, @@ -1190,6 +1288,7 @@ static const GskTransformClass GSK_SKEW_TRANSFORM_CLASS = gsk_skew_transform_apply_2d, NULL, NULL, + NULL, gsk_skew_transform_print, gsk_skew_transform_apply, gsk_skew_transform_invert, @@ -1277,6 +1376,41 @@ gsk_scale_transform_apply_2d (GskTransform *transform, *out_yy *= self->factor_y; } +static void +gsk_scale_transform_apply_dihedral (GskTransform *transform, + GdkDihedral *out_dihedral, + float *out_scale_x, + float *out_scale_y, + float *out_dx, + float *out_dy) +{ + GskScaleTransform *self = (GskScaleTransform *) transform; + GdkDihedral dihedral; + float xx, xy, yx, yy; + + g_assert (self->factor_z == 1.0); + + gdk_dihedral_get_mat2 (*out_dihedral, &xx, &xy, &yx, &yy); + + if (self->factor_x >= 0) + { + if (self->factor_y >= 0) + dihedral = GDK_DIHEDRAL_NORMAL; + else + dihedral = GDK_DIHEDRAL_FLIPPED_180; + } + else + { + if (self->factor_y >= 0) + dihedral = GDK_DIHEDRAL_FLIPPED; + else + dihedral = GDK_DIHEDRAL_180; + } + *out_dihedral = gdk_dihedral_combine (dihedral, *out_dihedral); + *out_scale_x *= fabs (xx * self->factor_x + xy * self->factor_y); + *out_scale_y *= fabs (yx * self->factor_x + yy * self->factor_y); +} + static void gsk_scale_transform_apply_affine (GskTransform *transform, float *out_scale_x, @@ -1361,6 +1495,7 @@ static const GskTransformClass GSK_SCALE_TRANSFORM_CLASS = gsk_scale_transform_finalize, gsk_scale_transform_to_matrix, gsk_scale_transform_apply_2d, + gsk_scale_transform_apply_dihedral, gsk_scale_transform_apply_affine, NULL, gsk_scale_transform_print, @@ -1526,6 +1661,7 @@ static const GskTransformClass GSK_PERSPECTIVE_TRANSFORM_CLASS = NULL, NULL, NULL, + NULL, gsk_perspective_transform_print, gsk_perspective_transform_apply, gsk_perspective_transform_invert, @@ -1909,6 +2045,66 @@ gsk_transform_to_affine (GskTransform *self, out_dx, out_dy); } +/* + * gsk_transform_to_dihedral: + * @self: a `GskTransform` + * @out_dihedral: (out): return location for the + * @out_scale_x: (out): return location for the scale + * factor in the x direction + * @out_scale_y: (out): return location for the scale + * factor in the y direction + * @out_dx: (out): return location for the translation + * in the x direction + * @out_dy: (out): return location for the translation + * in the y direction + * + * Converts a `GskTransform` to 2D affine transformation factors. + * + * To recreate an equivalent transform from the factors returned + * by this function, use + * + * gsk_transform_scale (gsk_transform_translate (NULL, + * &GRAPHENE_POINT_T (dx, dy)), + * sx, sy) + * + * @self must be a 2D affine transformation. If you are not + * sure, use + * + * gsk_transform_get_category() >= %GSK_TRANSFORM_CATEGORY_2D_AFFINE + * + * to check. + */ +void +gsk_transform_to_dihedral (GskTransform *self, + GdkDihedral *out_dihedral, + float *out_scale_x, + float *out_scale_y, + float *out_dx, + float *out_dy) +{ + if (self == NULL) + { + *out_dihedral = GDK_DIHEDRAL_NORMAL; + *out_scale_x = 1.0f; + *out_scale_y = 1.0f; + *out_dx = 0.0f; + *out_dy = 0.0f; + return; + } + + g_assert (self->category >= GSK_FINE_TRANSFORM_CATEGORY_2D_DIHEDRAL); + + gsk_transform_to_dihedral (self->next, + out_dihedral, + out_scale_x, out_scale_y, + out_dx, out_dy); + + self->transform_class->apply_dihedral (self, + out_dihedral, + out_scale_x, out_scale_y, + out_dx, out_dy); +} + /** * gsk_transform_to_translate: * @self: a `GskTransform` diff --git a/gsk/gsktransformprivate.h b/gsk/gsktransformprivate.h index 53d444dc87..cb848f672b 100644 --- a/gsk/gsktransformprivate.h +++ b/gsk/gsktransformprivate.h @@ -25,6 +25,9 @@ #include #include "gtk/css/gtkcssparserprivate.h" +/* declares GdkDihedralTransform */ +#include "gdk/gdksubsurfaceprivate.h" + G_BEGIN_DECLS typedef struct _GskTransformClass GskTransformClass; @@ -87,6 +90,13 @@ struct _GskTransform gboolean gsk_transform_parser_parse (GtkCssParser *parser, GskTransform **out_transform); +void gsk_transform_to_dihedral (GskTransform *self, + GdkDihedral *out_dihedral, + float *out_scale_x, + float *out_scale_y, + float *out_dx, + float *out_dy); + void gsk_matrix_transform_point (const graphene_matrix_t *m, const graphene_point_t *p, graphene_point_t *res);