1 #include <stdlib.h>
2 #include <string.h>
3 #include <unistd.h>
4 
5 #include "shadowdive/internal/reader.h"
6 #include "shadowdive/internal/writer.h"
7 #include "shadowdive/palette.h"
8 #include "shadowdive/rgba_image.h"
9 #include "shadowdive/vga_image.h"
10 #include "shadowdive/animation.h"
11 #include "shadowdive/bkanim.h"
12 #include "shadowdive/error.h"
13 #include "shadowdive/bk.h"
14 
sd_bk_create(sd_bk_file * bk)15 int sd_bk_create(sd_bk_file *bk) {
16     if(bk == NULL) {
17         return SD_INVALID_INPUT;
18     }
19 
20     // Clear everything
21     memset(bk, 0, sizeof(sd_bk_file));
22     return SD_SUCCESS;
23 }
24 
sd_bk_copy(sd_bk_file * dst,const sd_bk_file * src)25 int sd_bk_copy(sd_bk_file *dst, const sd_bk_file *src) {
26     int ret;
27     if(dst == NULL || src == NULL) {
28         return SD_INVALID_INPUT;
29     }
30 
31     // Clear everything
32     memset(dst, 0, sizeof(sd_bk_file));
33 
34     // Int stuff
35     dst->file_id = src->file_id;
36     dst->unknown_a = src->unknown_a;
37     dst->palette_count = src->palette_count;
38 
39     // Copy sounds
40     memcpy(dst->soundtable, src->soundtable, sizeof(src->soundtable));
41 
42     // Copy animations
43     for(int i = 0; i < MAX_BK_ANIMS; i++) {
44         if(src->anims[i] != NULL) {
45             if((dst->anims[i] = malloc(sizeof(sd_bk_anim))) == NULL) {
46                 return SD_OUT_OF_MEMORY;
47             }
48             if((ret = sd_bk_anim_copy(dst->anims[i], src->anims[i])) != SD_SUCCESS) {
49                 return ret;
50             }
51         }
52     }
53 
54     // Copy background
55     if(src->background != NULL) {
56         if((dst->background = malloc(sizeof(sd_vga_image))) == NULL) {
57             return SD_OUT_OF_MEMORY;
58         }
59         if((ret = sd_vga_image_copy(dst->background, src->background)) != SD_SUCCESS) {
60             return ret;
61         }
62     }
63 
64     // Copy palettes
65     for(int i = 0; i < MAX_BK_PALETTES; i++) {
66         dst->palettes[i] = NULL;
67         if(src->palettes[i] != NULL) {
68             if((dst->palettes[i] = malloc(sizeof(sd_palette))) == NULL) {
69                 return SD_OUT_OF_MEMORY;
70             }
71             memcpy(dst->palettes[i], src->palettes[i], sizeof(sd_palette));
72         }
73     }
74 
75     return SD_SUCCESS;
76 }
77 
sd_bk_postprocess(sd_bk_file * bk)78 void sd_bk_postprocess(sd_bk_file *bk) {
79     char *table[1000] = {0}; // temporary lookup table
80     sd_animation *anim;
81     // fix NULL pointers for any 'missing' sprites
82     for(int i = 0; i < MAX_BK_ANIMS; i++) {
83         if(bk->anims[i] != NULL) {
84             anim = bk->anims[i]->animation;
85             for(int j = 0; j < anim->sprite_count; j++) {
86                 if(anim->sprites[j]->missing > 0) {
87                     if(table[anim->sprites[j]->index]) {
88                         anim->sprites[j]->data = table[anim->sprites[j]->index];
89                     }
90                 } else {
91                     table[anim->sprites[j]->index] = anim->sprites[j]->data;
92                 }
93             }
94         }
95     }
96 }
97 
sd_bk_load(sd_bk_file * bk,const char * filename)98 int sd_bk_load(sd_bk_file *bk, const char *filename) {
99     uint16_t img_w, img_h;
100     uint8_t animno = 0;
101     sd_reader *r;
102     int ret = SD_SUCCESS;
103 
104     // Initialize reader
105     if(!(r = sd_reader_open(filename))) {
106         return SD_FILE_OPEN_ERROR;
107     }
108 
109     // Header
110     bk->file_id = sd_read_udword(r);
111     bk->unknown_a = sd_read_ubyte(r);
112     img_w = sd_read_uword(r);
113     img_h = sd_read_uword(r);
114 
115     // Read animations
116     while(1) {
117         sd_skip(r, 4); // offset of next animation
118         animno = sd_read_ubyte(r);
119         if(animno >= MAX_BK_ANIMS || !sd_reader_ok(r)) {
120             break;
121         }
122 
123         // Initialize animation
124         if((bk->anims[animno] = malloc(sizeof(sd_bk_anim))) == NULL) {
125             ret = SD_OUT_OF_MEMORY;
126             goto exit_0;
127         }
128         if((ret = sd_bk_anim_create(bk->anims[animno])) != SD_SUCCESS) {
129             goto exit_0;
130         }
131         if((ret = sd_bk_anim_load(r, bk->anims[animno])) != SD_SUCCESS) {
132             goto exit_0;
133         }
134     }
135 
136     // Read background image
137     if((bk->background = malloc(sizeof(sd_vga_image))) == NULL) {
138         ret = SD_OUT_OF_MEMORY;
139         goto exit_0;
140     }
141     if((ret = sd_vga_image_create(bk->background, img_w, img_h)) != SD_SUCCESS) {
142         goto exit_0;
143     }
144     int bsize = img_w * img_h;
145     sd_read_buf(r, bk->background->data, bsize);
146 
147     // Read palettes
148     bk->palette_count = sd_read_ubyte(r);
149     for(uint8_t i = 0; i < bk->palette_count; i++) {
150         if((bk->palettes[i] = malloc(sizeof(sd_palette))) == NULL) {
151             ret = SD_OUT_OF_MEMORY;
152             goto exit_0;
153         }
154         if((ret = sd_palette_load(r, bk->palettes[i])) != SD_SUCCESS) {
155             goto exit_0;
156         }
157     }
158 
159     // Read soundtable
160     sd_read_buf(r, bk->soundtable, 30);
161 
162     // Fix missing sprites
163     sd_bk_postprocess(bk);
164 
165 exit_0:
166     sd_reader_close(r);
167     return ret;
168 }
169 
sd_bk_save(const sd_bk_file * bk,const char * filename)170 int sd_bk_save(const sd_bk_file *bk, const char* filename) {
171     long rpos = 0;
172     long opos = 0;
173     sd_writer *w;
174     int ret;
175 
176     if(!(w = sd_writer_open(filename))) {
177         return SD_FILE_OPEN_ERROR;
178     }
179 
180     // Write header
181     sd_write_udword(w, bk->file_id);
182     sd_write_ubyte(w, bk->unknown_a);
183 
184     // Write background size. In practice, this is always 320x200.
185     // Still, let's take it srsly.
186     if(bk->background != NULL) {
187         sd_write_uword(w, bk->background->w);
188         sd_write_uword(w, bk->background->h);
189     } else {
190         sd_write_uword(w, 320);
191         sd_write_uword(w, 200);
192     }
193 
194     // Write animations
195     for(uint8_t i = 0; i < MAX_BK_ANIMS; i++) {
196         if(bk->anims[i] != NULL) {
197             opos = sd_writer_pos(w); // remember where we need to fill in the blank
198             if (opos < 0) {
199                 goto error;
200             }
201             sd_write_udword(w, 0); // write a 0 as a placeholder
202             sd_write_ubyte(w, i);
203             if((ret = sd_bk_anim_save(w, bk->anims[i])) != SD_SUCCESS) {
204                 sd_writer_close(w);
205                 return ret;
206             }
207             rpos = sd_writer_pos(w);
208             if (rpos < 0) {
209                 goto error;
210             }
211             if (sd_writer_seek_start(w, opos) < 0) {
212                 goto error;
213             }
214             sd_write_udword(w, rpos); // write the actual size
215             if (sd_writer_seek_start(w, rpos) < 0) {
216                 goto error;
217             }
218         }
219     }
220     sd_write_udword(w, rpos);
221     sd_write_ubyte(w, MAX_BK_ANIMS+1); // indicate end of animations
222 
223     // Write background image. If none exists, write black image.
224     if(bk->background != NULL) {
225         sd_write_buf(w, bk->background->data, bk->background->len);
226     } else {
227         sd_write_fill(w, 0, 64000);
228     }
229 
230     // Write palettes
231     sd_write_ubyte(w, bk->palette_count);
232     for(uint8_t i = 0; i < bk->palette_count; i++) {
233         sd_palette_save(w, bk->palettes[i]);
234     }
235 
236     // Write soundtable
237     sd_write_buf(w, bk->soundtable, 30);
238 
239     if (sd_writer_errno(w)) {
240         goto error;
241     }
242 
243     // All done, close writer
244     sd_writer_close(w);
245     return SD_SUCCESS;
246 
247 error:
248     unlink(filename);
249     sd_writer_close(w);
250     return SD_FILE_WRITE_ERROR;
251 }
252 
sd_bk_set_background(sd_bk_file * bk,const sd_vga_image * img)253 int sd_bk_set_background(sd_bk_file *bk, const sd_vga_image *img) {
254     int ret;
255     if(bk == NULL) {
256         return SD_INVALID_INPUT;
257     }
258     if(bk->background != NULL) {
259         sd_vga_image_free(bk->background);
260         free(bk->background);
261     }
262     if(img == NULL) {
263         return SD_SUCCESS;
264     }
265     if((bk->background = malloc(sizeof(sd_vga_image))) == NULL) {
266         return SD_OUT_OF_MEMORY;
267     }
268     if((ret = sd_vga_image_copy(bk->background, img)) != SD_SUCCESS) {
269         return ret;
270     }
271     return SD_SUCCESS;
272 }
273 
sd_bk_get_background(const sd_bk_file * bk)274 sd_vga_image* sd_bk_get_background(const sd_bk_file *bk) {
275     return bk->background;
276 }
277 
sd_bk_set_anim(sd_bk_file * bk,int index,const sd_bk_anim * anim)278 int sd_bk_set_anim(sd_bk_file *bk, int index, const sd_bk_anim *anim) {
279     int ret;
280     if(index < 0 || index >= MAX_BK_ANIMS || bk == NULL) {
281         return SD_INVALID_INPUT;
282     }
283     if(bk->anims[index] != NULL) {
284         sd_bk_anim_free(bk->anims[index]);
285         free(bk->anims[index]);
286         bk->anims[index] = NULL;
287     }
288     // If input was NULL, we want to stop here.
289     if(anim == NULL) {
290         return SD_SUCCESS;
291     }
292     if((bk->anims[index] = malloc(sizeof(sd_bk_anim))) == NULL) {
293         return SD_OUT_OF_MEMORY;
294     }
295     if((ret = sd_bk_anim_copy(bk->anims[index], anim)) != SD_SUCCESS) {
296         return ret;
297     }
298     return SD_SUCCESS;
299 }
300 
sd_bk_get_anim(const sd_bk_file * bk,int index)301 sd_bk_anim* sd_bk_get_anim(const sd_bk_file *bk, int index) {
302     if(index < 0 || index >= MAX_BK_ANIMS || bk == NULL) {
303         return NULL;
304     }
305     return bk->anims[index];
306 }
307 
sd_bk_set_palette(sd_bk_file * bk,int index,const sd_palette * palette)308 int sd_bk_set_palette(sd_bk_file *bk, int index, const sd_palette *palette) {
309     if(index < 0 || bk == NULL || index >= bk->palette_count || palette == NULL) {
310         return SD_INVALID_INPUT;
311     }
312     if(bk->palettes[index] != NULL) {
313         free(bk->palettes[index]);
314     }
315     if((bk->palettes[index] = malloc(sizeof(sd_palette))) == NULL) {
316         return SD_OUT_OF_MEMORY;
317     }
318     memcpy(bk->palettes[index], palette, sizeof(sd_palette));
319     return SD_SUCCESS;
320 }
321 
sd_bk_pop_palette(sd_bk_file * bk)322 int sd_bk_pop_palette(sd_bk_file *bk) {
323     if(bk == NULL || bk->palette_count <= 0) {
324         return SD_INVALID_INPUT;
325     }
326 
327     bk->palette_count--;
328     free(bk->palettes[bk->palette_count]);
329     bk->palettes[bk->palette_count] = NULL;
330 
331     return SD_SUCCESS;
332 }
333 
sd_bk_push_palette(sd_bk_file * bk,const sd_palette * palette)334 int sd_bk_push_palette(sd_bk_file *bk, const sd_palette *palette) {
335     if(bk == NULL || palette == NULL || bk->palette_count >= MAX_BK_PALETTES) {
336         return SD_INVALID_INPUT;
337     }
338     if(bk->palettes[bk->palette_count] != NULL) {
339         free(bk->palettes[bk->palette_count]);
340     }
341     if((bk->palettes[bk->palette_count] = malloc(sizeof(sd_palette))) == NULL) {
342         return SD_OUT_OF_MEMORY;
343     }
344     memcpy(bk->palettes[bk->palette_count], palette, sizeof(sd_palette));
345     bk->palette_count++;
346 
347     return SD_SUCCESS;
348 }
349 
sd_bk_get_palette(const sd_bk_file * bk,int index)350 sd_palette* sd_bk_get_palette(const sd_bk_file *bk, int index) {
351     if(bk == NULL || index < 0 || index >= bk->palette_count) {
352         return NULL;
353     }
354     return bk->palettes[index];
355 }
356 
sd_bk_free(sd_bk_file * bk)357 void sd_bk_free(sd_bk_file *bk) {
358     int i;
359     if(bk->background != NULL) {
360         sd_vga_image_free(bk->background);
361         free(bk->background);
362     }
363     for(i = 0; i < MAX_BK_ANIMS; i++) {
364         if(bk->anims[i] != NULL) {
365             sd_bk_anim_free(bk->anims[i]);
366             free(bk->anims[i]);
367         }
368     }
369     for(i = 0; i < bk->palette_count; i++) {
370         if(bk->palettes[i] != NULL) {
371             free(bk->palettes[i]);
372         }
373     }
374 }
375