1 /*
2 * OpenBOR - http://www.chronocrash.com
3 * -----------------------------------------------------------------------
4 * All rights reserved, see LICENSE in OpenBOR root for details.
5 *
6 * Copyright (c) 2004 - 2014 OpenBOR Team
7 */
8
9 // Animated GIF player.
10
11 #include <stdio.h>
12 #include <string.h>
13 #include "packfile.h"
14 #include "borendian.h"
15 #include "types.h"
16 #include "screen.h"
17 #include "anigif.h"
18
19 // Animated GIF player.
20
21
readbyte(int handle)22 static unsigned char readbyte(int handle)
23 {
24 unsigned char c = 0;
25 readpackfile(handle, &c, 1);
26 return c;
27 }
28
passgifblock(anigif_info * info,int n)29 static void passgifblock(anigif_info *info, int n)
30 {
31 int len;
32
33 // Skip all contained blocks
34 while((len = readbyte(info->info[n].handle)) != 0)
35 {
36 seekpackfile(info->info[n].handle, len, SEEK_CUR);
37 }
38 }
39
handle_gfx_control(anigif_info * info,int n)40 static void handle_gfx_control(anigif_info *info, int n)
41 {
42 int len;
43 int skip;
44 unsigned char buf[4];
45
46 // Handle all contained blocks
47 while((len = readbyte(info->info[n].handle)) != 0)
48 {
49 skip = len - 4;
50 if(len > 4)
51 {
52 len = 4;
53 }
54 readpackfile(info->info[n].handle, buf, len);
55 if(skip > 0)
56 {
57 seekpackfile(info->info[n].handle, skip, SEEK_CUR);
58 }
59
60 if(buf[0] & 1)
61 {
62 info->info[n].transparent = buf[3];
63 }
64 info->info[n].lastdelay = (buf[2] << 8) | buf[1];
65
66 // disposal = (buf[0]>>2) & 7;
67 // inputflag = (buf[0]>>1) & 1;
68 }
69 }
70
gifextension(anigif_info * info,int n)71 static void gifextension(anigif_info *info, int n)
72 {
73 int function;
74
75 // Get extension function code
76 function = readbyte(info->info[n].handle);
77
78 // Note: function may be repeated multiple times (size, data, size, data)
79 switch(function)
80 {
81 case 0xF9:
82 // Graphic control
83 handle_gfx_control(info, n);
84 return;
85 default:
86 // 0x01 = text
87 // 0xFF = app. extension
88 // 0xFE = comment
89 passgifblock(info, n);
90 return;
91 }
92 }
93
decodegifblock(anigif_info * info,gifblockstruct * gb,int n)94 static int decodegifblock(anigif_info *info, gifblockstruct *gb, int n)
95 {
96
97 unsigned char bits;
98 short bits2;
99 short codesize;
100 short codesize2;
101 short nextcode;
102 short thiscode;
103 short oldtoken;
104 short currentcode;
105 short oldcode;
106 short bitsleft;
107 short blocksize;
108 int line = 0, lineb;
109 int byte = gb->left;
110 int pass = 0;
111 int transparent = info->info[n].transparent;
112 int handle = info->info[n].handle;
113 s_screen *buf = info->gifbuffer[n];
114 int width = buf->width;
115 int height = buf->height;
116 unsigned char *pal = info->info[n].local_pal ? info->info[n].local_pal : info->info[n].global_pal;
117
118 unsigned char *p;
119 unsigned char *u;
120
121 unsigned char *q;
122 unsigned char b[255];
123
124 static unsigned char firstcodestack[4096];
125 static unsigned char lastcodestack[4096];
126 static short codestack[4096];
127
128 static short wordmasktable[] = {0x0000, 0x0001, 0x0003, 0x0007,
129 0x000f, 0x001f, 0x003f, 0x007f,
130 0x00ff, 0x01ff, 0x03ff, 0x07ff,
131 0x0fff, 0x1fff, 0x3fff, 0x7fff
132 };
133
134 static short inctable[] = { 8, 8, 4, 2, 0 };
135 static short startable[] = { 0, 4, 2, 1, 0 };
136
137
138 // get the initial LZW code bits
139 bits = readbyte(handle);
140 if(bits < 2 || bits > 8)
141 {
142 return 0;
143 }
144
145 p = q = b;
146 bitsleft = 8;
147
148 bits2 = 1 << bits;
149 nextcode = bits2 + 2;
150 codesize2 = 1 << (codesize = bits + 1);
151 oldcode = oldtoken = NO_CODE;
152
153 lineb = gb->top * width;
154
155 // loop until something breaks
156 for(;;)
157 {
158 if(bitsleft == 8)
159 {
160 if(++p >= q && (((blocksize = readbyte(handle)) < 1) ||
161 (q = (p = b) + readpackfile(handle, b, blocksize)) < (b + blocksize)))
162 {
163 return 1; // Done
164 }
165 bitsleft = 0;
166 }
167 thiscode = *p;
168 if((currentcode = (codesize + bitsleft)) <= 8)
169 {
170 *p >>= codesize;
171 bitsleft = currentcode;
172 }
173 else
174 {
175 if(++p >= q && (((blocksize = readbyte(handle)) < 1) ||
176 (q = (p = b) + readpackfile(handle, b, blocksize)) < (b + blocksize)))
177 {
178 return 1; // Done
179 }
180
181 thiscode |= *p << (8 - bitsleft);
182 if(currentcode <= 16)
183 {
184 *p >>= (bitsleft = currentcode - 8);
185 }
186 else
187 {
188 if(++p >= q && (((blocksize = readbyte(handle)) < 1) ||
189 (q = (p = b) + readpackfile(handle, b, blocksize)) < (b + blocksize)))
190 {
191 return 1; // Done
192 }
193
194 thiscode |= *p << (16 - bitsleft);
195 *p >>= (bitsleft = currentcode - 16);
196 }
197 }
198 thiscode &= wordmasktable[codesize];
199 currentcode = thiscode;
200
201 if(thiscode == (bits2 + 1))
202 {
203 break;
204 }
205 if(thiscode > nextcode)
206 {
207 return 0; // Bad code
208 }
209
210 if(thiscode == bits2)
211 {
212 nextcode = bits2 + 2;
213 codesize2 = 1 << (codesize = (bits + 1));
214 oldtoken = oldcode = NO_CODE;
215 continue;
216 }
217
218 u = firstcodestack;
219
220 if(thiscode == nextcode)
221 {
222 if(oldcode == NO_CODE)
223 {
224 return 0; // Bad code
225 }
226 *u++ = oldtoken;
227 thiscode = oldcode;
228 }
229
230 while(thiscode >= bits2)
231 {
232 *u++ = lastcodestack [thiscode];
233 thiscode = codestack[thiscode];
234 }
235
236 oldtoken = thiscode;
237 do
238 {
239 if(byte < width && byte >= 0 && gb->top + line >= 0 && line < (height - gb->top) && thiscode != transparent)
240 {
241 switch(buf->pixelformat)
242 {
243 case PIXEL_8:
244 ((unsigned char *)buf->data)[lineb + byte] = thiscode;
245 break;
246 case PIXEL_16:
247 ((unsigned short *)buf->data)[lineb + byte] = ((unsigned short *)pal)[thiscode & 0xff];
248 break;
249 case PIXEL_32:
250 ((unsigned *)buf->data)[lineb + byte] = ((unsigned *)pal)[thiscode & 0xff];
251 //printf("%08x, %02x, %ld\n", ((unsigned*)buf->data)[lineb + byte], thiscode&0xff, info->handle);
252 break;
253 }
254 }
255 byte++;
256 if(byte >= gb->left + gb->width)
257 {
258 byte = gb->left;
259 // check for interlaced image
260 if(gb->flags & 0x40)
261 {
262 line += inctable[pass];
263 if(line >= gb->height)
264 {
265 line = startable[++pass];
266 }
267 }
268 else
269 {
270 ++line;
271 }
272 lineb = width * (gb->top + line);
273 }
274 if (u <= firstcodestack)
275 {
276 break;
277 }
278 thiscode = *--u;
279 }
280 while(1);
281
282 if(nextcode < 4096 && oldcode != NO_CODE)
283 {
284 codestack[nextcode] = oldcode;
285 lastcodestack[nextcode] = oldtoken;
286 if(++nextcode >= codesize2 && codesize < 12)
287 {
288 codesize2 = 1 << ++codesize;
289 }
290 }
291 oldcode = currentcode;
292 }
293
294 return 1;
295 }
296
297
anigif_close(anigif_info * info)298 void anigif_close(anigif_info *info)
299 {
300 int i;
301 for(i = 0; i < 3; i++)
302 {
303 if(info->info[i].handle >= 0)
304 {
305 closepackfile(info->info[i].handle);
306 info->info[i].handle = -1;
307 }
308 if(info->info[i].global_pal)
309 {
310 free(info->info[i].global_pal);
311 info->info[i].global_pal = NULL;
312 }
313 if(info->info[i].local_pal)
314 {
315 free(info->info[i].local_pal);
316 info->info[i].local_pal = NULL;
317 }
318 if(info->gifbuffer[i])
319 {
320 freescreen(&info->gifbuffer[i]);
321 }
322
323 }
324 if(info->backbuffer)
325 {
326 freescreen(&info->backbuffer);
327 }
328 }
329
test_anigif_open(anigif_info * info,char * tname,char * packfilename,int n)330 static int test_anigif_open(anigif_info *info, char *tname, char *packfilename, int n)
331 {
332 int i, j;
333 unsigned char tpal[1024];
334 unsigned char *pal;
335 if(
336 (info->info[n].handle = openpackfile(tname, packfilename)) == -1 ||
337 readpackfile(info->info[n].handle, &info->info[n].gif_header, sizeof_gifheaderstruct) != sizeof_gifheaderstruct ||
338 info->info[n].gif_header.magic[0] != 'G' || info->info[n].gif_header.magic[1] != 'I' || info->info[n].gif_header.magic[2] != 'F'
339 )
340 {
341 anigif_close(info);
342 return 0;
343 }
344
345 info->info[n].gif_header.screenwidth = SwapLSB16(info->info[n].gif_header.screenwidth);
346 info->info[n].gif_header.screenheight = SwapLSB16(info->info[n].gif_header.screenheight);
347
348 if(info->info[n].gif_header.flags & 0x80)
349 {
350 info->info[n].bitdepth = (info->info[n].gif_header.flags & 7) + 1;
351 info->info[n].numcolours = 1 << info->info[n].bitdepth ;
352 }
353 else
354 {
355 info->info[n].bitdepth = 8;
356 info->info[n].numcolours = 0;
357 }
358 info->info[n].lastdelay = 1;
359 info->info[n].code = ANIGIF_DECODE_RETRY;
360
361 //info->current_res[0] = SwapLSB16(info->gif_header.screenwidth);
362 //info->current_res[1] = SwapLSB16(info->gif_header.screenheight);
363
364 //printf("numcolours:%d\n", info->numcolours);
365
366 // Get global palette, if present and if wanted
367 if(info->info[n].gif_header.flags & 0x80)
368 {
369 pal = info->info[n].global_pal = calloc(1, PAL_BYTES);
370
371 if(readpackfile(info->info[n].handle, tpal, info->info[n].numcolours * 3) != info->info[n].numcolours * 3)
372 {
373 anigif_close(info);
374 return 0;
375 }
376 if(!info->isRGB)
377 {
378 tpal[0] = tpal[1] = tpal[2] = 0;
379 }
380 switch(PAL_BYTES)
381 {
382 case 768:
383 memcpy(pal, tpal, 768);
384 break;
385 case 1024:
386 for(i = 0, j = 0; i < 1024; i += 4, j += 3)
387 {
388 *(unsigned *)(pal + i) = colour32(tpal[j], tpal[j + 1], tpal[j + 2]);
389 }
390 break;
391 case 512:
392 for(i = 0, j = 0; i < 512; i += 2, j += 3)
393 {
394 *(unsigned short *)(pal + i) = colour16(tpal[j], tpal[j + 1], tpal[j + 2]);
395 }
396 break;
397 }
398 }
399 return 1;
400
401 }
402
403
404 // Returns true on success
anigif_open(char * filename,char * packfilename,anigif_info * info)405 int anigif_open(char *filename, char *packfilename, anigif_info *info)
406 {
407 char tname[256] = {""};
408 int i;
409
410 memset(info, 0, sizeof(anigif_info));
411 info->isRGB = (pixelformat == PIXEL_x8);
412 strcpy(tname, filename);
413 if(stricmp(tname + strlen(tname) - 4, ".gif") == 0)
414 {
415 tname[strlen(tname) - 4] = 0;
416 }
417
418 strcat(tname, "_.gif");
419
420 if(info->isRGB)
421 {
422 tname[strlen(tname) - 5] = 'r';
423 if(testpackfile(tname, packfilename) < 0)
424 {
425 info->isRGB = 0;
426 }
427 tname[strlen(tname) - 5] = 'g';
428 if(testpackfile(tname, packfilename) < 0)
429 {
430 info->isRGB = 0;
431 }
432 tname[strlen(tname) - 5] = 'b';
433 if(testpackfile(tname, packfilename) < 0)
434 {
435 info->isRGB = 0;
436 }
437 }
438
439 for(i = 0; i < 3; i++)
440 {
441 info->info[i].handle = -1;
442 info->info[i].transparent = -1;
443 }
444
445 if(info->isRGB)
446 {
447 tname[strlen(tname) - 5] = 'r';
448 if(!test_anigif_open(info, tname, packfilename, 0))
449 {
450 return 0;
451 }
452 tname[strlen(tname) - 5] = 'g';
453 if(!test_anigif_open(info, tname, packfilename, 1))
454 {
455 return 0;
456 }
457 tname[strlen(tname) - 5] = 'b';
458 if(!test_anigif_open(info, tname, packfilename, 2))
459 {
460 return 0;
461 }
462 }
463 else
464 {
465 if(!test_anigif_open(info, filename, packfilename, 0))
466 {
467 return 0;
468 }
469 }
470
471 if(info->isRGB)
472 {
473 info->backbuffer = allocscreen(info->info[0].gif_header.screenwidth, info->info[0].gif_header.screenheight, screenformat);
474 clearscreen(info->backbuffer);
475 }
476 for(i = info->isRGB ? 2 : 0; i >= 0; i--)
477 {
478 info->gifbuffer[i] = allocscreen(info->info[0].gif_header.screenwidth, info->info[0].gif_header.screenheight, screenformat);
479 clearscreen(info->gifbuffer[i]);
480 }
481 info->frame = -1;
482 return 1;
483 }
484
485
486 // Returns type of action to take (frame, retry, end)
anigif_decode(anigif_info * info,int n)487 int anigif_decode(anigif_info *info, int n)
488 {
489
490 gifblockstruct iblock;
491 unsigned char tpal[1024];
492 unsigned char *pal;
493 unsigned char c;
494 int i, j, numcolours;
495
496 if(info->info[n].handle < 0 || info->gifbuffer[n] == NULL ||
497 readpackfile(info->info[n].handle, &c, 1) != 1)
498 {
499 goto decode_end;
500 }
501
502 switch(c)
503 {
504 case ',':
505 // An image block
506 if(readpackfile(info->info[n].handle, &iblock, sizeof_iblock) != sizeof_iblock)
507 {
508 goto decode_end;
509 }
510
511 if(iblock.flags & 0x80)
512 {
513 if(!info->info[n].local_pal)
514 {
515 info->info[n].local_pal = calloc(1, PAL_BYTES);
516 }
517 pal = info->info[n].local_pal;
518 numcolours = 1 << ((iblock.flags & 7) + 1);
519 if(readpackfile(info->info[n].handle, tpal, numcolours * 3) != numcolours * 3)
520 {
521 goto decode_end;
522 }
523 if(!info->isRGB)
524 {
525 tpal[0] = tpal[1] = tpal[2] = 0;
526 }
527 switch(PAL_BYTES)
528 {
529 case 768:
530 memcpy(pal, tpal, 768);
531 break;
532 case 1024:
533 for(i = 0, j = 0; i < 1024; i += 4, j += 3)
534 {
535 *(unsigned *)(pal + i) = colour32(tpal[j], tpal[j + 1], tpal[j + 2]);
536 }
537 break;
538 case 512:
539 for(i = 0, j = 0; i < 512; i += 2, j += 3)
540 {
541 *(unsigned short *)(pal + i) = colour16(tpal[j], tpal[j + 1], tpal[j + 2]);
542 //printf("%d*", *(unsigned short*)(pal+i));
543 }
544 break;
545 }
546 }
547 else if (info->info[n].local_pal)
548 {
549 free(info->info[n].local_pal);
550 info->info[n].local_pal = NULL;
551 }
552
553 iblock.left = SwapLSB16(iblock.left);
554 iblock.top = SwapLSB16(iblock.top);
555 iblock.width = SwapLSB16(iblock.width);
556 iblock.height = SwapLSB16(iblock.height);
557
558 decodegifblock(info, &iblock, n);
559
560 // lastdelay = 0;
561
562 return ANIGIF_DECODE_FRAME | ((iblock.flags & 0x80) ? ANIGIF_DECODE_PAL : 0);
563
564 case '!':
565 // Handle GIF extension
566 gifextension(info, n);
567 // if(delay) *delay = lastdelay;
568 // lastdelay = 0;
569 return ANIGIF_DECODE_RETRY;
570
571 // case 0:
572 default:
573 // Isn't this an EOF?
574 return ANIGIF_DECODE_RETRY;
575 // anigif_close();
576 // return ANIGIF_DECODE_END;
577 }
578
579 decode_end:
580 //anigif_close(info);
581 return ANIGIF_DECODE_END;
582 }
583
anigif_updatebuffer(anigif_info * info)584 static void anigif_updatebuffer(anigif_info *info)
585 {
586 s_screen *backbuffer = info->backbuffer;
587 s_screen **gifbuffer = info->gifbuffer;
588 int i, l = backbuffer->width * backbuffer->height;
589 unsigned short *ps16, *ppr16, *ppg16, *ppb16;
590 unsigned int *ps32, *ppr32, *ppg32, *ppb32;
591 switch(screenformat)
592 {
593 case PIXEL_16:
594 ps16 = (unsigned short *)(backbuffer->data);
595 ppr16 = (unsigned short *)(gifbuffer[0]->data);
596 ppg16 = (unsigned short *)(gifbuffer[1]->data);
597 ppb16 = (unsigned short *)(gifbuffer[2]->data);
598 for(i = 0; i < l; i++)
599 {
600 ps16[i] = ppr16[i] | ppg16[i] | ppb16[i];
601 }
602 break;
603 case PIXEL_32:
604 ps32 = (unsigned int *)(backbuffer->data);
605 ppr32 = (unsigned int *)(gifbuffer[0]->data);
606 ppg32 = (unsigned int *)(gifbuffer[1]->data);
607 ppb32 = (unsigned int *)(gifbuffer[2]->data);
608 for(i = 0; i < l; i++)
609 {
610 ps32[i] = ppr32[i] | ppg32[i] | ppb32[i];
611 //printf(" %u %u %u\n", ppr32[i], ppg32[i], ppb32[i]);
612 }
613 break;
614 }
615
616 }
617
anigif_decode_frame(anigif_info * info)618 int anigif_decode_frame(anigif_info *info)
619 {
620 int n, num = info->isRGB ? 3 : 1;
621 if(!info->done)
622 {
623 for(n = 0; n < num; n++)
624 {
625 if(info->info[n].code != ANIGIF_DECODE_END)
626 {
627 while((info->info[n].code = anigif_decode(info, n)) == ANIGIF_DECODE_RETRY);
628 info->info[n].nextframe += info->info[n].lastdelay * 10;
629 }
630 if(info->info[n].code == ANIGIF_DECODE_END)
631 {
632 info->done = 1;
633 break;
634 }
635 }
636 if(!info->done)
637 {
638 if(info->isRGB)
639 {
640 anigif_updatebuffer(info);
641 }
642 info->frame++;
643 }
644 }
645 return info->done;
646 }
647
648
anigif_getbuffer(anigif_info * info)649 s_screen *anigif_getbuffer(anigif_info *info)
650 {
651 s_screen *buffer = info->isRGB ? info->backbuffer : info->gifbuffer[0];
652 if(buffer)
653 {
654 buffer->palette = info->isRGB ? NULL : (info->info[0].local_pal ? info->info[0].local_pal : info->info[0].global_pal);
655 }
656 return buffer;
657 }
658
659
660