1.1 --- a/examples/vga/main.c Sat Nov 10 23:38:09 2018 +0100
1.2 +++ b/examples/vga/main.c Sun Nov 11 18:15:24 2018 +0100
1.3 @@ -105,69 +105,63 @@
1.4
1.5 /* Plot the revealed region at the edge of the screen after scrolling. */
1.6
1.7 -static void plot_screen_edge(viewport_t *v, int xorigin, int yorigin,
1.8 - int xstep, int ystep)
1.9 +static void plot_screen_edge(int xorigin, int yorigin, int xstep, int ystep)
1.10 {
1.11 - /* Determine positions within the image. */
1.12 + /* The display regions are either the left or right edge... */
1.13 +
1.14 + int xedge = xstep < 0 ? 0 : display_config.line_length - xstep;
1.15 + int xdisplay = xedge;
1.16 +
1.17 + /* and either the top or bottom edge... */
1.18 +
1.19 + int yedge = ystep < 0 ? 0 : display_config.line_count * scr.yscale - ystep;
1.20 + int ydisplay = yedge / scr.yscale;
1.21 +
1.22 + /* Determine the origin position within the image. */
1.23
1.24 int xpos = wrap_value(xorigin, scr.image->width);
1.25 int ypos = wrap_value(yorigin, scr.image->height);
1.26 -
1.27 - /* The display region is either the left or right edge. */
1.28 + int xsource, ysource;
1.29
1.30 - int xdisplay = xstep < 0 ? 0 : scr.image->width - xstep;
1.31 -
1.32 - /* The source region depends on the origin within the background image. */
1.33 -
1.34 - int xsource = wrap_value(xdisplay + xpos, scr.image->width);
1.35 + /* Horizontal scrolling requires columns spanning the height of the screen
1.36 + at the appropriate edge (left or right). */
1.37
1.38 /* The column width is the absolute increment. */
1.39
1.40 - int width = xstep < 0 ? -xstep : xstep;
1.41 -
1.42 - /* Not all of the column may be available if close to the edge of the
1.43 - image, requiring multiple slices. */
1.44 -
1.45 - int available = scr.image->width - xsource;
1.46 -
1.47 - while (width)
1.48 + if (xstep)
1.49 {
1.50 - /* Plot a column in two pieces if the vertical origin is
1.51 - non-zero. The first piece is at (xdisplay, 0) and
1.52 - provides the lower part of the background image displaced
1.53 - upwards (or downwards having wrapped around) on the
1.54 - screen. */
1.55 + /* Find the source position for the appropriate edge. */
1.56 +
1.57 + xsource = wrap_value(xpos + xedge, scr.image->width);
1.58 + ysource = ypos;
1.59
1.60 - image_plot_sprite_section(&scr, xsource, ypos,
1.61 - width, scr.image->height - ypos,
1.62 - xdisplay, 0,
1.63 - -1);
1.64 + /* Request tiling in the source coordinates. */
1.65 +
1.66 + image_tile_sprite(&scr, xsource, ysource,
1.67 + abs(xstep), display_config.line_count * scr.yscale,
1.68 + xdisplay, 0);
1.69 + }
1.70
1.71 - /* The second column is at (xdisplay, h - ypos) and
1.72 - provides the upper part of the background image displaced
1.73 - downwards (or upwards having wrapped around) on the
1.74 - screen. */
1.75 + /* Vertical scrolling requires columns across the width of the screen at the
1.76 + appropriate edge (top or bottom). */
1.77
1.78 - if (ypos)
1.79 - image_plot_sprite_section(&scr, xsource, 0,
1.80 - width, ypos,
1.81 - xdisplay, (scr.image->height - ypos) / v->yscale,
1.82 - -1);
1.83 + if (ystep)
1.84 + {
1.85 + /* Find the source position for the appropriate edge. */
1.86
1.87 - /* Get the next slice of the column. */
1.88 + xsource = xpos;
1.89 + ysource = wrap_value(ypos + yedge, scr.image->height);
1.90
1.91 - if (available < width)
1.92 - {
1.93 - width -= available;
1.94 - xsource = 0;
1.95 - xdisplay = wrap_value(xdisplay + available, scr.image->width);
1.96 - available = scr.image->width;
1.97 - }
1.98 - else
1.99 - width = 0;
1.100 + /* Request tiling in the source coordinates. */
1.101 +
1.102 + image_tile_sprite(&scr, xsource, ysource,
1.103 + display_config.line_length, abs(ystep),
1.104 + 0, ydisplay);
1.105 }
1.106 }
1.107
1.108 +
1.109 +
1.110 /* Move a sprite around on the framebuffer. */
1.111
1.112 static void animate(uint32_t delay)
1.113 @@ -285,12 +279,11 @@
1.114
1.115 display_select_frame(&display_config, frame);
1.116
1.117 - /* Plot the image centred on the screen. */
1.118 + /* Tile the image on the screen. */
1.119
1.120 - image_plot_sprite(&scr,
1.121 - (display_config.line_length - scr.image->width) / 2,
1.122 - (display_config.line_count - (scr.image->height / scr.yscale)) / 2,
1.123 - -1);
1.124 + image_tile_sprite(&scr, 0, 0, display_config.line_length,
1.125 + display_config.line_count * scr.yscale,
1.126 + 0, 0);
1.127
1.128 /* Write a sequence of characters. */
1.129
2.1 --- a/include/image.h Sat Nov 10 23:38:09 2018 +0100
2.2 +++ b/include/image.h Sun Nov 11 18:15:24 2018 +0100
2.3 @@ -156,4 +156,8 @@
2.4 int xstart, int ystart, int xsize, int ysize,
2.5 int x, int y, int key);
2.6
2.7 +void image_tile_sprite(sprite_t *s, int xsource, int ysource,
2.8 + int width, int height,
2.9 + int xdisplay, int ydisplay);
2.10 +
2.11 #endif /* __IMAGE_H__ */
3.1 --- a/include/utils.h Sat Nov 10 23:38:09 2018 +0100
3.2 +++ b/include/utils.h Sun Nov 11 18:15:24 2018 +0100
3.3 @@ -22,6 +22,10 @@
3.4
3.5 #include <stdint.h>
3.6
3.7 +#define abs(x) ((x) < 0 ? -(x) : (x))
3.8 +#define max(x, y) ((x) > (y) ? (x) : (y))
3.9 +#define min(x, y) ((x) < (y) ? (x) : (y))
3.10 +
3.11 void wait(uint32_t delay);
3.12
3.13 uint8_t *wrap_pointer(uint8_t *ptr, uint8_t *lower, uint8_t *upper);
4.1 --- a/lib/image.c Sat Nov 10 23:38:09 2018 +0100
4.2 +++ b/lib/image.c Sun Nov 11 18:15:24 2018 +0100
4.3 @@ -19,6 +19,7 @@
4.4
4.5 #include "display.h"
4.6 #include "image.h"
4.7 +#include "utils.h"
4.8
4.9
4.10
4.11 @@ -110,3 +111,67 @@
4.12 xstart, ystart, xsize, ysize, s->yscale,
4.13 x, y, key, 1);
4.14 }
4.15 +
4.16 +
4.17 +
4.18 +/* Tile a sprite, using the given source origin, filling a display region. */
4.19 +
4.20 +void image_tile_sprite(sprite_t *s, int xsource, int ysource,
4.21 + int width, int height,
4.22 + int xdisplay, int ydisplay)
4.23 +{
4.24 + /* Determine the portion of the sprite to be plotted in the first column. */
4.25 +
4.26 + int source_width = s->image->width - xsource;
4.27 + int source_height;
4.28 + int total_height;
4.29 + int x, y;
4.30 + int xs, ys;
4.31 +
4.32 + /* Fill (xdisplay, ydisplay) with (width, height) from source, slice by
4.33 + slice. */
4.34 +
4.35 + x = xdisplay;
4.36 + xs = xsource;
4.37 +
4.38 + while (width)
4.39 + {
4.40 + /* Fill (x, ydisplay) with (source_width, height) from source, with the
4.41 + height being divided into image-sized pieces. */
4.42 +
4.43 + total_height = height;
4.44 + source_height = s->image->height - ysource;
4.45 + y = ydisplay;
4.46 + ys = ysource;
4.47 +
4.48 + while (total_height)
4.49 + {
4.50 + /* Plot as much of the image as is available from the given source
4.51 + coordinates. */
4.52 +
4.53 + image_plot_sprite_section(s, xs, ys,
4.54 + min(width, source_width), min(total_height, source_height),
4.55 + x, y, -1);
4.56 +
4.57 + /* Continue to plot the image again to fill the slice. */
4.58 +
4.59 + if (source_height >= total_height)
4.60 + break;
4.61 +
4.62 + total_height -= source_height;
4.63 + y += source_height / s->yscale;
4.64 + ys = 0;
4.65 + source_height = s->image->height;
4.66 + }
4.67 +
4.68 + /* Get the next slice of the column. */
4.69 +
4.70 + if (source_width >= width)
4.71 + break;
4.72 +
4.73 + width -= source_width;
4.74 + x += source_width;
4.75 + xs = 0;
4.76 + source_width = s->image->width;
4.77 + }
4.78 +}
5.1 --- a/lib/viewport.c Sat Nov 10 23:38:09 2018 +0100
5.2 +++ b/lib/viewport.c Sun Nov 11 18:15:24 2018 +0100
5.3 @@ -65,7 +65,7 @@
5.4 scrolling left) or at the right (if scrolling right). */
5.5
5.6 if (v->update)
5.7 - v->update(v, v->xorigin, v->yorigin, xstep, ystep);
5.8 + v->update(v->xorigin, v->yorigin, xstep, ystep);
5.9
5.10 /* Record the origin for this frame. */
5.11