# HG changeset patch # User Paul Boddie # Date 1541956524 -3600 # Node ID 14bc79b7e4dc9af5c34459412116a0340bd9302c # Parent 301fb9b9ed234e8e4e4390a2640f598c16491dd5 Added a function for tiling sprites across a region, using it in the scrolling update function and when setting up the screen. diff -r 301fb9b9ed23 -r 14bc79b7e4dc examples/vga/main.c --- a/examples/vga/main.c Sat Nov 10 23:38:09 2018 +0100 +++ b/examples/vga/main.c Sun Nov 11 18:15:24 2018 +0100 @@ -105,69 +105,63 @@ /* Plot the revealed region at the edge of the screen after scrolling. */ -static void plot_screen_edge(viewport_t *v, int xorigin, int yorigin, - int xstep, int ystep) +static void plot_screen_edge(int xorigin, int yorigin, int xstep, int ystep) { - /* Determine positions within the image. */ + /* The display regions are either the left or right edge... */ + + int xedge = xstep < 0 ? 0 : display_config.line_length - xstep; + int xdisplay = xedge; + + /* and either the top or bottom edge... */ + + int yedge = ystep < 0 ? 0 : display_config.line_count * scr.yscale - ystep; + int ydisplay = yedge / scr.yscale; + + /* Determine the origin position within the image. */ int xpos = wrap_value(xorigin, scr.image->width); int ypos = wrap_value(yorigin, scr.image->height); - - /* The display region is either the left or right edge. */ + int xsource, ysource; - int xdisplay = xstep < 0 ? 0 : scr.image->width - xstep; - - /* The source region depends on the origin within the background image. */ - - int xsource = wrap_value(xdisplay + xpos, scr.image->width); + /* Horizontal scrolling requires columns spanning the height of the screen + at the appropriate edge (left or right). */ /* The column width is the absolute increment. */ - int width = xstep < 0 ? -xstep : xstep; - - /* Not all of the column may be available if close to the edge of the - image, requiring multiple slices. */ - - int available = scr.image->width - xsource; - - while (width) + if (xstep) { - /* Plot a column in two pieces if the vertical origin is - non-zero. The first piece is at (xdisplay, 0) and - provides the lower part of the background image displaced - upwards (or downwards having wrapped around) on the - screen. */ + /* Find the source position for the appropriate edge. */ + + xsource = wrap_value(xpos + xedge, scr.image->width); + ysource = ypos; - image_plot_sprite_section(&scr, xsource, ypos, - width, scr.image->height - ypos, - xdisplay, 0, - -1); + /* Request tiling in the source coordinates. */ + + image_tile_sprite(&scr, xsource, ysource, + abs(xstep), display_config.line_count * scr.yscale, + xdisplay, 0); + } - /* The second column is at (xdisplay, h - ypos) and - provides the upper part of the background image displaced - downwards (or upwards having wrapped around) on the - screen. */ + /* Vertical scrolling requires columns across the width of the screen at the + appropriate edge (top or bottom). */ - if (ypos) - image_plot_sprite_section(&scr, xsource, 0, - width, ypos, - xdisplay, (scr.image->height - ypos) / v->yscale, - -1); + if (ystep) + { + /* Find the source position for the appropriate edge. */ - /* Get the next slice of the column. */ + xsource = xpos; + ysource = wrap_value(ypos + yedge, scr.image->height); - if (available < width) - { - width -= available; - xsource = 0; - xdisplay = wrap_value(xdisplay + available, scr.image->width); - available = scr.image->width; - } - else - width = 0; + /* Request tiling in the source coordinates. */ + + image_tile_sprite(&scr, xsource, ysource, + display_config.line_length, abs(ystep), + 0, ydisplay); } } + + /* Move a sprite around on the framebuffer. */ static void animate(uint32_t delay) @@ -285,12 +279,11 @@ display_select_frame(&display_config, frame); - /* Plot the image centred on the screen. */ + /* Tile the image on the screen. */ - image_plot_sprite(&scr, - (display_config.line_length - scr.image->width) / 2, - (display_config.line_count - (scr.image->height / scr.yscale)) / 2, - -1); + image_tile_sprite(&scr, 0, 0, display_config.line_length, + display_config.line_count * scr.yscale, + 0, 0); /* Write a sequence of characters. */ diff -r 301fb9b9ed23 -r 14bc79b7e4dc include/image.h --- a/include/image.h Sat Nov 10 23:38:09 2018 +0100 +++ b/include/image.h Sun Nov 11 18:15:24 2018 +0100 @@ -156,4 +156,8 @@ int xstart, int ystart, int xsize, int ysize, int x, int y, int key); +void image_tile_sprite(sprite_t *s, int xsource, int ysource, + int width, int height, + int xdisplay, int ydisplay); + #endif /* __IMAGE_H__ */ diff -r 301fb9b9ed23 -r 14bc79b7e4dc include/utils.h --- a/include/utils.h Sat Nov 10 23:38:09 2018 +0100 +++ b/include/utils.h Sun Nov 11 18:15:24 2018 +0100 @@ -22,6 +22,10 @@ #include +#define abs(x) ((x) < 0 ? -(x) : (x)) +#define max(x, y) ((x) > (y) ? (x) : (y)) +#define min(x, y) ((x) < (y) ? (x) : (y)) + void wait(uint32_t delay); uint8_t *wrap_pointer(uint8_t *ptr, uint8_t *lower, uint8_t *upper); diff -r 301fb9b9ed23 -r 14bc79b7e4dc lib/image.c --- a/lib/image.c Sat Nov 10 23:38:09 2018 +0100 +++ b/lib/image.c Sun Nov 11 18:15:24 2018 +0100 @@ -19,6 +19,7 @@ #include "display.h" #include "image.h" +#include "utils.h" @@ -110,3 +111,67 @@ xstart, ystart, xsize, ysize, s->yscale, x, y, key, 1); } + + + +/* Tile a sprite, using the given source origin, filling a display region. */ + +void image_tile_sprite(sprite_t *s, int xsource, int ysource, + int width, int height, + int xdisplay, int ydisplay) +{ + /* Determine the portion of the sprite to be plotted in the first column. */ + + int source_width = s->image->width - xsource; + int source_height; + int total_height; + int x, y; + int xs, ys; + + /* Fill (xdisplay, ydisplay) with (width, height) from source, slice by + slice. */ + + x = xdisplay; + xs = xsource; + + while (width) + { + /* Fill (x, ydisplay) with (source_width, height) from source, with the + height being divided into image-sized pieces. */ + + total_height = height; + source_height = s->image->height - ysource; + y = ydisplay; + ys = ysource; + + while (total_height) + { + /* Plot as much of the image as is available from the given source + coordinates. */ + + image_plot_sprite_section(s, xs, ys, + min(width, source_width), min(total_height, source_height), + x, y, -1); + + /* Continue to plot the image again to fill the slice. */ + + if (source_height >= total_height) + break; + + total_height -= source_height; + y += source_height / s->yscale; + ys = 0; + source_height = s->image->height; + } + + /* Get the next slice of the column. */ + + if (source_width >= width) + break; + + width -= source_width; + x += source_width; + xs = 0; + source_width = s->image->width; + } +} diff -r 301fb9b9ed23 -r 14bc79b7e4dc lib/viewport.c --- a/lib/viewport.c Sat Nov 10 23:38:09 2018 +0100 +++ b/lib/viewport.c Sun Nov 11 18:15:24 2018 +0100 @@ -65,7 +65,7 @@ scrolling left) or at the right (if scrolling right). */ if (v->update) - v->update(v, v->xorigin, v->yorigin, xstep, ystep); + v->update(v->xorigin, v->yorigin, xstep, ystep); /* Record the origin for this frame. */