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(sprite_t *s, int frame) 29 { 30 return &s->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 /* Get a sprite's position. */ 43 44 position_t *image_get_sprite_position(sprite_t *s) 45 { 46 return image_get_stored_position(s, s->cfg->frame); 47 } 48 49 /* Set a sprite's position. */ 50 51 void image_set_sprite_position(sprite_t *s, int x, int y) 52 { 53 position_t *p = image_get_sprite_position(s); 54 55 p->x = x; 56 p->y = y; 57 } 58 59 60 61 /* Copy a region from the screen to the store, then blit the image. */ 62 63 void image_plot_sprite(sprite_t *s) 64 { 65 int frame = 0; 66 position_t *p = 0; 67 68 if (s->regions) 69 { 70 frame = s->cfg->frame; 71 p = image_get_stored_position(s, frame); 72 73 /* Copy to the stored region. */ 74 75 display_copy(s->cfg, image_get_stored_region(s->regions, frame), 76 s->image->width, s->image->height, 77 p->x, p->y, -1, 0); 78 } 79 80 /* Plot to the screen. */ 81 82 display_copy(s->cfg, s->image->image, 83 s->image->width, s->image->height, 84 p->x, p->y, s->key, 1); 85 86 if (s->regions) 87 { 88 /* Record the stored background details. */ 89 90 if (frame >= s->regions->stored) 91 s->regions->stored = frame + 1; 92 } 93 } 94 95 /* Copy a region from the store to the screen, restoring the original 96 background. */ 97 98 void image_unplot_sprite(sprite_t *s) 99 { 100 int frame; 101 position_t *p; 102 103 if (!s->regions) 104 return; 105 106 frame = s->cfg->frame; 107 p = image_get_stored_position(s, frame); 108 109 /* Only unplot the sprite if a region was stored for the frame. */ 110 111 if (s->regions->stored > frame) 112 display_copy(s->cfg, image_get_stored_region(s->regions, frame), 113 s->image->width, s->image->height, 114 p->x, p->y, -1, 1); 115 } 116 117 /* Unplot a sprite by restoring a region from the background image. */ 118 119 void image_unplot_sprite_from_image(sprite_t *s, sprite_t *bg, 120 int xorigin, int yorigin) 121 { 122 int frame = s->cfg->frame; 123 position_t *p = image_get_stored_position(s, frame); 124 125 /* Plot the region of the background using the sprite image dimensions 126 converted to background image dimensions at the sprite's position on the 127 display. */ 128 129 image_update_tiled_image(bg, xorigin, yorigin, 130 s->image->width, s->image->height, 131 p->x, p->y); 132 } 133 134 135 136 /* Plot a section of an image without storing the background beforehand. */ 137 138 void image_plot_sprite_section(sprite_t *s, 139 int xstart, int ystart, int xsize, int ysize, 140 int x, int y, int key) 141 { 142 display_copy_section(s->cfg, s->image->image, 143 s->image->width, s->image->height, 144 xstart, ystart, xsize, ysize, 145 x, y, key, 1); 146 } 147 148 149 150 /* Tile a sprite, using the given source origin, filling a display region. */ 151 152 void image_tile_sprite(sprite_t *s, int xsource, int ysource, 153 int width, int height, 154 int xdisplay, int ydisplay) 155 { 156 /* Determine the portion of the sprite to be plotted in the first column. */ 157 158 int source_width = s->image->width - xsource; 159 int source_height; 160 int total_height; 161 int x, y; 162 int xs, ys; 163 164 /* Fill (xdisplay, ydisplay) with (width, height) from source, slice by 165 slice. */ 166 167 x = xdisplay; 168 xs = xsource; 169 170 while (width) 171 { 172 /* Fill (x, ydisplay) with (source_width, height) from source, with the 173 height being divided into image-sized pieces. */ 174 175 total_height = height; 176 source_height = s->image->height - ysource; 177 y = ydisplay; 178 ys = ysource; 179 180 while (total_height) 181 { 182 /* Plot as much of the image as is available from the given source 183 coordinates. */ 184 185 image_plot_sprite_section(s, xs, ys, 186 min(width, source_width), min(total_height, source_height), 187 x, y, -1); 188 189 /* Continue to plot the image again to fill the slice. */ 190 191 if (source_height >= total_height) 192 break; 193 194 total_height -= source_height; 195 y += source_height; 196 ys = 0; 197 source_height = s->image->height; 198 } 199 200 /* Get the next slice of the column. */ 201 202 if (source_width >= width) 203 break; 204 205 width -= source_width; 206 x += source_width; 207 xs = 0; 208 source_width = s->image->width; 209 } 210 } 211 212 /* Plot a scrolling tiled image upon a viewport update. */ 213 214 void image_update_scrolled_tiled_image(sprite_t *s, int xorigin, int yorigin, 215 int xstep, int ystep) 216 { 217 /* The display regions are either the left or right edge... */ 218 219 int xedge = xstep < 0 ? 0 : s->cfg->line_length - xstep; 220 int xdisplay = xedge; 221 222 /* and either the top or bottom edge... */ 223 224 int yedge = ystep < 0 ? 0 : s->cfg->line_count - ystep; 225 int ydisplay = yedge; 226 227 /* Determine the origin position within the image. */ 228 229 int xpos = wrap_value(xorigin, s->image->width); 230 int ypos = wrap_value(yorigin, s->image->height); 231 int xsource, ysource; 232 233 /* Horizontal scrolling requires columns spanning the height of the screen 234 at the appropriate edge (left or right). */ 235 236 /* The column width is the absolute increment. */ 237 238 if (xstep) 239 { 240 /* Find the source position for the appropriate edge. */ 241 242 xsource = wrap_value(xpos + xedge, s->image->width); 243 ysource = ypos; 244 245 /* Request tiling in the source coordinates. */ 246 247 image_tile_sprite(s, xsource, ysource, 248 abs(xstep), s->cfg->line_count, 249 xdisplay, 0); 250 } 251 252 /* Vertical scrolling requires columns across the width of the screen at the 253 appropriate edge (top or bottom). */ 254 255 if (ystep) 256 { 257 /* Find the source position for the appropriate edge. */ 258 259 xsource = xpos; 260 ysource = wrap_value(ypos + yedge, s->image->height); 261 262 /* Request tiling in the source coordinates. */ 263 264 image_tile_sprite(s, xsource, ysource, 265 s->cfg->line_length, abs(ystep), 266 0, ydisplay); 267 } 268 } 269 270 /* Plot a region of a tiled image. */ 271 272 void image_update_tiled_image(sprite_t *s, int xorigin, int yorigin, 273 int width, int height, 274 int xdisplay, int ydisplay) 275 { 276 /* Find the source position for the region. */ 277 278 int xsource = wrap_value(xorigin + xdisplay, s->image->width); 279 int ysource = wrap_value(yorigin + ydisplay, s->image->height); 280 281 /* Request tiling in the source coordinates. */ 282 283 image_tile_sprite(s, xsource, ysource, 284 width, height, 285 xdisplay, ydisplay); 286 }