* Change "#offsets" to "#frames". This makes lbximg capable of decoding all
frames of images such as the TANM_ family and science.lbx.001
* Change interpretation of "pal" to a bitmask containing flags. Current flags
handled are
- 0x0400: render each frame on a blank slate (makes TANM_ family work).
- 0x1000: image contains embedded palette, as previously understood.
- 0x2000: image loops over all frames.
* Change interpretation of previously-thought "#frames" to "leadin" - that is,
indicates the first frame that is part of a looping animation. This is
superseded by flag 0x2000, and yes - leadin == 0 means the same thing as that
flag. This will allow science.lbx.001 to be looped correctly. This leads to
the somewhat strange notion that all images loop, just that some simply loop
over the last frame.
Also update lbx_getinfo() to reflect the new information.
#include <stdlib.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdint.h>
#include <assert.h>
#include <errno.h>
#include <assert.h>
#include <errno.h>
#include "lbx.h"
#include "image.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;
struct lbx_image {
uint16_t width, height;
uint16_t wtf1;
- uint16_t offs, frames;
- uint16_t pal;
+ uint16_t frames, leadin;
+ uint16_t flags;
struct lbx_image *lbximg_fopen(FILE *f)
{
struct lbx_image tmp = {.f = f}, *new = NULL;
struct lbx_image *lbximg_fopen(FILE *f)
{
struct lbx_image tmp = {.f = f}, *new = NULL;
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.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.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.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.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. */
/* Format constraints. */
- if (tmp.offs <= tmp.frames) {
+ if (tmp.frames <= tmp.leadin) {
lbx_errno = LBX_EFORMAT;
return NULL;
}
lbx_errno = LBX_EFORMAT;
return NULL;
}
* assumptions.
*/
_lbx_assert(tmp.wtf1 == 0);
* 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;
if (!new) {
lbx_errno = -errno;
return NULL;
*new = tmp;
new->currentframe = -1;
*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)
- new->foff += sizeof *new->offsets * new->offs;
+ new->foff += sizeof *new->offsets * (new->frames+1);
if (img->currentframe > frame)
img->currentframe == -1;
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) {
}
if (img->currentframe != frame) {
int
lbximg_getpalette(struct lbx_image *img, struct lbx_colour palette[static 256])
{
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;
unsigned int i;
size_t rc;
uint8_t entry[4];
/* Do nothing if the image doesn't have embedded palette data. */
uint8_t entry[4];
/* Do nothing if the image doesn't have embedded palette data. */
+ if (!(img->flags & FLAG_PALETTE))
return 0;
/* Palette data is located right after the header. */
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) {
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)
}
void lbximg_close(struct lbx_image *img)
struct lbx_imginfo {
unsigned int width, height;
struct lbx_imginfo {
unsigned int width, height;
+ unsigned int nframes, loopstart;
+ int haspalette;
+ int looping;
};
LBX_IMG *lbximg_fopen(FILE *f);
};
LBX_IMG *lbximg_fopen(FILE *f);