[libshumate] map-layer: Shift row and columns when possible
- From: Corentin Noël <corentinnoel src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libshumate] map-layer: Shift row and columns when possible
- Date: Wed, 10 Mar 2021 07:51:19 +0000 (UTC)
commit 8744b93fa36516e8f6b76b1944c92ca37cfd6aa7
Author: Georges Basile Stavracas Neto <georges stavracas gmail com>
Date: Sun Mar 7 21:14:39 2021 -0300
map-layer: Shift row and columns when possible
Every time the top-left tile changes the row or column it's displaying, *all*
other tiles change too. This incurs all tiles reloading every time the viewport
is moved enough, which flickers and makes up for a bad experience.
Fix that by shifting rows and columns by a certain amount to avoid making all
tiles reload.
shumate/shumate-map-layer.c | 89 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 89 insertions(+)
---
diff --git a/shumate/shumate-map-layer.c b/shumate/shumate-map-layer.c
index 45165c7..ee53807 100644
--- a/shumate/shumate-map-layer.c
+++ b/shumate/shumate-map-layer.c
@@ -92,6 +92,91 @@ shumate_map_layer_get_tile_child (ShumateMapLayer *self,
return NULL;
}
+static inline int
+modadd (int current,
+ int shift,
+ int size)
+{
+ /* This is scary, but the idea behind it is simple: the regular modulo operator
+ * does *not* wrap around when giving it negative numbers. For example, -1 % 8
+ * yields -1 instead of 7.
+ *
+ * The following pair of lines do exactly that, on top of adding a number. This
+ * is so that we can do e.g. (0 + -1) % 8 = 7.
+ */
+ current = current % size;
+ return (size + current + shift) % size;
+}
+
+static void
+maybe_shift_grid (ShumateMapLayer *self,
+ guint n_columns,
+ guint n_rows,
+ int new_first_tile_column,
+ int new_first_tile_row)
+{
+ TileGridPosition *first_tile;
+ int first_tile_column;
+ int first_tile_row;
+ int column_backward_diff;
+ int column_forward_diff;
+ int row_backward_diff;
+ int row_forward_diff;
+ int column_diff;
+ int row_diff;
+
+ first_tile = shumate_map_layer_get_tile_child (self, 0, 0);
+ if (!first_tile)
+ return;
+
+ first_tile_column = shumate_tile_get_x (first_tile->tile);
+ first_tile_row = shumate_tile_get_y (first_tile->tile);
+
+ /* The allocation function uses unsigned ints everywhere, and they do wrap
+ * around, so we can often receive super large values here.
+ */
+ new_first_tile_column = new_first_tile_column % n_columns;
+ new_first_tile_row = new_first_tile_row % n_rows;
+
+ if (new_first_tile_column == first_tile_column && new_first_tile_row == first_tile_row)
+ return;
+
+ /* This too looks more complicated than it is. Because all the calculations
+ * are modular, we check which is closest: moving forward or backward.
+ *
+ * For example, in a 8x8 grid, if the first tile is going from 7x0 to 0x0,
+ * the forward diff is 7x0, and the backward diff is 1x0. We want to pick
+ * the backward diff in this case.
+ */
+ column_backward_diff = (new_first_tile_column - first_tile_column) % n_columns;
+ column_forward_diff = (first_tile_column - new_first_tile_column) % n_columns;
+
+ row_backward_diff = (new_first_tile_row - first_tile_row) % n_rows;
+ row_forward_diff = (first_tile_row - new_first_tile_row) % n_rows;
+
+ column_diff = ABS (column_backward_diff) < ABS (column_forward_diff) ? column_backward_diff :
-column_forward_diff;
+ row_diff = ABS (row_backward_diff) < ABS (row_forward_diff) ? row_backward_diff : -row_forward_diff;
+
+ /* If the diff is bigger than the number of tiles being displayed in any axis,
+ * there's no point shifting them; they all will need to reload.
+ */
+ if (ABS (column_diff) >= self->required_tiles_columns || ABS (row_diff) >= self->required_tiles_rows)
+ return;
+
+ for (gsize i = 0; i < self->tiles_positions->len; i++)
+ {
+ TileGridPosition *tile_child = g_ptr_array_index (self->tiles_positions, i);
+
+ tile_child->left_attach = modadd (tile_child->left_attach,
+ -column_diff,
+ self->required_tiles_columns);
+
+ tile_child->top_attach = modadd (tile_child->top_attach,
+ -row_diff,
+ self->required_tiles_rows);
+ }
+}
+
static void
recompute_grid (ShumateMapLayer *self,
int width,
@@ -394,6 +479,10 @@ shumate_map_layer_size_allocate (GtkWidget *widget,
child_allocation.width = tile_size;
child_allocation.height = tile_size;
+ maybe_shift_grid (self,
+ source_columns, source_rows,
+ tile_initial_column, tile_initial_row);
+
tile_row = tile_initial_row;
for (int row = 0; row < self->required_tiles_rows; row++)
{
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]