moving to RLE sprites instead of compiled sprites
[eradicate] / src / sprite.c
diff --git a/src/sprite.c b/src/sprite.c
new file mode 100644 (file)
index 0000000..067c41c
--- /dev/null
@@ -0,0 +1,136 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include "inttypes.h"
+#include "sprite.h"
+#include "util.h"
+
+#pragma pack (push, 1)
+struct file_header {
+       char magic[8];
+       uint16_t width, height, bpp;
+       uint16_t count;
+} PACKED;
+#pragma pack (pop)
+
+
+static int read_sprite(struct sprite *spr, int pixsz, FILE *fp);
+
+
+void destroy_sprites(struct sprites *ss)
+{
+       int i;
+
+       for(i=0; i<ss->num_sprites; i++) {
+               free(ss->sprites[i].ops);
+       }
+       free(ss->sprites);
+}
+
+int load_sprites(struct sprites *ss, const char *fname)
+{
+       int i;
+       FILE *fp;
+       struct file_header hdr;
+
+       ss->sprites = 0;
+
+       if(!(fp = fopen(fname, "rb"))) {
+               fprintf(stderr, "failed to load sprites from %s: %s\n", fname, strerror(errno));
+               return -1;
+       }
+       if(fread(&hdr, sizeof hdr, 1, fp) <= 0) {
+               fprintf(stderr, "unexpected EOF while reading from %s\n", fname);
+               goto err;
+       }
+       if(memcmp(hdr.magic, "RLESPRIT", sizeof hdr.magic) != 0) {
+               fprintf(stderr, "invalid magic in %s\n", fname);
+               goto err;
+       }
+
+       ss->width = hdr.width;
+       ss->height = hdr.height;
+       ss->bpp = hdr.bpp;
+       ss->num_sprites = hdr.count;
+
+       if(!(ss->sprites = malloc(hdr.count * sizeof *ss->sprites))) {
+               fprintf(stderr, "failed to allocate %d sprites for %s\n", hdr.count, fname);
+               goto err;
+       }
+
+       for(i=0; i<ss->num_sprites; i++) {
+               if(read_sprite(ss->sprites + i, (hdr.bpp + 7) / 8, fp) == -1) {
+                       goto err;
+               }
+       }
+
+       fclose(fp);
+       return 0;
+
+err:
+       free(ss->sprites);
+       fclose(fp);
+       return -1;
+}
+
+static int read_sprite(struct sprite *spr, int pixsz, FILE *fp)
+{
+       int i, idx, max_ops, newmax, len, bufsz;
+       void *tmp;
+       uint32_t op;
+
+       spr->ops = 0;
+       spr->num_ops = max_ops = 0;
+
+       do {
+               /* read the op */
+               if(fread(&op, sizeof op, 1, fp) <= 0) {
+                       free(spr->ops);
+                       return -1;
+               }
+
+               /* realloc ops array if necessary */
+               if(spr->num_ops >= max_ops) {
+                       newmax = max_ops ? max_ops << 1 : 16;
+                       if(!(tmp = realloc(spr->ops, newmax * sizeof *spr->ops))) {
+                               fprintf(stderr, "failed to add sprite op (newmax: %d)\n", newmax);
+                               goto err;
+                       }
+                       spr->ops = tmp;
+                       max_ops = newmax;
+               }
+
+               /* append */
+               idx = spr->num_ops++;
+               spr->ops[idx].op = SOP_OP(op);
+               len = SOP_LEN(op);
+               bufsz = len * pixsz;
+               spr->ops[idx].size = bufsz;
+
+               /* if the op was copy, we need to grab the pixel data */
+               if(SOP_OP(op) == SOP_COPY) {
+                       if(!(tmp = malloc(bufsz))) {
+                               fprintf(stderr, "failed to allocate sprite pixel data (%d bytes)\n", bufsz);
+                               goto err;
+                       }
+                       if(fread(tmp, 1, bufsz, fp) < bufsz) {
+                               fprintf(stderr, "unexpected EOF while trying to read sprite data (%d pixels)\n", len);
+                               goto err;
+                       }
+                       spr->ops[idx].data = tmp;
+               } else {
+                       spr->ops[idx].data = 0;
+               }
+
+       } while(SOP_OP(op) != SOP_END);
+
+       return 0;
+
+err:
+       for(i=0; i<spr->num_ops; i++) {
+               free(spr->ops[i].data);
+       }
+       free(spr->ops);
+       return -1;
+}