# HG changeset patch # User Paul Boddie # Date 1541005327 -3600 # Node ID d3de41d851b917e4c96b12f7307bb9976f4d33ad # Parent b54c63959b330d836d024aa6005e7993f398385b Added scrolling support, making display operations relative to the start address and not the framebuffer address. Extended the display copying function to be able to access regions of a source image. This is useful when updating the display after a scroll event has occurred. diff -r b54c63959b33 -r d3de41d851b9 examples/vga/main.c --- a/examples/vga/main.c Tue Oct 30 23:59:47 2018 +0100 +++ b/examples/vga/main.c Wed Oct 31 18:02:07 2018 +0100 @@ -113,23 +113,75 @@ { uint8_t background[sprite_width * sprite_height]; int x, y; + int dir[] = {1, 0, -1, 0, 1}, i = 0, width, column_width; + int xsource, xdisplay, xorigin = 0; while (1) + { for (y = 0; y < screendata_height - sprite_height; y++) + { for (x = 0; x < screendata_width - sprite_width; x++) { /* Copy to the store from the display, then blit the image. */ - copy_display(&display_config, background, sprite_width, sprite_height, x, y, -1, 0); - copy_display(&display_config, sprite, sprite_width, sprite_height, x, y, 0x8c, 1); + copy_display(&display_config, background, + sprite_width, sprite_height, + x, y, -1, 0); + copy_display(&display_config, sprite, + sprite_width, sprite_height, + x, y, 0x8c, 1); wait(delay); /* Copy to the display from the store, restoring the original background. */ - copy_display(&display_config, background, sprite_width, sprite_height, x, y, -1, 1); + copy_display(&display_config, background, + sprite_width, sprite_height, + x, y, -1, 1); + + /* Scroll in the indicated direction. */ + + scroll_display(&display_config, dir[i], dir[i + 1]); + + /* For horizontal scrolling, plot the exposed column at the left + (if scrolling left) or at the right (if scrolling right). */ + + if (dir[i]) + { + /* Due to the effect of a simple screen start increment in + the dual channel configuration, horizontal scrolling + involves two pixel increments and thus requires a two- + pixel column to be plotted. */ + + width = dir[i] * LINE_CHANNELS; + column_width = width < 0 ? -width : width; + + /* Plot either at the left or right edge. */ + + xdisplay = width < 0 ? 0 : screendata_width - width; + + /* Determine the location of the column to be plotted. */ + + xorigin += width; + xsource = (xdisplay + xorigin) % screendata_width; + + copy_display_section(&display_config, screendata, + screendata_width, screendata_height, + xsource, 0, + column_width, screendata_height, + xdisplay, 0, + -1, 1); + } } + + /* Switch direction periodically. */ + + i++; + if (i == 4) + i = 0; + } + } } /* Fill the screen with characters. */ @@ -203,7 +255,8 @@ /* Plot the image centred on the screen. */ copy_display(&display_config, screendata, screendata_width, screendata_height, - (LINE_LENGTH - screendata_width) / 2, (LINE_COUNT - screendata_height) / 2, -1, 1); + (LINE_LENGTH - screendata_width) / 2, + (LINE_COUNT - screendata_height) / 2, -1, 1); /* Write a sequence of characters. */ @@ -211,7 +264,7 @@ /* Move a sprite around on the screen with a delay between each movement. */ - animate(1 << 24); + animate(1 << 21); } diff -r b54c63959b33 -r d3de41d851b9 include/display.h --- a/include/display.h Tue Oct 30 23:59:47 2018 +0100 +++ b/include/display.h Wed Oct 31 18:02:07 2018 +0100 @@ -71,4 +71,11 @@ void copy_display(display_config_t *cfg, uint8_t *store, int width, int height, int x, int y, int key, int to_display); +void copy_display_section(display_config_t *cfg, uint8_t *store, + int width, int height, + int xstart, int ystart, int xsize, int ysize, + int x, int y, int key, int to_display); + +void scroll_display(display_config_t *cfg, int x, int y); + #endif /* __DISPLAY_H__ */ diff -r b54c63959b33 -r d3de41d851b9 lib/display.c --- a/lib/display.c Tue Oct 30 23:59:47 2018 +0100 +++ b/lib/display.c Wed Oct 31 18:02:07 2018 +0100 @@ -36,7 +36,7 @@ void test_linedata(display_config_t *cfg) { int x, y; - uint8_t *linedata = cfg->framebuffer; + uint8_t *linedata = cfg->screen_start; for (y = 0; y < cfg->line_count; y++) { @@ -52,6 +52,9 @@ } linedata += cfg->line_length; + + if (linedata >= cfg->screen_limit) + linedata -= cfg->screen_size; } } @@ -60,14 +63,40 @@ void copy_display(display_config_t *cfg, uint8_t *store, int width, int height, int x, int y, int key, int to_display) { + copy_display_section(cfg, store, width, height, 0, 0, width, height, x, y, + key, to_display); +} + +/* Copying from/to the display to/from a backing store region. */ + +void copy_display_section(display_config_t *cfg, uint8_t *store, + int width, int height, + int xstart, int ystart, int xsize, int ysize, + int x, int y, int key, int to_display) +{ int sx, sy, dx, dy; - uint8_t *storeline = store, - *displayline = cfg->framebuffer + y * cfg->line_length, + uint8_t *storeline = store + ystart * width, + *displayline = cfg->screen_start + y * cfg->line_length, pixel; - for (sy = 0, dy = y; (sy < height) && (dy < cfg->line_count); sy++, dy++) + /* Define the limits of the copying in the store. */ + + int xlimit = xstart + xsize, ylimit = ystart + ysize; + + if (xlimit > width) + xlimit = width; + + if (ylimit > height) + ylimit = height; + + /* Perform the copying between the store and display. */ + + for (sy = ystart, dy = y; (sy < ylimit) && (dy < cfg->line_count); sy++, dy++) { - for (sx = 0, dx = x; (sx < width) && (dx < cfg->line_length); sx++, dx++) + if (displayline >= cfg->screen_limit) + displayline -= cfg->screen_size; + + for (sx = xstart, dx = x; (sx < xlimit) && (dx < cfg->line_length); sx++, dx++) { if (to_display) { @@ -83,3 +112,26 @@ displayline += cfg->line_length; } } + +/* Scroll the display. */ + +void scroll_display(display_config_t *cfg, int x, int y) +{ + uint8_t *start; + + /* Move the screen start by the given number of bytes and lines. */ + + start = cfg->screen_start + x + y * cfg->line_length; + + /* Wrap around the start of the framebuffer to the end. */ + + if (start < cfg->framebuffer) + start = cfg->screen_limit - (cfg->screen_limit - start) % cfg->screen_size; + + /* Wrap around the end of the framebuffer to the start. */ + + else if (start >= cfg->screen_limit) + start = cfg->framebuffer + (start - cfg->framebuffer) % cfg->screen_size; + + cfg->screen_start = start; +}