1 /* 2 * Common image-related functions. 3 * 4 * Copyright (C) 2018 Paul Boddie <paul@boddie.org.uk> 5 * 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation, either version 3 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program. If not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 #include "display.h" 21 #include "image.h" 22 #include "utils.h" 23 24 25 26 /* Obtain the position for the stored region from the given frame. */ 27 28 position_t *image_get_stored_position(stored_regions_t *r, int frame) 29 { 30 return &r->pos[frame]; 31 } 32 33 /* Obtain the image data for the stored region from the given frame. */ 34 35 uint8_t *image_get_stored_region(stored_regions_t *r, int frame) 36 { 37 return r->image + r->size * frame; 38 } 39 40 41 42 /* Copy a region from the screen to the store, then blit the image. */ 43 44 void image_plot_sprite(sprite_t *s, int x, int y, int key) 45 { 46 int frame = 0; 47 position_t *p = 0; 48 49 if (s->regions) 50 { 51 frame = s->cfg->frame; 52 p = image_get_stored_position(s->regions, frame); 53 54 /* Copy to the stored region. */ 55 56 display_copy(s->cfg, image_get_stored_region(s->regions, frame), 57 s->image->width, s->image->height / s->yscale, 1, 58 x, y, -1, 0); 59 } 60 61 /* Plot to the screen. */ 62 63 display_copy(s->cfg, s->image->image, 64 s->image->width, s->image->height, s->yscale, 65 x, y, key, 1); 66 67 if (s->regions) 68 { 69 /* Record the stored background details. */ 70 71 p->x = x; 72 p->y = y; 73 74 if (frame >= s->regions->stored) 75 s->regions->stored = frame + 1; 76 } 77 } 78 79 /* Copy a region from the store to the screen, restoring the original 80 background. */ 81 82 void image_unplot_sprite(sprite_t *s) 83 { 84 int frame; 85 position_t *p; 86 87 if (!s->regions) 88 return; 89 90 frame = s->cfg->frame; 91 p = image_get_stored_position(s->regions, frame); 92 93 /* Only unplot the sprite if a region was stored for the frame. */ 94 95 if (s->regions->stored > frame) 96 display_copy(s->cfg, image_get_stored_region(s->regions, frame), 97 s->image->width, s->image->height / s->yscale, 1, 98 p->x, p->y, -1, 1); 99 } 100 101 102 103 /* Plot a section of an image without storing the background beforehand. */ 104 105 void image_plot_sprite_section(sprite_t *s, 106 int xstart, int ystart, int xsize, int ysize, 107 int x, int y, int key) 108 { 109 display_copy_section(s->cfg, s->image->image, 110 s->image->width, s->image->height, 111 xstart, ystart, xsize, ysize, s->yscale, 112 x, y, key, 1); 113 } 114 115 116 117 /* Tile a sprite, using the given source origin, filling a display region. */ 118 119 void image_tile_sprite(sprite_t *s, int xsource, int ysource, 120 int width, int height, 121 int xdisplay, int ydisplay) 122 { 123 /* Determine the portion of the sprite to be plotted in the first column. */ 124 125 int source_width = s->image->width - xsource; 126 int source_height; 127 int total_height; 128 int x, y; 129 int xs, ys; 130 131 /* Fill (xdisplay, ydisplay) with (width, height) from source, slice by 132 slice. */ 133 134 x = xdisplay; 135 xs = xsource; 136 137 while (width) 138 { 139 /* Fill (x, ydisplay) with (source_width, height) from source, with the 140 height being divided into image-sized pieces. */ 141 142 total_height = height; 143 source_height = s->image->height - ysource; 144 y = ydisplay; 145 ys = ysource; 146 147 while (total_height) 148 { 149 /* Plot as much of the image as is available from the given source 150 coordinates. */ 151 152 image_plot_sprite_section(s, xs, ys, 153 min(width, source_width), min(total_height, source_height), 154 x, y, -1); 155 156 /* Continue to plot the image again to fill the slice. */ 157 158 if (source_height >= total_height) 159 break; 160 161 total_height -= source_height; 162 y += source_height / s->yscale; 163 ys = 0; 164 source_height = s->image->height; 165 } 166 167 /* Get the next slice of the column. */ 168 169 if (source_width >= width) 170 break; 171 172 width -= source_width; 173 x += source_width; 174 xs = 0; 175 source_width = s->image->width; 176 } 177 } 178 179 /* Plot a scrolling tiled image upon a viewport update. */ 180 181 void image_update_scrolled_tiled_image(sprite_t *s, int xorigin, int yorigin, 182 int xstep, int ystep) 183 { 184 /* The display regions are either the left or right edge... */ 185 186 int xedge = xstep < 0 ? 0 : s->cfg->line_length - xstep; 187 int xdisplay = xedge; 188 189 /* and either the top or bottom edge... */ 190 191 int yedge = ystep < 0 ? 0 : s->cfg->line_count * s->yscale - ystep; 192 int ydisplay = yedge / s->yscale; 193 194 /* Determine the origin position within the image. */ 195 196 int xpos = wrap_value(xorigin, s->image->width); 197 int ypos = wrap_value(yorigin, s->image->height); 198 int xsource, ysource; 199 200 /* Horizontal scrolling requires columns spanning the height of the screen 201 at the appropriate edge (left or right). */ 202 203 /* The column width is the absolute increment. */ 204 205 if (xstep) 206 { 207 /* Find the source position for the appropriate edge. */ 208 209 xsource = wrap_value(xpos + xedge, s->image->width); 210 ysource = ypos; 211 212 /* Request tiling in the source coordinates. */ 213 214 image_tile_sprite(s, xsource, ysource, 215 abs(xstep), s->cfg->line_count * s->yscale, 216 xdisplay, 0); 217 } 218 219 /* Vertical scrolling requires columns across the width of the screen at the 220 appropriate edge (top or bottom). */ 221 222 if (ystep) 223 { 224 /* Find the source position for the appropriate edge. */ 225 226 xsource = xpos; 227 ysource = wrap_value(ypos + yedge, s->image->height); 228 229 /* Request tiling in the source coordinates. */ 230 231 image_tile_sprite(s, xsource, ysource, 232 s->cfg->line_length, abs(ystep), 233 0, ydisplay); 234 } 235 }