#include <stdlib.h>
#include <stdint.h>
+#include <string.h>
#include <assert.h>
#include <errno.h>
#include "lbx.h"
#include "image.h"
+#define FLAG_OVERWRITE 0x0400 /* Draw each frame on a clean slate (unsure). */
+#define FLAG_PALETTE 0x1000 /* Image contains embedded palette. */
+#define FLAG_LOOPING 0x2000 /* Loop over all frames in the image (unsure). */
+
struct lbx_image {
uint16_t width, height;
uint16_t wtf1;
- uint16_t offs, frames;
- uint16_t pal;
+ uint16_t frames, leadin;
+ uint16_t flags;
FILE *f;
long foff;
struct lbx_image *lbximg_fopen(FILE *f)
{
struct lbx_image tmp = {.f = f}, *new = NULL;
+ size_t rc;
if (fread(&tmp.width, sizeof tmp.width, 1, f) != 1) goto readerr;
if (fread(&tmp.height, sizeof tmp.height, 1, f) != 1) goto readerr;
if (fread(&tmp.wtf1, sizeof tmp.wtf1, 1, f) != 1) goto readerr;
- if (fread(&tmp.offs, sizeof tmp.offs, 1, f) != 1) goto readerr;
if (fread(&tmp.frames, sizeof tmp.frames, 1, f) != 1) goto readerr;
- if (fread(&tmp.pal, sizeof tmp.pal, 1, f) != 1) goto readerr;
+ if (fread(&tmp.leadin, sizeof tmp.leadin, 1, f) != 1) goto readerr;
+ if (fread(&tmp.flags, sizeof tmp.flags, 1, f) != 1) goto readerr;
tmp.width = letohs(tmp.width); tmp.foff += sizeof tmp.width;
tmp.height = letohs(tmp.height); tmp.foff += sizeof tmp.height;
tmp.wtf1 = letohs(tmp.wtf1); tmp.foff += sizeof tmp.wtf1;
- tmp.offs = letohs(tmp.offs); tmp.foff += sizeof tmp.offs;
tmp.frames = letohs(tmp.frames); tmp.foff += sizeof tmp.frames;
- tmp.pal = letohs(tmp.pal); tmp.foff += sizeof tmp.pal;
-
- /* For some reason, the format seems to need this. */
- tmp.offs++;
- tmp.frames++;
+ tmp.leadin = letohs(tmp.leadin); tmp.foff += sizeof tmp.leadin;
+ tmp.flags = letohs(tmp.flags); tmp.foff += sizeof tmp.flags;
/* Format constraints. */
- if (tmp.offs <= tmp.frames) {
+ if (tmp.frames <= tmp.leadin) {
lbx_errno = LBX_EFORMAT;
return NULL;
}
* assumptions.
*/
_lbx_assert(tmp.wtf1 == 0);
- _lbx_assert(tmp.offs == tmp.frames + 1);
- _lbx_assert(tmp.pal == 0 || tmp.pal == 0x1000);
+ _lbx_assert(!(tmp.flags & ~(FLAG_PALETTE|FLAG_OVERWRITE|FLAG_LOOPING)));
- new = malloc(sizeof *new + tmp.offs * sizeof *new->offsets);
+ new = malloc(sizeof *new + (tmp.frames+1) * sizeof *new->offsets);
if (!new) {
lbx_errno = -errno;
return NULL;
*new = tmp;
new->currentframe = -1;
- if (fread(new->offsets, sizeof *new->offsets, new->offs, f)!= new->offs)
+ rc = fread(new->offsets, sizeof *new->offsets, new->frames+1, f);
+ if (rc < new->frames+1)
goto readerr;
- new->foff += sizeof *new->offsets * new->offs;
+ new->foff += sizeof *new->offsets * (new->frames+1);
return new;
readerr:
if (img->currentframe > frame)
img->currentframe == -1;
- /* We must have previous frame decoded to continue. */
- if (frame > img->currentframe + 1) {
- if (!lbximg_getframe(img, frame-1))
- return NULL;
+ if (img->flags & FLAG_OVERWRITE) {
+ /* Clear the slate. */
+ memset(img->framedata[0], 0, img->width * img->height);
+ } else {
+ /* We must have previous frame decoded to continue. */
+ if (frame > img->currentframe + 1) {
+ if (!lbximg_getframe(img, frame-1))
+ return NULL;
+ }
}
if (img->currentframe != frame) {
int
lbximg_getpalette(struct lbx_image *img, struct lbx_colour palette[static 256])
{
- size_t hdrlen = 6*(sizeof img->pal)+(img->offs)*(sizeof *img->offsets);
+ size_t hdrlen = 6*(sizeof img->wtf1)+(img->frames+1)*(sizeof *img->offsets);
unsigned int i;
size_t rc;
uint8_t entry[4];
/* Do nothing if the image doesn't have embedded palette data. */
- if (img->pal == 0)
+ if (!(img->flags & FLAG_PALETTE))
return 0;
/* Palette data is located right after the header. */
void lbximg_getinfo(struct lbx_image *img, struct lbx_imginfo *info)
{
*info = (struct lbx_imginfo) {
- .width = img->width,
- .height = img->height,
- .nframes = img->frames,
+ .width = img->width,
+ .height = img->height,
+ .nframes = img->frames,
+ .haspalette = (_Bool)(img->flags & FLAG_PALETTE),
};
+
+ /* There seems to be two ways of specifying that an image loops. */
+ if (img->flags & FLAG_LOOPING) {
+ info->loopstart = 0;
+ info->looping = 1;
+ } else if (img->leadin != img->frames - 1) {
+ info->loopstart = img->leadin;
+ info->looping = 1;
+ }
}
void lbximg_close(struct lbx_image *img)