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