[gtk/wip/chergert/glproto: 795/920] add nine slicing helpers
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/wip/chergert/glproto: 795/920] add nine slicing helpers
- Date: Mon, 8 Feb 2021 19:15:42 +0000 (UTC)
commit 5f0101b30c894b0ff514181d05e8e4ef8ca54e7d
Author: Christian Hergert <chergert redhat com>
Date: Thu Jan 28 15:51:19 2021 -0800
add nine slicing helpers
- break it out into a single header with inlines
- interlace texture rect and translated areas (0..1)
- store nine-slice info with the texture itself
gsk/next/gskgltexturepool.c | 22 +++
gsk/next/gskgltexturepoolprivate.h | 66 +++++----
gsk/next/gskgltypesprivate.h | 1 +
gsk/next/ninesliceprivate.h | 284 +++++++++++++++++++++++++++++++++++++
4 files changed, 346 insertions(+), 27 deletions(-)
---
diff --git a/gsk/next/gskgltexturepool.c b/gsk/next/gskgltexturepool.c
index 18654a7a00..bc1ff47b0c 100644
--- a/gsk/next/gskgltexturepool.c
+++ b/gsk/next/gskgltexturepool.c
@@ -25,6 +25,7 @@
#include <gdk/gdktextureprivate.h>
#include "gskgltexturepoolprivate.h"
+#include "ninesliceprivate.h"
void
gsk_gl_texture_free (GskGLTexture *texture)
@@ -52,6 +53,7 @@ gsk_gl_texture_free (GskGLTexture *texture)
}
g_clear_pointer (&texture->slices, g_free);
+ g_clear_pointer (&texture->nine_slice, g_free);
g_slice_free (GskGLTexture, texture);
}
@@ -242,3 +244,23 @@ gsk_gl_texture_new (guint texture_id,
return texture;
}
+
+const GskGLTextureNineSlice *
+gsk_gl_texture_get_nine_slice (GskGLTexture *texture,
+ const GskRoundedRect *outline,
+ float extra_pixels)
+{
+ g_return_val_if_fail (texture != NULL, NULL);
+ g_return_val_if_fail (outline != NULL, NULL);
+
+ if G_UNLIKELY (texture->nine_slice == NULL)
+ {
+ texture->nine_slice = g_new0 (GskGLTextureNineSlice, 9);
+
+ nine_slice_rounded_rect (texture->nine_slice, outline);
+ nine_slice_grow (texture->nine_slice, extra_pixels);
+ nine_slice_to_texture_coords (texture->nine_slice, texture->width, texture->height);
+ }
+
+ return texture->nine_slice;
+}
diff --git a/gsk/next/gskgltexturepoolprivate.h b/gsk/next/gskgltexturepoolprivate.h
index 8c000b5ee8..68af88f44c 100644
--- a/gsk/next/gskgltexturepoolprivate.h
+++ b/gsk/next/gskgltexturepoolprivate.h
@@ -37,51 +37,63 @@ struct _GskGLTextureSlice
guint texture_id;
};
+struct _GskGLTextureNineSlice
+{
+ cairo_rectangle_int_t rect;
+ graphene_rect_t area;
+};
+
struct _GskGLTexture
{
/* Used to sort by width/height in pool */
- GList width_link;
- GList height_link;
+ GList width_link;
+ GList height_link;
/* Identifier of the frame that created it */
- gint64 last_used_in_frame;
+ gint64 last_used_in_frame;
/* Backpointer to texture (can be cleared asynchronously) */
- GdkTexture *user;
+ GdkTexture *user;
/* Only used by sliced textures */
GskGLTextureSlice *slices;
- guint n_slices;
+ guint n_slices;
+
+ /* Only used by nine-slice textures */
+ GskGLTextureNineSlice *nine_slice;
/* The actual GL texture identifier in some shared context */
- guint texture_id;
+ guint texture_id;
- float width;
- float height;
- int min_filter;
- int mag_filter;
+ float width;
+ float height;
+ int min_filter;
+ int mag_filter;
/* Set when used by an atlas so we don't drop the texture */
guint permanent : 1;
};
-void gsk_gl_texture_pool_init (GskGLTexturePool *self);
-void gsk_gl_texture_pool_clear (GskGLTexturePool *self);
-GskGLTexture *gsk_gl_texture_pool_get (GskGLTexturePool *self,
- float width,
- float height,
- int min_filter,
- int mag_filter,
- gboolean always_create);
-void gsk_gl_texture_pool_put (GskGLTexturePool *self,
- GskGLTexture *texture);
-GskGLTexture *gsk_gl_texture_new (guint texture_id,
- int width,
- int height,
- int min_filter,
- int mag_filter,
- gint64 frame_id);
-void gsk_gl_texture_free (GskGLTexture *texture);
+void gsk_gl_texture_pool_init (GskGLTexturePool *self);
+void gsk_gl_texture_pool_clear (GskGLTexturePool *self);
+GskGLTexture *gsk_gl_texture_pool_get (GskGLTexturePool *self,
+ float width,
+ float height,
+ int min_filter,
+ int mag_filter,
+ gboolean always_create);
+void gsk_gl_texture_pool_put (GskGLTexturePool *self,
+ GskGLTexture *texture);
+GskGLTexture *gsk_gl_texture_new (guint texture_id,
+ int width,
+ int height,
+ int min_filter,
+ int mag_filter,
+ gint64 frame_id);
+const GskGLTextureNineSlice *gsk_gl_texture_get_nine_slice (GskGLTexture *texture,
+ const GskRoundedRect *outline,
+ float extra_pixels);
+void gsk_gl_texture_free (GskGLTexture *texture);
G_END_DECLS
diff --git a/gsk/next/gskgltypesprivate.h b/gsk/next/gskgltypesprivate.h
index 5927d780fc..d8b22f7019 100644
--- a/gsk/next/gskgltypesprivate.h
+++ b/gsk/next/gskgltypesprivate.h
@@ -45,6 +45,7 @@ typedef struct _GskGLTexture GskGLTexture;
typedef struct _GskGLTextureSlice GskGLTextureSlice;
typedef struct _GskGLTextureAtlas GskGLTextureAtlas;
typedef struct _GskGLTextureLibrary GskGLTextureLibrary;
+typedef struct _GskGLTextureNineSlice GskGLTextureNineSlice;
typedef struct _GskGLUniformState GskGLUniformState;
typedef struct _GskNextDriver GskNextDriver;
diff --git a/gsk/next/ninesliceprivate.h b/gsk/next/ninesliceprivate.h
new file mode 100644
index 0000000000..02d250ec4e
--- /dev/null
+++ b/gsk/next/ninesliceprivate.h
@@ -0,0 +1,284 @@
+/* ninesliceprivate.h
+ *
+ * Copyright 2017 Timm Bäder <mail baedert org>
+ * Copyright 2021 Christian Hergert <chergert redhat com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#ifndef __NINE_SLICE_PRIVATE_H__
+#define __NINE_SLICE_PRIVATE_H__
+
+#include "gskgltexturepoolprivate.h"
+
+G_BEGIN_DECLS
+
+enum {
+ NINE_SLICE_TOP_LEFT = 0,
+ NINE_SLICE_TOP_CENTER = 1,
+ NINE_SLICE_TOP_RIGHT = 2,
+ NINE_SLICE_LEFT_CENTER = 3,
+ NINE_SLICE_CENTER = 4,
+ NINE_SLICE_RIGHT_CENTER = 5,
+ NINE_SLICE_BOTTOM_LEFT = 6,
+ NINE_SLICE_BOTTOM_CENTER = 7,
+ NINE_SLICE_BOTTOM_RIGHT = 8,
+};
+
+static inline bool G_GNUC_PURE
+slice_is_visible (const cairo_rectangle_int_t *r)
+{
+ return (r->width > 0 && r->height > 0);
+}
+
+static inline void
+nine_slice_rounded_rect (GskGLTextureNineSlice *slices,
+ const GskRoundedRect *rect)
+{
+ const graphene_point_t *origin = &rect->bounds.origin;
+ const graphene_size_t *size = &rect->bounds.size;
+ int top_height = ceilf (MAX (rect->corner[GSK_CORNER_TOP_LEFT].height,
+ rect->corner[GSK_CORNER_TOP_RIGHT].height));
+ int bottom_height = ceilf (MAX (rect->corner[GSK_CORNER_BOTTOM_LEFT].height,
+ rect->corner[GSK_CORNER_BOTTOM_RIGHT].height));
+ int right_width = ceilf (MAX (rect->corner[GSK_CORNER_TOP_RIGHT].width,
+ rect->corner[GSK_CORNER_BOTTOM_RIGHT].width));
+ int left_width = ceilf (MAX (rect->corner[GSK_CORNER_TOP_LEFT].width,
+ rect->corner[GSK_CORNER_BOTTOM_LEFT].width));
+
+ /* Top left */
+ slices[0].rect.x = origin->x;
+ slices[0].rect.y = origin->y;
+ slices[0].rect.width = left_width;
+ slices[0].rect.height = top_height;
+
+ /* Top center */
+ slices[1].rect.x = origin->x + size->width / 2.0 - 0.5;
+ slices[1].rect.y = origin->y;
+ slices[1].rect.width = 1;
+ slices[1].rect.height = top_height;
+
+ /* Top right */
+ slices[2].rect.x = origin->x + size->width - right_width;
+ slices[2].rect.y = origin->y;
+ slices[2].rect.width = right_width;
+ slices[2].rect.height = top_height;
+
+ /* Left center */
+ slices[3].rect.x = origin->x;
+ slices[3].rect.y = origin->y + size->height / 2.0;
+ slices[3].rect.width = left_width;
+ slices[3].rect.height = 1;
+
+ /* center */
+ slices[4].rect.x = origin->x + size->width / 2.0 - 0.5;
+ slices[4].rect.y = origin->y + size->height / 2.0 - 0.5;
+ slices[4].rect.width = 1;
+ slices[4].rect.height = 1;
+
+ /* Right center */
+ slices[5].rect.x = origin->x + size->width - right_width;
+ slices[5].rect.y = origin->y + (size->height / 2.0) - 0.5;
+ slices[5].rect.width = right_width;
+ slices[5].rect.height = 1;
+
+ /* Bottom Left */
+ slices[6].rect.x = origin->x;
+ slices[6].rect.y = origin->y + size->height - bottom_height;
+ slices[6].rect.width = left_width;
+ slices[6].rect.height = bottom_height;
+
+ /* Bottom center */
+ slices[7].rect.x = origin->x + (size->width / 2.0) - 0.5;
+ slices[7].rect.y = origin->y + size->height - bottom_height;
+ slices[7].rect.width = 1;
+ slices[7].rect.height = bottom_height;
+
+ /* Bottom right */
+ slices[8].rect.x = origin->x + size->width - right_width;
+ slices[8].rect.y = origin->y + size->height - bottom_height;
+ slices[8].rect.width = right_width;
+ slices[8].rect.height = bottom_height;
+
+#ifdef G_ENABLE_DEBUG
+ g_assert_cmpfloat (size->width, >=, left_width + right_width);
+ g_assert_cmpfloat (size->height, >=, top_height + bottom_height);
+#endif
+}
+
+static inline void
+nine_slice_to_texture_coords (GskGLTextureNineSlice *slices,
+ int texture_width,
+ int texture_height)
+{
+ float fw = (float)texture_width;
+ float fh = (float)texture_height;
+
+ for (guint i = 0; i < 9; i++)
+ {
+ GskGLTextureNineSlice *slice = &slices[i];
+
+ slice->area.origin.x = slice->rect.x / fw;
+ slice->area.origin.y = 1.0 - ((slice->rect.y + slice->rect.height) / fh);
+ slice->area.size.width = slice->rect.width / fw;
+ slice->area.size.height = slice->rect.height / fh;
+
+#ifdef G_ENABLE_DEBUG
+ g_assert_cmpfloat (slice->area.origin.x, >=, 0);
+ g_assert_cmpfloat (slice->area.origin.x, <=, 1);
+ g_assert_cmpfloat (slice->area.origin.y, >=, 0);
+ g_assert_cmpfloat (slice->area.origin.y, <=, 1);
+ g_assert_cmpfloat (slice->area.origin.x + slice->area.size.width, <=, 1);
+ g_assert_cmpfloat (slice->area.origin.y + slice->area.size.height, <=, 1);
+#endif
+ }
+}
+
+static inline void
+nine_slice_grow (GskGLTextureNineSlice *slices,
+ int amount)
+{
+ /* top left */
+ slices[0].rect.x -= amount;
+ slices[0].rect.y -= amount;
+ if (amount > slices[0].rect.width)
+ slices[0].rect.width += amount * 2;
+ else
+ slices[0].rect.width += amount;
+
+ if (amount > slices[0].rect.height)
+ slices[0].rect.height += amount * 2;
+ else
+ slices[0].rect.height += amount;
+
+
+ /* Top center */
+ slices[1].rect.y -= amount;
+ if (amount > slices[1].rect.height)
+ slices[1].rect.height += amount * 2;
+ else
+ slices[1].rect.height += amount;
+
+ /* top right */
+ slices[2].rect.y -= amount;
+ if (amount > slices[2].rect.width)
+ {
+ slices[2].rect.x -= amount;
+ slices[2].rect.width += amount * 2;
+ }
+ else
+ {
+ slices[2].rect.width += amount;
+ }
+
+ if (amount > slices[2].rect.height)
+ slices[2].rect.height += amount * 2;
+ else
+ slices[2].rect.height += amount;
+
+
+
+ slices[3].rect.x -= amount;
+ if (amount > slices[3].rect.width)
+ slices[3].rect.width += amount * 2;
+ else
+ slices[3].rect.width += amount;
+
+ /* Leave center alone */
+
+ if (amount > slices[5].rect.width)
+ {
+ slices[5].rect.x -= amount;
+ slices[5].rect.width += amount * 2;
+ }
+ else
+ {
+ slices[5].rect.width += amount;
+ }
+
+
+ /* Bottom left */
+ slices[6].rect.x -= amount;
+ if (amount > slices[6].rect.width)
+ {
+ slices[6].rect.width += amount * 2;
+ }
+ else
+ {
+ slices[6].rect.width += amount;
+ }
+
+ if (amount > slices[6].rect.height)
+ {
+ slices[6].rect.y -= amount;
+ slices[6].rect.height += amount * 2;
+ }
+ else
+ {
+ slices[6].rect.height += amount;
+ }
+
+
+ /* Bottom center */
+ if (amount > slices[7].rect.height)
+ {
+ slices[7].rect.y -= amount;
+ slices[7].rect.height += amount * 2;
+ }
+ else
+ {
+ slices[7].rect.height += amount;
+ }
+
+ if (amount > slices[8].rect.width)
+ {
+ slices[8].rect.x -= amount;
+ slices[8].rect.width += amount * 2;
+ }
+ else
+ {
+ slices[8].rect.width += amount;
+ }
+
+ if (amount > slices[8].rect.height)
+ {
+ slices[8].rect.y -= amount;
+ slices[8].rect.height += amount * 2;
+ }
+ else
+ {
+ slices[8].rect.height += amount;
+ }
+
+#ifdef G_ENABLE_DEBUG
+ for (guint i = 0; i < 9; i ++)
+ {
+ g_assert_cmpint (slices[i].rect.x, >=, 0);
+ g_assert_cmpint (slices[i].rect.y, >=, 0);
+ g_assert_cmpint (slices[i].rect.width, >=, 0);
+ g_assert_cmpint (slices[i].rect.height, >=, 0);
+ }
+
+ /* Rows don't overlap */
+ for (guint i = 0; i < 3; i++)
+ g_assert_cmpint (slices[i * 3 + 0].rect.x + slices[i * 3 + 0].rect.width, <, slices[i * 3 + 1].rect.x);
+#endif
+
+}
+
+G_END_DECLS
+
+#endif /* __NINE_SLICE_PRIVATE_H__ */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]