CommonPIC32

Annotated lib/image.c

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