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)?
This commit is contained in:
Benjamin Otte 2024-07-09 10:33:55 +02:00
parent 4cfcc7e521
commit 3bcfc5539c
5 changed files with 278 additions and 1 deletions

61
gdk/gdkdihedral.c Normal file
View File

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

View File

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

View File

@ -15,6 +15,7 @@ gdk_public_sources = files([
'gdkdevice.c',
'gdkdevicepad.c',
'gdkdevicetool.c',
'gdkdihedral.c',
'gdkdisplay.c',
'gdkdisplaymanager.c',
'gdkdmabuf.c',

View File

@ -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);
}
/*<private>
* 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`

View File

@ -25,6 +25,9 @@
#include <gtk/css/gtkcss.h>
#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);