]> git.draconx.ca Git - liblbx.git/blobdiff - src/image.c
Implement image masks to handle transparency in images.
[liblbx.git] / src / image.c
index 2d34b52b0e2c742611e292c1d68cd8bcbec35e77..f32a66094372eda5de7418afa32450abad9ab2f2 100644 (file)
@@ -29,6 +29,7 @@ struct lbx_image {
        int currentframe;
        int currentx, currenty;
        unsigned char **framedata;
+       unsigned char **mask;
 
        uint32_t offsets[];
 };
@@ -101,6 +102,7 @@ static int _lbx_drawrow(int first, struct lbx_image *img)
        size_t rc;
 
        assert(img->framedata);
+       assert(img->mask);
 
        if (fread(&type, sizeof type, 1, img->f) != 1) goto readerr;
        type = letohs(type); img->foff += sizeof type;
@@ -150,6 +152,8 @@ static int _lbx_drawrow(int first, struct lbx_image *img)
                return -1;
        }
 
+       memset(&img->mask[img->currenty][img->currentx], 1, count);
+
        pos = &img->framedata[img->currenty][img->currentx];
        rc  = fread(pos, 1, count, img->f);
        img->currentx += rc;
@@ -174,6 +178,31 @@ readerr:
        return -1;
 }
 
+static unsigned char **allocframebuffer(size_t width, size_t height)
+{
+       unsigned char **new, *tmp;
+       size_t i;
+
+       tmp = calloc(height, width);
+       if (!tmp) {
+               lbx_errno = -errno;
+               return NULL;
+       }
+
+       new = malloc(height * sizeof *new);
+       if (!new) {
+               lbx_errno = -errno;
+               free(tmp);
+               return NULL;
+       }
+
+       for (i = 0; i < height; i++) {
+               new[i] = tmp + i * width;
+       }
+
+       return new;
+}
+
 unsigned char **lbximg_getframe(struct lbx_image *img, int frame)
 {
        if (frame >= img->frames || frame < 0) {
@@ -182,25 +211,15 @@ unsigned char **lbximg_getframe(struct lbx_image *img, int frame)
        }
 
        if (!img->framedata) {
-               unsigned char *tmp;
-               int i;
-
-               tmp = malloc(img->width * img->height);
-               if (!tmp) {
-                       lbx_errno = -errno;
+               img->framedata = allocframebuffer(img->width, img->height);
+               if (!img->framedata)
                        return NULL;
-               }
+       }
 
-               img->framedata = malloc(img->height * sizeof *img->framedata);
-               if (!img->framedata) {
-                       lbx_errno = -errno;
-                       free(tmp);
+       if (!img->mask) {
+               img->mask = allocframebuffer(img->width, img->height);
+               if (!img->mask)
                        return NULL;
-               }
-
-               for (i = 0; i < img->height; i++) {
-                       img->framedata[i] = tmp + i * img->width;
-               }
        }
 
        /* Start over if we are backtracking. */
@@ -210,6 +229,7 @@ unsigned char **lbximg_getframe(struct lbx_image *img, int frame)
        if (img->flags & FLAG_OVERWRITE) {
                /* Clear the slate. */
                memset(img->framedata[0], 0, img->width * img->height);
+               memset(img->mask[0],      0, img->width * img->height);
        } else {
                /* We must have previous frame decoded to continue. */
                if (frame > img->currentframe + 1) {
@@ -346,6 +366,11 @@ void lbximg_getinfo(struct lbx_image *img, struct lbx_imginfo *info)
        }
 }
 
+unsigned char **lbximg_getmask(struct lbx_image *img)
+{
+       return img->mask;
+}
+
 void lbximg_close(struct lbx_image *img)
 {
        if (!img) return;
@@ -355,6 +380,11 @@ void lbximg_close(struct lbx_image *img)
                free(img->framedata);
        }
 
+       if (img->mask) {
+               free(img->mask[0]);
+               free(img->mask);
+       }
+
        if (img->f) {
                fclose(img->f);
        }