1.1 --- a/examples/vga/main.c Sun Nov 04 20:45:02 2018 +0100
1.2 +++ b/examples/vga/main.c Sun Nov 04 22:44:17 2018 +0100
1.3 @@ -161,62 +161,86 @@
1.4 x, y, -1, 1);
1.5 }
1.6
1.7 +/* Wrap a value within the bounds [0, limit). */
1.8 +
1.9 +static int wrap_value(int value, int limit)
1.10 +{
1.11 + if (value < 0)
1.12 + return limit - (-value % limit);
1.13 + else if (value >= limit)
1.14 + return (value - limit) % limit;
1.15 + else
1.16 + return value;
1.17 +}
1.18 +
1.19 /* Plot the revealed region at the edge of the screen after scrolling. */
1.20
1.21 static void plot_screen_edge(int xorigin, int yorigin, int xstep)
1.22 {
1.23 + /* Determine positions within the image. */
1.24 +
1.25 + int xpos = wrap_value(xorigin, screendata_width);
1.26 + int ypos = wrap_value(yorigin, screendata_height);
1.27 +
1.28 /* The display region is either the left or right edge. */
1.29
1.30 int xdisplay = xstep < 0 ? 0 : screendata_width - xstep;
1.31
1.32 /* The source region depends on the origin within the background image. */
1.33
1.34 - int xsource = (xdisplay + xorigin) % screendata_width;
1.35 + int xsource = wrap_value(xdisplay + xpos, screendata_width);
1.36
1.37 /* The column width is the absolute increment. */
1.38
1.39 int width = xstep < 0 ? -xstep : xstep;
1.40
1.41 - /* Plot a column in two pieces if the vertical origin is
1.42 - non-zero. The first piece is at (xdisplay, 0) and
1.43 - provides the lower part of the background image displaced
1.44 - upwards (or downwards having wrapped around) on the
1.45 - screen. */
1.46 + /* Not all of the column may be available if close to the edge of the
1.47 + image, requiring multiple slices. */
1.48 +
1.49 + int available = screendata_width - xsource;
1.50
1.51 - copy_display_section(&display_config, screendata,
1.52 - screendata_width, screendata_height,
1.53 - xsource, yorigin,
1.54 - width, screendata_height - yorigin,
1.55 - SOURCE_YSTEP,
1.56 - xdisplay, 0,
1.57 - -1, 1);
1.58 + while (width)
1.59 + {
1.60 + /* Plot a column in two pieces if the vertical origin is
1.61 + non-zero. The first piece is at (xdisplay, 0) and
1.62 + provides the lower part of the background image displaced
1.63 + upwards (or downwards having wrapped around) on the
1.64 + screen. */
1.65
1.66 - /* The second column is at (xdisplay, h - yorigin) and
1.67 - provides the upper part of the background image displaced
1.68 - downwards (or upwards having wrapped around) on the
1.69 - screen. */
1.70 -
1.71 - if (yorigin)
1.72 copy_display_section(&display_config, screendata,
1.73 screendata_width, screendata_height,
1.74 - xsource, 0,
1.75 - width, yorigin,
1.76 + xsource, ypos,
1.77 + width, screendata_height - ypos,
1.78 SOURCE_YSTEP,
1.79 - xdisplay, (screendata_height - yorigin) / SOURCE_YSTEP,
1.80 + xdisplay, 0,
1.81 -1, 1);
1.82 -}
1.83 +
1.84 + /* The second column is at (xdisplay, h - ypos) and
1.85 + provides the upper part of the background image displaced
1.86 + downwards (or upwards having wrapped around) on the
1.87 + screen. */
1.88
1.89 -/* Wrap a value within the bounds [0, limit) provided value is already within
1.90 - the bounds [-limit, limit * 2). */
1.91 + if (ypos)
1.92 + copy_display_section(&display_config, screendata,
1.93 + screendata_width, screendata_height,
1.94 + xsource, 0,
1.95 + width, ypos,
1.96 + SOURCE_YSTEP,
1.97 + xdisplay, (screendata_height - ypos) / SOURCE_YSTEP,
1.98 + -1, 1);
1.99 +
1.100 + /* Get the next slice of the column. */
1.101
1.102 -static int wrap_value(int value, int limit)
1.103 -{
1.104 - if (value < 0)
1.105 - return value + limit;
1.106 - else if (value >= limit)
1.107 - return value - limit;
1.108 - else
1.109 - return value;
1.110 + if (available < width)
1.111 + {
1.112 + width -= available;
1.113 + xsource = 0;
1.114 + xdisplay = wrap_value(xdisplay + available, screendata_width);
1.115 + available = screendata_width;
1.116 + }
1.117 + else
1.118 + width = 0;
1.119 + }
1.120 }
1.121
1.122 /* Move a sprite around on the framebuffer. */
1.123 @@ -312,11 +336,14 @@
1.124 /* Due to the effect of a simple screen start increment in the
1.125 dual channel configuration, horizontal scrolling involves two
1.126 pixel increments and thus requires a two-pixel column to be
1.127 - plotted. */
1.128 + plotted per scrolling increment. */
1.129
1.130 if (xdir)
1.131 xorigin += xdir * SCROLL_XSTEP;
1.132
1.133 + /* For vertically-scaled backgrounds, the full resolution image
1.134 + is traversed by multiples of the scrolling increment. */
1.135 +
1.136 if (ydir)
1.137 yorigin += ydir * SOURCE_YSTEP;
1.138
1.139 @@ -335,11 +362,6 @@
1.140
1.141 frame_offset[frame] = get_start_offset(&display_config);
1.142
1.143 - /* Update the current origin. */
1.144 -
1.145 - xorigin = wrap_value(xorigin, screendata_width);
1.146 - yorigin = wrap_value(yorigin, screendata_height);
1.147 -
1.148 /* For horizontal scrolling, plot the exposed column at the left
1.149 (if scrolling left) or at the right (if scrolling right). */
1.150