1.1 --- a/lib/display.c Tue Nov 13 22:33:09 2018 +0100
1.2 +++ b/lib/display.c Wed Nov 14 13:55:15 2018 +0100
1.3 @@ -215,6 +215,14 @@
1.4 }
1.5 }
1.6
1.7 +/* Convenience function for copying. */
1.8 +
1.9 +static void copy_data(uint8_t *dest, const uint8_t *src, int count)
1.10 +{
1.11 + while (count--)
1.12 + *dest = *src;
1.13 +}
1.14 +
1.15 /* Scroll the display. */
1.16
1.17 void display_scroll(display_config_t *cfg, int x, int y)
1.18 @@ -222,8 +230,50 @@
1.19 /* Move the screen start by the given number of bytes and lines, wrapping
1.20 around the start and end of the framebuffer. */
1.21
1.22 - cfg->screen_start = display_wrap_pointer(cfg, cfg->screen_start + x +
1.23 - y * cfg->line_length);
1.24 + uint8_t *screen_start = cfg->screen_start + x + y * cfg->line_length;
1.25 + uint32_t offset;
1.26 +
1.27 + /* Test for the start pointer needing to be wrapped. Where wrapping around
1.28 + the screen limits occurs, the data for the line referenced by the start
1.29 + pointer needs copying to its new location. This is because a spare line
1.30 + is used (due to line data needing to be contiguous), and upon wrapping
1.31 + around, the newly-referenced line will not contain relevant data.
1.32 +
1.33 + Such copying may be unnecessary if an entire pixel line is scrolled onto
1.34 + the display. */
1.35 +
1.36 + if (screen_start < cfg->frame_start)
1.37 + {
1.38 + /* Get the extent to which the screen start (and the start of the first
1.39 + display line) is off the start of the frame. */
1.40 +
1.41 + offset = cfg->frame_start - screen_start;
1.42 + screen_start = display_wrap_pointer(cfg, screen_start);
1.43 +
1.44 + /* The end of the first display line needs copying, with any data from
1.45 + the frame start being transferred to the relocated line. */
1.46 +
1.47 + if (offset < cfg->line_length)
1.48 + copy_data(screen_start + offset, cfg->frame_start,
1.49 + cfg->line_length - offset);
1.50 + }
1.51 + else if (screen_start >= cfg->screen_limit)
1.52 + {
1.53 + /* Get the extent to which the screen start (and the start of the first
1.54 + display line) is off the end of the frame. */
1.55 +
1.56 + offset = screen_start - cfg->screen_limit;
1.57 + screen_start = display_wrap_pointer(cfg, screen_start);
1.58 +
1.59 + /* The start of the first display line needs copying, with any data
1.60 + before the frame end being transferred to the relocated line. */
1.61 +
1.62 + if (offset < cfg->line_length)
1.63 + copy_data(screen_start, cfg->screen_limit + offset,
1.64 + cfg->line_length - offset);
1.65 + }
1.66 +
1.67 + cfg->screen_start = screen_start;
1.68 }
1.69
1.70 /* Provide a pattern to test the line data. */