1.1 --- a/examples/vga/main.c Tue Oct 30 23:59:47 2018 +0100
1.2 +++ b/examples/vga/main.c Wed Oct 31 18:02:07 2018 +0100
1.3 @@ -113,23 +113,75 @@
1.4 {
1.5 uint8_t background[sprite_width * sprite_height];
1.6 int x, y;
1.7 + int dir[] = {1, 0, -1, 0, 1}, i = 0, width, column_width;
1.8 + int xsource, xdisplay, xorigin = 0;
1.9
1.10 while (1)
1.11 + {
1.12 for (y = 0; y < screendata_height - sprite_height; y++)
1.13 + {
1.14 for (x = 0; x < screendata_width - sprite_width; x++)
1.15 {
1.16 /* Copy to the store from the display, then blit the image. */
1.17
1.18 - copy_display(&display_config, background, sprite_width, sprite_height, x, y, -1, 0);
1.19 - copy_display(&display_config, sprite, sprite_width, sprite_height, x, y, 0x8c, 1);
1.20 + copy_display(&display_config, background,
1.21 + sprite_width, sprite_height,
1.22 + x, y, -1, 0);
1.23 + copy_display(&display_config, sprite,
1.24 + sprite_width, sprite_height,
1.25 + x, y, 0x8c, 1);
1.26
1.27 wait(delay);
1.28
1.29 /* Copy to the display from the store, restoring the original
1.30 background. */
1.31
1.32 - copy_display(&display_config, background, sprite_width, sprite_height, x, y, -1, 1);
1.33 + copy_display(&display_config, background,
1.34 + sprite_width, sprite_height,
1.35 + x, y, -1, 1);
1.36 +
1.37 + /* Scroll in the indicated direction. */
1.38 +
1.39 + scroll_display(&display_config, dir[i], dir[i + 1]);
1.40 +
1.41 + /* For horizontal scrolling, plot the exposed column at the left
1.42 + (if scrolling left) or at the right (if scrolling right). */
1.43 +
1.44 + if (dir[i])
1.45 + {
1.46 + /* Due to the effect of a simple screen start increment in
1.47 + the dual channel configuration, horizontal scrolling
1.48 + involves two pixel increments and thus requires a two-
1.49 + pixel column to be plotted. */
1.50 +
1.51 + width = dir[i] * LINE_CHANNELS;
1.52 + column_width = width < 0 ? -width : width;
1.53 +
1.54 + /* Plot either at the left or right edge. */
1.55 +
1.56 + xdisplay = width < 0 ? 0 : screendata_width - width;
1.57 +
1.58 + /* Determine the location of the column to be plotted. */
1.59 +
1.60 + xorigin += width;
1.61 + xsource = (xdisplay + xorigin) % screendata_width;
1.62 +
1.63 + copy_display_section(&display_config, screendata,
1.64 + screendata_width, screendata_height,
1.65 + xsource, 0,
1.66 + column_width, screendata_height,
1.67 + xdisplay, 0,
1.68 + -1, 1);
1.69 + }
1.70 }
1.71 +
1.72 + /* Switch direction periodically. */
1.73 +
1.74 + i++;
1.75 + if (i == 4)
1.76 + i = 0;
1.77 + }
1.78 + }
1.79 }
1.80
1.81 /* Fill the screen with characters. */
1.82 @@ -203,7 +255,8 @@
1.83 /* Plot the image centred on the screen. */
1.84
1.85 copy_display(&display_config, screendata, screendata_width, screendata_height,
1.86 - (LINE_LENGTH - screendata_width) / 2, (LINE_COUNT - screendata_height) / 2, -1, 1);
1.87 + (LINE_LENGTH - screendata_width) / 2,
1.88 + (LINE_COUNT - screendata_height) / 2, -1, 1);
1.89
1.90 /* Write a sequence of characters. */
1.91
1.92 @@ -211,7 +264,7 @@
1.93
1.94 /* Move a sprite around on the screen with a delay between each movement. */
1.95
1.96 - animate(1 << 24);
1.97 + animate(1 << 21);
1.98 }
1.99
1.100
2.1 --- a/include/display.h Tue Oct 30 23:59:47 2018 +0100
2.2 +++ b/include/display.h Wed Oct 31 18:02:07 2018 +0100
2.3 @@ -71,4 +71,11 @@
2.4 void copy_display(display_config_t *cfg, uint8_t *store, int width, int height,
2.5 int x, int y, int key, int to_display);
2.6
2.7 +void copy_display_section(display_config_t *cfg, uint8_t *store,
2.8 + int width, int height,
2.9 + int xstart, int ystart, int xsize, int ysize,
2.10 + int x, int y, int key, int to_display);
2.11 +
2.12 +void scroll_display(display_config_t *cfg, int x, int y);
2.13 +
2.14 #endif /* __DISPLAY_H__ */
3.1 --- a/lib/display.c Tue Oct 30 23:59:47 2018 +0100
3.2 +++ b/lib/display.c Wed Oct 31 18:02:07 2018 +0100
3.3 @@ -36,7 +36,7 @@
3.4 void test_linedata(display_config_t *cfg)
3.5 {
3.6 int x, y;
3.7 - uint8_t *linedata = cfg->framebuffer;
3.8 + uint8_t *linedata = cfg->screen_start;
3.9
3.10 for (y = 0; y < cfg->line_count; y++)
3.11 {
3.12 @@ -52,6 +52,9 @@
3.13 }
3.14
3.15 linedata += cfg->line_length;
3.16 +
3.17 + if (linedata >= cfg->screen_limit)
3.18 + linedata -= cfg->screen_size;
3.19 }
3.20 }
3.21
3.22 @@ -60,14 +63,40 @@
3.23 void copy_display(display_config_t *cfg, uint8_t *store, int width, int height,
3.24 int x, int y, int key, int to_display)
3.25 {
3.26 + copy_display_section(cfg, store, width, height, 0, 0, width, height, x, y,
3.27 + key, to_display);
3.28 +}
3.29 +
3.30 +/* Copying from/to the display to/from a backing store region. */
3.31 +
3.32 +void copy_display_section(display_config_t *cfg, uint8_t *store,
3.33 + int width, int height,
3.34 + int xstart, int ystart, int xsize, int ysize,
3.35 + int x, int y, int key, int to_display)
3.36 +{
3.37 int sx, sy, dx, dy;
3.38 - uint8_t *storeline = store,
3.39 - *displayline = cfg->framebuffer + y * cfg->line_length,
3.40 + uint8_t *storeline = store + ystart * width,
3.41 + *displayline = cfg->screen_start + y * cfg->line_length,
3.42 pixel;
3.43
3.44 - for (sy = 0, dy = y; (sy < height) && (dy < cfg->line_count); sy++, dy++)
3.45 + /* Define the limits of the copying in the store. */
3.46 +
3.47 + int xlimit = xstart + xsize, ylimit = ystart + ysize;
3.48 +
3.49 + if (xlimit > width)
3.50 + xlimit = width;
3.51 +
3.52 + if (ylimit > height)
3.53 + ylimit = height;
3.54 +
3.55 + /* Perform the copying between the store and display. */
3.56 +
3.57 + for (sy = ystart, dy = y; (sy < ylimit) && (dy < cfg->line_count); sy++, dy++)
3.58 {
3.59 - for (sx = 0, dx = x; (sx < width) && (dx < cfg->line_length); sx++, dx++)
3.60 + if (displayline >= cfg->screen_limit)
3.61 + displayline -= cfg->screen_size;
3.62 +
3.63 + for (sx = xstart, dx = x; (sx < xlimit) && (dx < cfg->line_length); sx++, dx++)
3.64 {
3.65 if (to_display)
3.66 {
3.67 @@ -83,3 +112,26 @@
3.68 displayline += cfg->line_length;
3.69 }
3.70 }
3.71 +
3.72 +/* Scroll the display. */
3.73 +
3.74 +void scroll_display(display_config_t *cfg, int x, int y)
3.75 +{
3.76 + uint8_t *start;
3.77 +
3.78 + /* Move the screen start by the given number of bytes and lines. */
3.79 +
3.80 + start = cfg->screen_start + x + y * cfg->line_length;
3.81 +
3.82 + /* Wrap around the start of the framebuffer to the end. */
3.83 +
3.84 + if (start < cfg->framebuffer)
3.85 + start = cfg->screen_limit - (cfg->screen_limit - start) % cfg->screen_size;
3.86 +
3.87 + /* Wrap around the end of the framebuffer to the start. */
3.88 +
3.89 + else if (start >= cfg->screen_limit)
3.90 + start = cfg->framebuffer + (start - cfg->framebuffer) % cfg->screen_size;
3.91 +
3.92 + cfg->screen_start = start;
3.93 +}