From: Timm Bäder Date: Wed, 20 May 2020 06:01:48 +0000 (+0200) Subject: gl renderer: Fix blurred outset shadow slicing X-Git-Tag: archive/raspbian/4.4.1+ds1-2+rpi1^2~18^2~16^2~133 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=1aa86d23f4b25f23f434f8c0f0ec90e6d255da08;p=gtk4.git gl renderer: Fix blurred outset shadow slicing Take 23. Fixes #2759 --- diff --git a/gsk/gl/glutilsprivate.h b/gsk/gl/glutilsprivate.h new file mode 100644 index 0000000000..fb2c67d11b --- /dev/null +++ b/gsk/gl/glutilsprivate.h @@ -0,0 +1,287 @@ + +#pragma once + +#define SANITY_CHECKS 0 + + +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, +}; +#define NINE_SLICE_SIZE 9 /* Hah. */ + +typedef struct +{ + int texture_id; + float x; + float y; + float x2; + float y2; +} TextureRegion; + +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 (const GskRoundedRect *rect, + cairo_rectangle_int_t *out_rects) +{ + const graphene_point_t *origin = &rect->bounds.origin; + const graphene_size_t *size = &rect->bounds.size; + const int top_height = ceilf (MAX (rect->corner[GSK_CORNER_TOP_LEFT].height, + rect->corner[GSK_CORNER_TOP_RIGHT].height)); + const int bottom_height = ceilf (MAX (rect->corner[GSK_CORNER_BOTTOM_LEFT].height, + rect->corner[GSK_CORNER_BOTTOM_RIGHT].height)); + const int right_width = ceilf (MAX (rect->corner[GSK_CORNER_TOP_RIGHT].width, + rect->corner[GSK_CORNER_BOTTOM_RIGHT].width)); + const int left_width = ceilf (MAX (rect->corner[GSK_CORNER_TOP_LEFT].width, + rect->corner[GSK_CORNER_BOTTOM_LEFT].width)); + + /* Top left */ + out_rects[0] = (cairo_rectangle_int_t) { + origin->x, origin->y, + left_width, top_height, + }; + + /* Top center */ + out_rects[1] = (cairo_rectangle_int_t) { + origin->x + size->width / 2.0 - 1, origin->y, + 1, top_height, + }; + + /* Top right */ + out_rects[2] = (cairo_rectangle_int_t) { + origin->x + size->width - right_width, origin->y, + right_width, top_height + }; + + /* Left center */ + out_rects[3] = (cairo_rectangle_int_t) { + origin->x, origin->y + size->height / 2, + left_width, 1, + }; + + /* center */ + out_rects[4] = (cairo_rectangle_int_t) { + origin->x + size->width / 2.0, + origin->y + size->height / 2.0, + 1, 1 + }; + + /* Right center */ + out_rects[5] = (cairo_rectangle_int_t) { + origin->x + size->width - right_width, + origin->y + (size->height / 2.0), + right_width, + 1, + }; + + /* Bottom Left */ + out_rects[6] = (cairo_rectangle_int_t) { + origin->x, origin->y + size->height - bottom_height, + left_width, bottom_height, + }; + + /* Bottom center */ + out_rects[7] = (cairo_rectangle_int_t) { + origin->x + (size->width / 2.0), origin->y + size->height - bottom_height, + 1, bottom_height, + }; + + /* Bottom right */ + out_rects[8] = (cairo_rectangle_int_t) { + origin->x + size->width - right_width, + origin->y + size->height - bottom_height, + right_width, bottom_height, + }; + +#if SANITY_CHECKS + g_assert_cmpfloat (size->width, >=, left_width + right_width); + g_assert_cmpfloat (size->height, >=, top_height + bottom_height); +#endif +} + +static inline void +nine_slice_grow (cairo_rectangle_int_t *slices, + const int amount) +{ + /* top left */ + slices[0].x -= amount; + slices[0].y -= amount; + if (amount > slices[0].width) + slices[0].width += amount * 2; + else + slices[0].width += amount; + + if (amount > slices[0].height) + slices[0].height += amount * 2; + else + slices[0].height += amount; + + + /* Top center */ + slices[1].y -= amount; + if (amount > slices[1].height) + slices[1].height += amount * 2; + else + slices[1].height += amount; + + + /* top right */ + slices[2].y -= amount; + if (amount > slices[2].width) + { + slices[2].x -= amount; + slices[2].width += amount * 2; + } + else + { + slices[2].width += amount; + } + + if (amount > slices[2].height) + slices[2].height += amount * 2; + else + slices[2].height += amount; + + + + slices[3].x -= amount; + if (amount > slices[3].width) + slices[3].width += amount * 2; + else + slices[3].width += amount; + + /* Leave Britney^Wcenter alone */ + + if (amount > slices[5].width) + { + slices[5].x -= amount; + slices[5].width += amount * 2; + } + else + { + slices[5].width += amount; + } + + + /* Bottom left */ + slices[6].x -= amount; + if (amount > slices[6].width) + { + slices[6].width += amount * 2; + } + else + { + slices[6].width += amount; + } + + if (amount > slices[6].height) + { + slices[6].y -= amount; + slices[6].height += amount * 2; + } + else + { + slices[6].height += amount; + } + + + /* Bottom center */ + if (amount > slices[7].height) + { + slices[7].y -= amount; + slices[7].height += amount * 2; + } + else + { + slices[7].height += amount; + } + + if (amount > slices[8].width) + { + slices[8].x -= amount; + slices[8].width += amount * 2; + } + else + { + slices[8].width += amount; + } + + if (amount > slices[8].height) + { + slices[8].y -= amount; + slices[8].height += amount * 2; + } + else + { + slices[8].height += amount; + } + +#if SANITY_CHECKS + { + for (int i = 0; i < 9; i ++) + { + g_assert_cmpint (slices[i].x, >=, 0); + g_assert_cmpint (slices[i].y, >=, 0); + g_assert_cmpint (slices[i].width, >=, 0); + g_assert_cmpint (slices[i].height, >=, 0); + } + + /* Rows don't overlap */ + for (int i = 0; i < 3; i++) + { + g_assert_cmpint (slices[i * 3 + 0].x + slices[i * 3 + 0].width, <, slices[i * 3 + 1].x); + } + } +#endif + +} + +static inline void +nine_slice_to_texture_coords (const cairo_rectangle_int_t *slices, + const int texture_width, + const int texture_height, + TextureRegion *out_regions) +{ + const float fw = (float)texture_width; + const float fh = (float)texture_height; + int i; + + for (i = 0; i < 9; i++) + { + out_regions[i] = (TextureRegion) { + 0, /* Texture id */ + slices[i].x / fw, + 1.0 - ((slices[i].y + slices[i].height) / fh), + (slices[i].x + slices[i].width) / fw, + 1.0 - (slices[i].y / fh), + }; + } + +#if SANITY_CHECKS + { + for (i = 0; i < 9; i++) + { + const TextureRegion *r = &out_regions[i]; + g_assert_cmpfloat (r->x, >=, 0); + g_assert_cmpfloat (r->x, <=, 1); + g_assert_cmpfloat (r->y, >=, 0); + g_assert_cmpfloat (r->y, <=, 1); + + g_assert_cmpfloat (r->x, <, r->x2); + g_assert_cmpfloat (r->y, <, r->y2); + } + } +#endif +} diff --git a/gsk/gl/gskglrenderer.c b/gsk/gl/gskglrenderer.c index 2061a12fec..288a015524 100644 --- a/gsk/gl/gskglrenderer.c +++ b/gsk/gl/gskglrenderer.c @@ -18,6 +18,7 @@ #include "gskglshadowcacheprivate.h" #include "gskglnodesampleprivate.h" #include "gsktransform.h" +#include "glutilsprivate.h" #include "gskprivate.h" @@ -73,15 +74,6 @@ typedef enum NO_CACHE_PLZ = 1 << 5, } OffscreenFlags; -typedef struct -{ - int texture_id; - float x; - float y; - float x2; - float y2; -} TextureRegion; - static inline void init_full_texture_region (TextureRegion *r, int texture_id) @@ -1712,6 +1704,8 @@ render_unblurred_outset_shadow_node (GskGLRenderer *self, load_vertex_data (ops_draw (builder, NULL), node, builder); } + + static GdkRGBA COLOR_WHITE = { 1, 1, 1, 1 }; static inline void render_outset_shadow_node (GskGLRenderer *self, @@ -1727,8 +1721,7 @@ render_outset_shadow_node (GskGLRenderer *self, const float dx = gsk_outset_shadow_node_get_dx (node); const float dy = gsk_outset_shadow_node_get_dy (node); GskRoundedRect scaled_outline; - GskRoundedRect unscaled_outline; - float texture_width, texture_height; + int texture_width, texture_height; OpShadow *shadow; int blurred_texture_id; int cached_tid; @@ -1740,15 +1733,14 @@ render_outset_shadow_node (GskGLRenderer *self, gsk_rounded_rect_shrink_to_minimum (&scaled_outline); /* Increase by the spread */ gsk_rounded_rect_shrink (&scaled_outline, -spread, -spread, -spread, -spread); + /* Grow bounds but don't grow corners */ + graphene_rect_inset (&scaled_outline.bounds, - blur_extra / 2.0 * scale, - blur_extra / 2.0 * scale); /* For the center part, we add a few pixels */ scaled_outline.bounds.size.width += SHADOW_EXTRA_SIZE; scaled_outline.bounds.size.height += SHADOW_EXTRA_SIZE; - texture_width = ceil ((scaled_outline.bounds.size.width + (blur_extra)) * scale); - texture_height = ceil ((scaled_outline.bounds.size.height + (blur_extra)) * scale); - - /* Preserve this for usage later */ - unscaled_outline = scaled_outline; + texture_width = (int)ceil ((scaled_outline.bounds.size.width + blur_extra) * scale); + texture_height = (int)ceil ((scaled_outline.bounds.size.height + blur_extra) * scale); scaled_outline.bounds.origin.x = blur_extra / 2.0 * scale; scaled_outline.bounds.origin.y = blur_extra / 2.0 * scale; @@ -1782,6 +1774,7 @@ render_outset_shadow_node (GskGLRenderer *self, gdk_gl_context_label_object_printf (self->gl_context, GL_FRAMEBUFFER, render_target, "Outset Shadow FB Temp %d", render_target); + ops_set_program (builder, &self->programs->color_program); graphene_matrix_init_ortho (&item_proj, 0, texture_width, 0, texture_height, ORTHO_NEAR_PLANE, ORTHO_FAR_PLANE); @@ -1794,7 +1787,6 @@ render_outset_shadow_node (GskGLRenderer *self, prev_viewport = ops_set_viewport (builder, &GRAPHENE_RECT_INIT (0, 0, texture_width, texture_height)); /* Draw outline */ - ops_set_program (builder, &self->programs->color_program); ops_push_clip (builder, &scaled_outline); ops_set_color (builder, &COLOR_WHITE); ops_draw (builder, (GskQuadVertex[GL_N_VERTICES]) { @@ -1843,42 +1835,30 @@ render_outset_shadow_node (GskGLRenderer *self, const float min_y = builder->dy + outline->bounds.origin.y - spread - (blur_extra / 2.0) + dy; const float max_x = min_x + outline->bounds.size.width + (spread + (blur_extra / 2.0)) * 2; const float max_y = min_y + outline->bounds.size.height + (spread + (blur_extra / 2.0)) * 2; - const float left_width = MAX (MAX (unscaled_outline.corner[GSK_CORNER_TOP_LEFT].width, - unscaled_outline.corner[GSK_CORNER_BOTTOM_LEFT].width), - blur_extra / 2.0); - const float top_height = MAX (MAX (unscaled_outline.corner[GSK_CORNER_TOP_LEFT].height, - unscaled_outline.corner[GSK_CORNER_TOP_RIGHT].height), - blur_extra / 2.0); - const float right_width = MAX (MAX (unscaled_outline.corner[GSK_CORNER_TOP_RIGHT].width, - unscaled_outline.corner[GSK_CORNER_BOTTOM_RIGHT].width), - blur_extra / 2.0); - const float bottom_height = MAX (MAX (unscaled_outline.corner[GSK_CORNER_BOTTOM_LEFT].height, - unscaled_outline.corner[GSK_CORNER_BOTTOM_RIGHT].height), - blur_extra / 2.0); - const float center_width = (max_x - min_x) - left_width - right_width; - const float center_height = (max_y - min_y) - top_height - bottom_height; float x1, x2, y1, y2, tx1, tx2, ty1, ty2; + cairo_rectangle_int_t slices[9]; + TextureRegion tregs[9]; + + /* TODO: The slicing never changes and could just go into the cache */ + nine_slice_rounded_rect (&scaled_outline, slices); + nine_slice_grow (slices, blur_extra / 2.0 * scale); + nine_slice_to_texture_coords (slices, texture_width, texture_height, tregs); /* Our texture coordinates MUST be scaled, while the actual vertex coords * MUST NOT be scaled. */ /* Top left */ - if (top_height > 0 && left_width > 0) + if (slice_is_visible (&slices[NINE_SLICE_TOP_LEFT])) { x1 = min_x; - x2 = min_x + left_width; + x2 = min_x + (slices[NINE_SLICE_TOP_LEFT].width / scale); y1 = min_y; - y2 = min_y + top_height; + y2 = min_y + (slices[NINE_SLICE_TOP_LEFT].height / scale); - tx1 = 0; - tx2 = (left_width * scale) / texture_width; - ty1 = 1 - (top_height * scale / texture_height); - ty2 = 1; - - g_assert_cmpfloat (x1, <=, x2); - g_assert_cmpfloat (y1, <=, y2); - g_assert_cmpfloat (tx1, <=, tx2); - g_assert_cmpfloat (ty1, <=, ty2); + tx1 = tregs[NINE_SLICE_TOP_LEFT].x; + tx2 = tregs[NINE_SLICE_TOP_LEFT].x2; + ty1 = tregs[NINE_SLICE_TOP_LEFT].y; + ty2 = tregs[NINE_SLICE_TOP_LEFT].y2; ops_draw (builder, (GskQuadVertex[GL_N_VERTICES]) { { { x1, y1 }, { tx1, ty2 }, }, @@ -1891,23 +1871,18 @@ render_outset_shadow_node (GskGLRenderer *self, }); } - /* Top side */ - if (top_height > 0 && center_width > 0) + /* Top center */ + if (slice_is_visible (&slices[NINE_SLICE_TOP_CENTER])) { - x1 = min_x + left_width; - x2 = x1 + center_width; + x1 = min_x + (slices[NINE_SLICE_TOP_LEFT].width / scale); + x2 = max_x - (slices[NINE_SLICE_TOP_RIGHT].width / scale); y1 = min_y; - y2 = min_y + top_height; - - tx1 = left_width * scale / texture_width; - tx2 = 1.0 - (right_width * scale / texture_width); - ty1 = 1 - (top_height * scale / texture_height); - ty2 = 1; + y2 = min_y + (slices[NINE_SLICE_TOP_CENTER].height / scale); - g_assert_cmpfloat (x1, <=, x2); - g_assert_cmpfloat (y1, <=, y2); - g_assert_cmpfloat (tx1, <=, tx2); - g_assert_cmpfloat (ty1, <=, ty2); + tx1 = tregs[NINE_SLICE_TOP_CENTER].x; + tx2 = tregs[NINE_SLICE_TOP_CENTER].x2; + ty1 = tregs[NINE_SLICE_TOP_CENTER].y; + ty2 = tregs[NINE_SLICE_TOP_CENTER].y2; ops_draw (builder, (GskQuadVertex[GL_N_VERTICES]) { { { x1, y1 }, { tx1, ty2 }, }, @@ -1921,20 +1896,23 @@ render_outset_shadow_node (GskGLRenderer *self, } /* Top right */ - if (top_height > 0 && right_width > 0) - { - x1 = max_x - right_width; - x2 = max_x; - y1 = min_y; - y2 = min_y + top_height; - tx1 = 1 - (right_width * scale / texture_width); - tx2 = 1; - ty1 = 1 - (top_height * scale / texture_height); - ty2 = 1; - ops_draw (builder, (GskQuadVertex[GL_N_VERTICES]) { - { { x1, y1 }, { tx1, ty2 }, }, - { { x1, y2 }, { tx1, ty1 }, }, - { { x2, y1 }, { tx2, ty2 }, }, + if (slice_is_visible (&slices[NINE_SLICE_TOP_RIGHT])) + { + x1 = max_x - (slices[NINE_SLICE_TOP_RIGHT].width / scale); + x2 = max_x; + y1 = min_y; + y2 = min_y + (slices[NINE_SLICE_TOP_RIGHT].height / scale); + + tx1 = tregs[NINE_SLICE_TOP_RIGHT].x; + tx2 = tregs[NINE_SLICE_TOP_RIGHT].x2; + + ty1 = tregs[NINE_SLICE_TOP_RIGHT].y; + ty2 = tregs[NINE_SLICE_TOP_RIGHT].y2; + + ops_draw (builder, (GskQuadVertex[GL_N_VERTICES]) { + { { x1, y1 }, { tx1, ty2 }, }, + { { x1, y2 }, { tx1, ty1 }, }, + { { x2, y1 }, { tx2, ty2 }, }, { { x2, y2 }, { tx2, ty1 }, }, { { x1, y2 }, { tx1, ty1 }, }, @@ -1943,16 +1921,17 @@ render_outset_shadow_node (GskGLRenderer *self, } /* Bottom right */ - if (bottom_height > 0 && left_width > 0) + if (slice_is_visible (&slices[NINE_SLICE_BOTTOM_RIGHT])) { - x1 = max_x - right_width; + x1 = max_x - (slices[NINE_SLICE_BOTTOM_RIGHT].width / scale); x2 = max_x; - y1 = max_y - bottom_height; + y1 = max_y - (slices[NINE_SLICE_BOTTOM_RIGHT].height / scale); y2 = max_y; - tx1 = 1 - (right_width * scale / texture_width); - tx2 = 1; - ty1 = 0; - ty2 = (bottom_height * scale / texture_height); + tx1 = tregs[NINE_SLICE_BOTTOM_RIGHT].x; + tx2 = tregs[NINE_SLICE_BOTTOM_RIGHT].x2; + ty1 = tregs[NINE_SLICE_BOTTOM_RIGHT].y; + ty2 = tregs[NINE_SLICE_BOTTOM_RIGHT].y2; + ops_draw (builder, (GskQuadVertex[GL_N_VERTICES]) { { { x1, y1 }, { tx1, ty2 }, }, { { x1, y2 }, { tx1, ty1 }, }, @@ -1965,16 +1944,18 @@ render_outset_shadow_node (GskGLRenderer *self, } /* Bottom left */ - if (bottom_height > 0 && left_width > 0) + if (slice_is_visible (&slices[NINE_SLICE_BOTTOM_LEFT])) { x1 = min_x; - x2 = min_x + left_width; - y1 = max_y - bottom_height; + x2 = min_x + (slices[NINE_SLICE_BOTTOM_LEFT].width / scale); + y1 = max_y - (slices[NINE_SLICE_BOTTOM_LEFT].height / scale); y2 = max_y; - tx1 = 0; - tx2 = left_width * scale / texture_width; - ty1 = 0; - ty2 = bottom_height * scale / texture_height; + + tx1 = tregs[NINE_SLICE_BOTTOM_LEFT].x; + tx2 = tregs[NINE_SLICE_BOTTOM_LEFT].x2; + ty1 = tregs[NINE_SLICE_BOTTOM_LEFT].y; + ty2 = tregs[NINE_SLICE_BOTTOM_LEFT].y2; + ops_draw (builder, (GskQuadVertex[GL_N_VERTICES]) { { { x1, y1 }, { tx1, ty2 }, }, { { x1, y2 }, { tx1, ty1 }, }, @@ -1987,21 +1968,16 @@ render_outset_shadow_node (GskGLRenderer *self, } /* Left side */ - if (left_width > 0) + if (slice_is_visible (&slices[NINE_SLICE_LEFT_CENTER])) { x1 = min_x; - x2 = min_x + left_width; - y1 = min_y + top_height; - y2 = y1 + center_height; - tx1 = 0; - tx2 = left_width * scale / texture_width; - ty1 = top_height * scale / texture_height; - ty2 = 1.0 - (bottom_height * scale / texture_height); - - g_assert_cmpfloat (x1, <=, x2); - g_assert_cmpfloat (y1, <=, y2); - g_assert_cmpfloat (tx1, <=, tx2); - g_assert_cmpfloat (ty1, <=, ty2); + x2 = min_x + (slices[NINE_SLICE_LEFT_CENTER].width / scale); + y1 = min_y + (slices[NINE_SLICE_TOP_LEFT].height / scale); + y2 = max_y - (slices[NINE_SLICE_BOTTOM_LEFT].height / scale); + tx1 = tregs[NINE_SLICE_LEFT_CENTER].x; + tx2 = tregs[NINE_SLICE_LEFT_CENTER].x2; + ty1 = tregs[NINE_SLICE_LEFT_CENTER].y; + ty2 = tregs[NINE_SLICE_LEFT_CENTER].y2; ops_draw (builder, (GskQuadVertex[GL_N_VERTICES]) { { { x1, y1 }, { tx1, ty2 }, }, @@ -2015,16 +1991,19 @@ render_outset_shadow_node (GskGLRenderer *self, } /* Right side */ - if (right_width > 0) + if (slice_is_visible (&slices[NINE_SLICE_RIGHT_CENTER])) { - x1 = max_x - right_width; + x1 = max_x - (slices[NINE_SLICE_RIGHT_CENTER].width / scale); x2 = max_x; - y1 = min_y + top_height; - y2 = y1 + center_height; - tx1 = 1 - (right_width * scale / texture_width); - tx2 = 1; - ty1 = top_height * scale / texture_height; - ty2 = 1.0 - (bottom_height * scale / texture_height); + y1 = min_y + (slices[NINE_SLICE_TOP_RIGHT].height / scale); + y2 = max_y - (slices[NINE_SLICE_BOTTOM_RIGHT].height / scale); + + tx1 = tregs[NINE_SLICE_RIGHT_CENTER].x; + tx2 = tregs[NINE_SLICE_RIGHT_CENTER].x2; + + ty1 = tregs[NINE_SLICE_RIGHT_CENTER].y; + ty2 = tregs[NINE_SLICE_RIGHT_CENTER].y2; + ops_draw (builder, (GskQuadVertex[GL_N_VERTICES]) { { { x1, y1 }, { tx1, ty2 }, }, { { x1, y2 }, { tx1, ty1 }, }, @@ -2037,16 +2016,20 @@ render_outset_shadow_node (GskGLRenderer *self, } /* Bottom side */ - if (bottom_height > 0) + if (slice_is_visible (&slices[NINE_SLICE_BOTTOM_CENTER])) { - x1 = min_x + left_width; - x2 = max_x - right_width; - y1 = max_y - bottom_height; + x1 = min_x + (slices[NINE_SLICE_BOTTOM_LEFT].width / scale); + x2 = max_x - (slices[NINE_SLICE_BOTTOM_RIGHT].width / scale); + y1 = max_y - (slices[NINE_SLICE_BOTTOM_CENTER].height / scale); y2 = max_y; - tx1 = left_width * scale / texture_width; - tx2 = 1.0 - (right_width * scale / texture_width); - ty1 = 0; - ty2 = bottom_height * scale / texture_height; + + tx1 = tregs[NINE_SLICE_BOTTOM_CENTER].x; + tx2 = tregs[NINE_SLICE_BOTTOM_CENTER].x2; + + ty1 = tregs[NINE_SLICE_BOTTOM_CENTER].y; + ty2 = tregs[NINE_SLICE_BOTTOM_CENTER].y2; + + ops_draw (builder, (GskQuadVertex[GL_N_VERTICES]) { { { x1, y1 }, { tx1, ty2 }, }, { { x1, y2 }, { tx1, ty1 }, }, @@ -2059,16 +2042,19 @@ render_outset_shadow_node (GskGLRenderer *self, } /* Middle */ - if (center_width > 0 && center_height > 0) + if (slice_is_visible (&slices[NINE_SLICE_CENTER])) { - x1 = min_x + left_width; - x2 = max_x - right_width; - y1 = min_y + top_height; - y2 = max_y - bottom_height; - tx1 = left_width * scale / texture_width; - tx2 = 1.0 - (right_width * scale / texture_width); - ty1 = top_height * scale / texture_height; - ty2 = 1.0 - (bottom_height * scale / texture_height); + x1 = min_x + (slices[NINE_SLICE_LEFT_CENTER].width / scale); + x2 = max_x - (slices[NINE_SLICE_RIGHT_CENTER].width / scale); + y1 = min_y + (slices[NINE_SLICE_TOP_CENTER].height / scale); + y2 = max_y - (slices[NINE_SLICE_BOTTOM_CENTER].height / scale); + + tx1 = tregs[NINE_SLICE_CENTER].x; + tx2 = tregs[NINE_SLICE_CENTER].x2; + + ty1 = tregs[NINE_SLICE_CENTER].y; + ty2 = tregs[NINE_SLICE_CENTER].y2; + ops_draw (builder, (GskQuadVertex[GL_N_VERTICES]) { { { x1, y1 }, { tx1, ty2 }, }, { { x1, y2 }, { tx1, ty1 }, },