moving to RLE sprites instead of compiled sprites
[eradicate] / src / sprite.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <errno.h>
5 #include "inttypes.h"
6 #include "sprite.h"
7 #include "util.h"
8
9 #pragma pack (push, 1)
10 struct file_header {
11         char magic[8];
12         uint16_t width, height, bpp;
13         uint16_t count;
14 } PACKED;
15 #pragma pack (pop)
16
17
18 static int read_sprite(struct sprite *spr, int pixsz, FILE *fp);
19
20
21 void destroy_sprites(struct sprites *ss)
22 {
23         int i;
24
25         for(i=0; i<ss->num_sprites; i++) {
26                 free(ss->sprites[i].ops);
27         }
28         free(ss->sprites);
29 }
30
31 int load_sprites(struct sprites *ss, const char *fname)
32 {
33         int i;
34         FILE *fp;
35         struct file_header hdr;
36
37         ss->sprites = 0;
38
39         if(!(fp = fopen(fname, "rb"))) {
40                 fprintf(stderr, "failed to load sprites from %s: %s\n", fname, strerror(errno));
41                 return -1;
42         }
43         if(fread(&hdr, sizeof hdr, 1, fp) <= 0) {
44                 fprintf(stderr, "unexpected EOF while reading from %s\n", fname);
45                 goto err;
46         }
47         if(memcmp(hdr.magic, "RLESPRIT", sizeof hdr.magic) != 0) {
48                 fprintf(stderr, "invalid magic in %s\n", fname);
49                 goto err;
50         }
51
52         ss->width = hdr.width;
53         ss->height = hdr.height;
54         ss->bpp = hdr.bpp;
55         ss->num_sprites = hdr.count;
56
57         if(!(ss->sprites = malloc(hdr.count * sizeof *ss->sprites))) {
58                 fprintf(stderr, "failed to allocate %d sprites for %s\n", hdr.count, fname);
59                 goto err;
60         }
61
62         for(i=0; i<ss->num_sprites; i++) {
63                 if(read_sprite(ss->sprites + i, (hdr.bpp + 7) / 8, fp) == -1) {
64                         goto err;
65                 }
66         }
67
68         fclose(fp);
69         return 0;
70
71 err:
72         free(ss->sprites);
73         fclose(fp);
74         return -1;
75 }
76
77 static int read_sprite(struct sprite *spr, int pixsz, FILE *fp)
78 {
79         int i, idx, max_ops, newmax, len, bufsz;
80         void *tmp;
81         uint32_t op;
82
83         spr->ops = 0;
84         spr->num_ops = max_ops = 0;
85
86         do {
87                 /* read the op */
88                 if(fread(&op, sizeof op, 1, fp) <= 0) {
89                         free(spr->ops);
90                         return -1;
91                 }
92
93                 /* realloc ops array if necessary */
94                 if(spr->num_ops >= max_ops) {
95                         newmax = max_ops ? max_ops << 1 : 16;
96                         if(!(tmp = realloc(spr->ops, newmax * sizeof *spr->ops))) {
97                                 fprintf(stderr, "failed to add sprite op (newmax: %d)\n", newmax);
98                                 goto err;
99                         }
100                         spr->ops = tmp;
101                         max_ops = newmax;
102                 }
103
104                 /* append */
105                 idx = spr->num_ops++;
106                 spr->ops[idx].op = SOP_OP(op);
107                 len = SOP_LEN(op);
108                 bufsz = len * pixsz;
109                 spr->ops[idx].size = bufsz;
110
111                 /* if the op was copy, we need to grab the pixel data */
112                 if(SOP_OP(op) == SOP_COPY) {
113                         if(!(tmp = malloc(bufsz))) {
114                                 fprintf(stderr, "failed to allocate sprite pixel data (%d bytes)\n", bufsz);
115                                 goto err;
116                         }
117                         if(fread(tmp, 1, bufsz, fp) < bufsz) {
118                                 fprintf(stderr, "unexpected EOF while trying to read sprite data (%d pixels)\n", len);
119                                 goto err;
120                         }
121                         spr->ops[idx].data = tmp;
122                 } else {
123                         spr->ops[idx].data = 0;
124                 }
125
126         } while(SOP_OP(op) != SOP_END);
127
128         return 0;
129
130 err:
131         for(i=0; i<spr->num_ops; i++) {
132                 free(spr->ops[i].data);
133         }
134         free(spr->ops);
135         return -1;
136 }