/* Copyright (C) 1998 BJ Eirich (aka vecna) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public Lic See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // ported by aen #define FLI_H #include #include #include #include "verge.h" // ================================= Data ==================================== #ifndef __WATCOMC__ #define INT_MAX 0xFFFFFFFF #define INT_MIN 0 #endif #ifndef MIN #define MIN(x,y) (((x) < (y)) ? (x) : (y)) #define MAX(x,y) (((x) > (y)) ? (x) : (y)) #define MID(x,y,z) MAX((x), MIN((y), (z))) #endif #ifndef ABS #define ABS(x) (((x) >= 0) ? (x) : (-(x))) #endif #ifndef SGN #define SGN(x) (((x) >= 0) ? 1 : -1) #endif #define FLI_MAGIC 0xAF11 // file header magic number #define FLC_MAGIC 0xAF12 // file magic number (Pro) #define FLI_FRAME_MAGIC 0xF1FA // frame header magic number #define FLI_FRAME_PREFIX 0xF100 // FLC's prefix info #define FLI_FRAME_USELESS 0x00A1 // FLC's garbage frame typedef struct { int w,h; byte *data; } BITMAP; #define FLI_OK 0 /* FLI player return values */ #define FLI_EOF -1 #define FLI_ERROR -2 #define FLI_NOT_OPEN -3 #ifdef __WATCOMC__ #define PACKED #pragma pack(1); #endif #ifdef __DJGPP__ #define PACKED __attribute__ ((packed)) #endif typedef struct { long size PACKED; word type PACKED; word frame_count PACKED; word width PACKED; word height PACKED; word bpp PACKED; word flags PACKED; word speed PACKED; long next_head PACKED; long frames_in_table PACKED; char reserved[102] PACKED; } FLI_HEADER; typedef struct { quad size PACKED; word type PACKED; word chunks PACKED; char pad[8] PACKED; } FLI_FRAME; typedef struct { quad size PACKED; word type PACKED; } FLI_CHUNK; #ifdef __WATCOMC__ #pragma pack(); #endif static int fli_status = FLI_NOT_OPEN; // current state of the FLI player int fli_bitmap_width = 0; int fli_bitmap_height = 0; byte *fli_bitmap_data = NULL; // current frame of the FLI byte fli_palette[768]; // current palette the FLI is using int fli_bmp_dirty_from = INT_MAX; // what part of fli_bitmap is dirty int fli_bmp_dirty_to = INT_MIN; int fli_pal_dirty_from = INT_MAX; // what part of fli_palette is dirty int fli_pal_dirty_to = INT_MIN; int fli_frame = 0; // current frame number in the FLI long speed; static int fli_file = 0; // the file we are reading static byte *fli_mem_data = NULL; // the memory FLI we are playing static int fli_mem_pos = 0; // position in the memory FLI static FLI_HEADER fli_header; // header structure static FLI_FRAME frame_header; // frame header structure // a block of temporary working memory byte *_scratch_mem = NULL; int _scratch_mem_size = 0; // ================================= Code ==================================== void reset_fli_variables(void); void close_fli(void); int next_fli_frame(int); int open_fli(char *); int open_memory_fli(byte *); void _grow_scratch_mem(int size) { if (size > _scratch_mem_size) { size = (size+1023) & 0xFFFFFC00; _scratch_mem = realloc(_scratch_mem, size); _scratch_mem_size = size; } } void vsync() { while (!(inp(986) & 8)); } void set_palette_range(byte *pal, int from, int to, int sync) { int i; // swap? if (to=256) to=255; if (sync) vsync(); outp(968, from); for (i=from; i<=to; i++) { outp(969, pal[(i*3)+0]); outp(969, pal[(i*3)+1]); outp(969, pal[(i*3)+2]); } } static byte *fli_read(byte *buf, int size) { int result; if (fli_mem_data) { if (buf) memcpy(buf, fli_mem_data+fli_mem_pos, size); else buf = fli_mem_data+fli_mem_pos; fli_mem_pos += size; } else { if (!buf) { _grow_scratch_mem(size); buf = _scratch_mem; } result = read(fli_file, buf, size); if (result != size) return NULL; } return buf; } static void fli_seek(int offset, int mode) { if (fli_mem_data) { if (mode == SEEK_CUR) fli_mem_pos += offset; else fli_mem_pos = offset; } else lseek(fli_file, offset, mode); } // helpers for reading FLI chunk data #define READ_BYTE() ((sz-- > 0) ? *(((byte *)p)++) : 0) #define READ_CHAR() ((sz-- > 0) ? *(((signed char *)p)++) : 0) #define READ_SHORT() (((sz-=2) > 0) ? *(((signed short *)p)++) : 0) #define READ_BLOCK(pos, size) \ { \ if (sz >= (size)) \ { \ memcpy(pos, p, size); \ p += (size); \ sz -= (size); \ } \ else \ { \ char *_p = (char *)(pos); \ int _c; \ \ for (_c=0; _c < (size); _c++) \ *(_p++) = READ_BYTE(); \ } \ } #define READ_RLE_BYTE(pos, size) \ { \ memset(pos, READ_BYTE(), size); \ } #define READ_RLE_WORD(pos, size) \ { \ short *_p = (short *)(pos); \ short _v = READ_SHORT(); \ int _c; \ \ for (_c=0; _c < (size); _c++) \ *(_p++) = _v; \ } static void do_fli_256_color(byte *p, int sz) { int packets; int c, c2; int offset; int length; offset = 0; packets = READ_SHORT(); for (c=0; c 0) { packets = READ_SHORT(); while (packets < 0) { if (packets & 0x4000) y -= packets; else fli_bitmap_data[(y*fli_bitmap_width)+fli_bitmap_width-1]=packets&0xff; //fli_bitmap->line[y][fli_bitmap->w-1] = packets & 0xFF; packets = READ_SHORT(); } x=0; while (packets-- > 0) { // skip bytes x += READ_BYTE(); size = READ_CHAR(); // copy size words if (size > 0) { READ_BLOCK(fli_bitmap_data+(y*fli_bitmap_width)+x, size*2); //READ_BLOCK(fli_bitmap->line[y]+x, size*2); x += size*2; } // repeat word -size times else if (size < 0) { READ_RLE_WORD(fli_bitmap_data+(y*fli_bitmap_width)+x, -size); //READ_RLE_WORD(fli_bitmap->line[y]+x, -size); x -= size*2; } } fli_bmp_dirty_from = MIN(fli_bmp_dirty_from, y); fli_bmp_dirty_to = MAX(fli_bmp_dirty_to, y); y++; } } static void do_fli_color(byte *p, int sz) { int packets; int c, c2; int offset; int length; offset = 0; packets = READ_SHORT(); for (c=0; c 0) { packets = READ_BYTE(); x = 0; while (packets-- > 0) { x += READ_BYTE(); size = READ_CHAR(); // copy size bytes if (size > 0) { READ_BLOCK(fli_bitmap_data+(y*fli_bitmap_width)+x, size); //READ_BLOCK(fli_bitmap->line[y]+x, size); x += size; } else if (size < 0) { READ_RLE_BYTE(fli_bitmap_data+(y*fli_bitmap_width)+x, -size); //READ_RLE_BYTE(fli_bitmap->line[y]+x, -size); x -= size; } } y++; } } static void do_fli_black(byte *p, int sz) { memset(fli_bitmap_data, 0, fli_bitmap_width*fli_bitmap_height); //clear(fli_bitmap); fli_bmp_dirty_from = 0; fli_bmp_dirty_to = fli_bitmap_height-1; } static void do_fli_brun(byte *p, int sz) { int packets; int size; int x, y; // for each line... for (y=0; y 0) { size = READ_CHAR(); if (size < 0) { READ_BLOCK(fli_bitmap_data+(y*fli_bitmap_width)+x, -size); //READ_BLOCK(fli_bitmap->line[y]+x, -size); x -= size; } // repeat byte size times else if (size > 0) { READ_RLE_BYTE(fli_bitmap_data+(y*fli_bitmap_width)+x, size); //READ_RLE_BYTE(fli_bitmap->line[y]+x, size); x += size; } } } fli_bmp_dirty_from = 0; fli_bmp_dirty_to = fli_bitmap_height-1; } static void do_fli_copy(byte *p, int sz) { READ_BLOCK(fli_bitmap_data, fli_bitmap_width * fli_bitmap_height); //READ_BLOCK(fli_bitmap->dat, fli_bitmap->w * fli_bitmap->h); fli_bmp_dirty_from = 0; fli_bmp_dirty_to = fli_bitmap_height-1; } static void read_frame() { byte *p; FLI_CHUNK *chunk; int c, sz; if (fli_status != FLI_OK) return; get_another_frame: if (!fli_read((byte *)&frame_header, sizeof(FLI_FRAME))) { fli_status = FLI_ERROR; return; } if ((frame_header.type == FLI_FRAME_PREFIX) || (frame_header.type == FLI_FRAME_USELESS)) { fli_seek(frame_header.size-sizeof(FLI_FRAME), SEEK_CUR); fli_frame++; goto get_another_frame; } if (frame_header.type != FLI_FRAME_MAGIC) { fli_status = FLI_ERROR; return; } if (frame_header.size == sizeof(FLI_FRAME)) { fli_frame++; return; } p = fli_read(NULL, frame_header.size-sizeof(FLI_FRAME)); if (!p) { fli_status = FLI_ERROR; return; } for (c=0; csize - sizeof(FLI_CHUNK); p += sizeof(FLI_CHUNK); switch (chunk->type) { case 4: do_fli_256_color(p, sz); break; case 7: do_fli_delta(p, sz); break; case 11: do_fli_color(p, sz); break; case 12: do_fli_lc(p, sz); break; case 13: do_fli_black(p, sz); break; case 15: do_fli_brun(p, sz); break; case 16: do_fli_copy(p, sz); break; default: err("Corrupt FLI chunk."); } p = ((byte *)chunk) + chunk->size; } fli_frame++; } static int do_play_fli(BITMAP *bmp, int loop, int (*callback)()) { int ret; ret = next_fli_frame(loop); while (ret == FLI_OK) { if (fli_pal_dirty_from <= fli_pal_dirty_to) set_palette_range(fli_palette, fli_pal_dirty_from, fli_pal_dirty_to, 1); if (fli_bmp_dirty_from <= fli_bmp_dirty_to) { int i,to=fli_bmp_dirty_to; if (to>=bmp->h) to=bmp->h-1; // vsync(); for (i=fli_bmp_dirty_from; i<=to; i++) { memcpy(bmp->data+(i*bmp->w), fli_bitmap_data+(i*fli_bitmap_width), (fli_bitmap_width>bmp->w) ? bmp->w : fli_bitmap_width); } //blit( // fli_bitmap, bmp, 0, fli_bmp_dirty_from, 0, fli_bmp_dirty_from, // fli_bitmap->w, 1+fli_bmp_dirty_to-fli_bmp_dirty_from); } reset_fli_variables(); if (callback) { ret = (*callback)(); if (ret != FLI_OK) break; } ret = next_fli_frame(loop); while (timer_count= fli_header.frame_count) { if (loop) { fli_seek(sizeof(FLI_HEADER), SEEK_SET); fli_frame = 0; } else { fli_status = FLI_EOF; return fli_status; } } read_frame(); return fli_status; } void reset_fli_variables() { fli_bmp_dirty_from = INT_MAX; fli_bmp_dirty_to = INT_MIN; fli_pal_dirty_from = INT_MAX; fli_pal_dirty_to = INT_MIN; }