2 Copyright (C) 1998 BJ Eirich (aka vecna)
\r
3 This program is free software; you can redistribute it and/or
\r
4 modify it under the terms of the GNU General Public License
\r
5 as published by the Free Software Foundation; either version 2
\r
6 of the License, or (at your option) any later version.
\r
7 This program is distributed in the hope that it will be useful,
\r
8 but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
\r
10 See the GNU General Public Lic
\r
11 See the GNU General Public License for more details.
\r
12 You should have received a copy of the GNU General Public License
\r
13 along with this program; if not, write to the Free Software
\r
14 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
\r
20 #include <sys/stat.h>
\r
25 // ================================= Data ====================================
\r
28 #define INT_MAX 0xFFFFFFFF
\r
33 #define MIN(x,y) (((x) < (y)) ? (x) : (y))
\r
34 #define MAX(x,y) (((x) > (y)) ? (x) : (y))
\r
35 #define MID(x,y,z) MAX((x), MIN((y), (z)))
\r
39 #define ABS(x) (((x) >= 0) ? (x) : (-(x)))
\r
43 #define SGN(x) (((x) >= 0) ? 1 : -1)
\r
46 #define FLI_MAGIC 0xAF11 // file header magic number
\r
47 #define FLC_MAGIC 0xAF12 // file magic number (Pro)
\r
48 #define FLI_FRAME_MAGIC 0xF1FA // frame header magic number
\r
49 #define FLI_FRAME_PREFIX 0xF100 // FLC's prefix info
\r
50 #define FLI_FRAME_USELESS 0x00A1 // FLC's garbage frame
\r
58 #define FLI_OK 0 /* FLI player return values */
\r
60 #define FLI_ERROR -2
\r
61 #define FLI_NOT_OPEN -3
\r
69 #define PACKED __attribute__ ((packed))
\r
76 word frame_count PACKED;
\r
82 long next_head PACKED;
\r
83 long frames_in_table PACKED;
\r
84 char reserved[102] PACKED;
\r
105 static int fli_status = FLI_NOT_OPEN; // current state of the FLI player
\r
107 int fli_bitmap_width = 0;
\r
108 int fli_bitmap_height = 0;
\r
109 byte *fli_bitmap_data = NULL; // current frame of the FLI
\r
110 byte fli_palette[768]; // current palette the FLI is using
\r
112 int fli_bmp_dirty_from = INT_MAX; // what part of fli_bitmap is dirty
\r
113 int fli_bmp_dirty_to = INT_MIN;
\r
114 int fli_pal_dirty_from = INT_MAX; // what part of fli_palette is dirty
\r
115 int fli_pal_dirty_to = INT_MIN;
\r
117 int fli_frame = 0; // current frame number in the FLI
\r
120 static int fli_file = 0; // the file we are reading
\r
122 static byte *fli_mem_data = NULL; // the memory FLI we are playing
\r
123 static int fli_mem_pos = 0; // position in the memory FLI
\r
125 static FLI_HEADER fli_header; // header structure
\r
126 static FLI_FRAME frame_header; // frame header structure
\r
128 // a block of temporary working memory
\r
129 byte *_scratch_mem = NULL;
\r
130 int _scratch_mem_size = 0;
\r
132 // ================================= Code ====================================
\r
134 void reset_fli_variables(void);
\r
135 void close_fli(void);
\r
136 int next_fli_frame(int);
\r
137 int open_fli(char *);
\r
138 int open_memory_fli(byte *);
\r
140 void _grow_scratch_mem(int size)
\r
142 if (size > _scratch_mem_size) {
\r
143 size = (size+1023) & 0xFFFFFC00;
\r
144 _scratch_mem = realloc(_scratch_mem, size);
\r
145 _scratch_mem_size = size;
\r
151 while (!(inp(986) & 8));
\r
154 void set_palette_range(byte *pal, int from, int to, int sync)
\r
159 if (to<from) { int t=from; from=to; to=t; }
\r
162 if (from<0) from=0;
\r
163 if (to>=256) to=255;
\r
168 for (i=from; i<=to; i++)
\r
170 outp(969, pal[(i*3)+0]);
\r
171 outp(969, pal[(i*3)+1]);
\r
172 outp(969, pal[(i*3)+2]);
\r
176 static byte *fli_read(byte *buf, int size)
\r
183 memcpy(buf, fli_mem_data+fli_mem_pos, size);
\r
185 buf = fli_mem_data+fli_mem_pos;
\r
187 fli_mem_pos += size;
\r
193 _grow_scratch_mem(size);
\r
194 buf = _scratch_mem;
\r
197 result = read(fli_file, buf, size);
\r
198 if (result != size)
\r
204 static void fli_seek(int offset, int mode)
\r
208 if (mode == SEEK_CUR)
\r
209 fli_mem_pos += offset;
\r
211 fli_mem_pos = offset;
\r
214 lseek(fli_file, offset, mode);
\r
217 // helpers for reading FLI chunk data
\r
218 #define READ_BYTE() ((sz-- > 0) ? *(((byte *)p)++) : 0)
\r
219 #define READ_CHAR() ((sz-- > 0) ? *(((signed char *)p)++) : 0)
\r
220 #define READ_SHORT() (((sz-=2) > 0) ? *(((signed short *)p)++) : 0)
\r
222 #define READ_BLOCK(pos, size) \
\r
224 if (sz >= (size)) \
\r
226 memcpy(pos, p, size); \
\r
232 char *_p = (char *)(pos); \
\r
235 for (_c=0; _c < (size); _c++) \
\r
236 *(_p++) = READ_BYTE(); \
\r
240 #define READ_RLE_BYTE(pos, size) \
\r
242 memset(pos, READ_BYTE(), size); \
\r
245 #define READ_RLE_WORD(pos, size) \
\r
247 short *_p = (short *)(pos); \
\r
248 short _v = READ_SHORT(); \
\r
251 for (_c=0; _c < (size); _c++) \
\r
255 static void do_fli_256_color(byte *p, int sz)
\r
263 packets = READ_SHORT();
\r
264 for (c=0; c<packets; c++)
\r
266 offset += READ_BYTE();
\r
267 length = READ_BYTE();
\r
268 if (length == 0) length = 256;
\r
269 for (c2=0; c2<length; c2++)
\r
271 fli_palette[((offset+c2)*3)+0] = READ_BYTE() / 4;
\r
272 fli_palette[((offset+c2)*3)+1] = READ_BYTE() / 4;
\r
273 fli_palette[((offset+c2)*3)+2] = READ_BYTE() / 4;
\r
275 fli_pal_dirty_from = MIN(fli_pal_dirty_from, offset);
\r
276 fli_pal_dirty_to = MAX(fli_pal_dirty_to, offset+length-1);
\r
281 static void do_fli_delta(byte *p, int sz)
\r
289 lines = READ_SHORT();
\r
291 // for each line...
\r
292 while (lines-- > 0)
\r
294 packets = READ_SHORT();
\r
296 while (packets < 0)
\r
298 if (packets & 0x4000)
\r
301 fli_bitmap_data[(y*fli_bitmap_width)+fli_bitmap_width-1]=packets&0xff;
\r
302 //fli_bitmap->line[y][fli_bitmap->w-1] = packets & 0xFF;
\r
304 packets = READ_SHORT();
\r
307 while (packets-- > 0)
\r
312 size = READ_CHAR();
\r
317 READ_BLOCK(fli_bitmap_data+(y*fli_bitmap_width)+x, size*2);
\r
318 //READ_BLOCK(fli_bitmap->line[y]+x, size*2);
\r
321 // repeat word -size times
\r
324 READ_RLE_WORD(fli_bitmap_data+(y*fli_bitmap_width)+x, -size);
\r
325 //READ_RLE_WORD(fli_bitmap->line[y]+x, -size);
\r
329 fli_bmp_dirty_from = MIN(fli_bmp_dirty_from, y);
\r
330 fli_bmp_dirty_to = MAX(fli_bmp_dirty_to, y);
\r
335 static void do_fli_color(byte *p, int sz)
\r
343 packets = READ_SHORT();
\r
345 for (c=0; c<packets; c++)
\r
347 offset += READ_BYTE();
\r
348 length = READ_BYTE();
\r
349 if (length == 0) length = 256;
\r
351 for (c2=0; c2<length; c2++)
\r
353 fli_palette[((offset+c2)*3)+0] = READ_BYTE();
\r
354 fli_palette[((offset+c2)*3)+1] = READ_BYTE();
\r
355 fli_palette[((offset+c2)*3)+2] = READ_BYTE();
\r
358 fli_pal_dirty_from = MIN(fli_pal_dirty_from, offset);
\r
359 fli_pal_dirty_to = MAX(fli_pal_dirty_to, offset+length-1);
\r
364 static void do_fli_lc(byte *p, int sz)
\r
372 lines = READ_SHORT();
\r
373 fli_bmp_dirty_from = MIN(fli_bmp_dirty_from, y);
\r
374 fli_bmp_dirty_to = MAX(fli_bmp_dirty_to, y+lines-1);
\r
376 // for each line...
\r
377 while (lines-- > 0)
\r
379 packets = READ_BYTE();
\r
381 while (packets-- > 0)
\r
384 size = READ_CHAR();
\r
389 READ_BLOCK(fli_bitmap_data+(y*fli_bitmap_width)+x, size);
\r
390 //READ_BLOCK(fli_bitmap->line[y]+x, size);
\r
395 READ_RLE_BYTE(fli_bitmap_data+(y*fli_bitmap_width)+x, -size);
\r
396 //READ_RLE_BYTE(fli_bitmap->line[y]+x, -size);
\r
404 static void do_fli_black(byte *p, int sz)
\r
406 memset(fli_bitmap_data, 0, fli_bitmap_width*fli_bitmap_height);
\r
407 //clear(fli_bitmap);
\r
409 fli_bmp_dirty_from = 0;
\r
410 fli_bmp_dirty_to = fli_bitmap_height-1;
\r
413 static void do_fli_brun(byte *p, int sz)
\r
419 // for each line...
\r
420 for (y=0; y<fli_bitmap_height; y++)
\r
422 packets = READ_BYTE();
\r
424 while (packets-- > 0)
\r
426 size = READ_CHAR();
\r
429 READ_BLOCK(fli_bitmap_data+(y*fli_bitmap_width)+x, -size);
\r
430 //READ_BLOCK(fli_bitmap->line[y]+x, -size);
\r
433 // repeat byte size times
\r
436 READ_RLE_BYTE(fli_bitmap_data+(y*fli_bitmap_width)+x, size);
\r
437 //READ_RLE_BYTE(fli_bitmap->line[y]+x, size);
\r
442 fli_bmp_dirty_from = 0;
\r
443 fli_bmp_dirty_to = fli_bitmap_height-1;
\r
446 static void do_fli_copy(byte *p, int sz)
\r
448 READ_BLOCK(fli_bitmap_data, fli_bitmap_width * fli_bitmap_height);
\r
449 //READ_BLOCK(fli_bitmap->dat, fli_bitmap->w * fli_bitmap->h);
\r
451 fli_bmp_dirty_from = 0;
\r
452 fli_bmp_dirty_to = fli_bitmap_height-1;
\r
455 static void read_frame()
\r
461 if (fli_status != FLI_OK)
\r
465 if (!fli_read((byte *)&frame_header, sizeof(FLI_FRAME)))
\r
467 fli_status = FLI_ERROR;
\r
471 if ((frame_header.type == FLI_FRAME_PREFIX)
\r
472 || (frame_header.type == FLI_FRAME_USELESS))
\r
474 fli_seek(frame_header.size-sizeof(FLI_FRAME), SEEK_CUR);
\r
477 goto get_another_frame;
\r
480 if (frame_header.type != FLI_FRAME_MAGIC)
\r
482 fli_status = FLI_ERROR;
\r
486 if (frame_header.size == sizeof(FLI_FRAME))
\r
491 p = fli_read(NULL, frame_header.size-sizeof(FLI_FRAME));
\r
494 fli_status = FLI_ERROR;
\r
497 for (c=0; c<frame_header.chunks; c++)
\r
499 chunk = (FLI_CHUNK *)p;
\r
500 sz = chunk->size - sizeof(FLI_CHUNK);
\r
501 p += sizeof(FLI_CHUNK);
\r
502 switch (chunk->type)
\r
504 case 4: do_fli_256_color(p, sz); break;
\r
505 case 7: do_fli_delta(p, sz); break;
\r
506 case 11: do_fli_color(p, sz); break;
\r
507 case 12: do_fli_lc(p, sz); break;
\r
508 case 13: do_fli_black(p, sz); break;
\r
509 case 15: do_fli_brun(p, sz); break;
\r
510 case 16: do_fli_copy(p, sz); break;
\r
511 default: err("Corrupt FLI chunk.");
\r
513 p = ((byte *)chunk) + chunk->size;
\r
518 static int do_play_fli(BITMAP *bmp, int loop, int (*callback)())
\r
522 ret = next_fli_frame(loop);
\r
523 while (ret == FLI_OK)
\r
525 if (fli_pal_dirty_from <= fli_pal_dirty_to)
\r
526 set_palette_range(fli_palette, fli_pal_dirty_from, fli_pal_dirty_to, 1);
\r
528 if (fli_bmp_dirty_from <= fli_bmp_dirty_to)
\r
530 int i,to=fli_bmp_dirty_to;
\r
531 if (to>=bmp->h) to=bmp->h-1;
\r
534 for (i=fli_bmp_dirty_from; i<=to; i++)
\r
536 memcpy(bmp->data+(i*bmp->w), fli_bitmap_data+(i*fli_bitmap_width),
\r
537 (fli_bitmap_width>bmp->w) ? bmp->w : fli_bitmap_width);
\r
541 // fli_bitmap, bmp, 0, fli_bmp_dirty_from, 0, fli_bmp_dirty_from,
\r
542 // fli_bitmap->w, 1+fli_bmp_dirty_to-fli_bmp_dirty_from);
\r
545 reset_fli_variables();
\r
549 ret = (*callback)();
\r
553 ret = next_fli_frame(loop);
\r
554 while (timer_count<speed) ShowPage();
\r
560 return (ret == FLI_EOF) ? FLI_OK : ret;
\r
563 int play_fli(char *filename, BITMAP *bmp, int loop, int (*callback)())
\r
565 if (open_fli(filename) != FLI_OK)
\r
568 return do_play_fli(bmp, loop, callback);
\r
571 int play_memory_fli(byte *fli_data, BITMAP *bmp, int loop, int (*callback)())
\r
573 if (open_memory_fli(fli_data) != FLI_OK)
\r
576 return do_play_fli(bmp, loop, callback);
\r
579 static int do_open_fli()
\r
582 if (!fli_read((byte *)&fli_header, sizeof(FLI_HEADER)))
\r
588 // check magic numbers
\r
589 if (((fli_header.bpp != 8) && (fli_header.bpp != 0))
\r
590 || ((fli_header.type != FLI_MAGIC) && (fli_header.type != FLC_MAGIC)))
\r
596 if (fli_header.width == 0)
\r
597 fli_header.width = 320;
\r
599 if (fli_header.height == 0)
\r
600 fli_header.height = 200;
\r
602 // create the frame bitmap
\r
603 fli_bitmap_width=fli_header.width;
\r
604 fli_bitmap_height=fli_header.height;
\r
605 fli_bitmap_data=(byte *)malloc(fli_bitmap_width*fli_bitmap_height);
\r
606 if (!fli_bitmap_data)
\r
612 reset_fli_variables();
\r
614 fli_status = FLI_OK;
\r
616 if (fli_header.type == FLI_MAGIC)
\r
617 speed = (long)fli_header.speed * 100 / 70;
\r
619 speed = (long)fli_header.speed / 10;
\r
627 int open_fli(char *filename)
\r
629 if (fli_status != FLI_NOT_OPEN)
\r
631 fli_file = open(filename, O_RDONLY | O_BINARY, S_IRUSR | S_IWUSR);
\r
637 return do_open_fli();
\r
640 int open_memory_fli(byte *fli_data)
\r
642 if (fli_status != FLI_NOT_OPEN)
\r
644 fli_mem_data = fli_data;
\r
646 return do_open_fli();
\r
651 //remove_int(fli_timer_callback);
\r
659 if (fli_bitmap_data)
\r
661 free(fli_bitmap_data);
\r
662 fli_bitmap_data = NULL;
\r
665 fli_mem_data = NULL;
\r
667 reset_fli_variables();
\r
668 fli_status = FLI_NOT_OPEN;
\r
671 int next_fli_frame(int loop)
\r
673 if (fli_status != FLI_OK)
\r
678 // end of file? should we loop?
\r
679 if (fli_frame >= fli_header.frame_count)
\r
683 fli_seek(sizeof(FLI_HEADER), SEEK_SET);
\r
688 fli_status = FLI_EOF;
\r
696 void reset_fli_variables()
\r
698 fli_bmp_dirty_from = INT_MAX;
\r
699 fli_bmp_dirty_to = INT_MIN;
\r
700 fli_pal_dirty_from = INT_MAX;
\r
701 fli_pal_dirty_to = INT_MIN;
\r