aview/flip.c

921 lines
24 KiB
C

/* Copyright 1993 J. Remyn */
/* This program is freely distributable, but there is no warranty */
/* of any kind. */
/* version 0.3 */
/* Modified for aaflip version 1.0 by Jan Hubicka*/
#include <stdlib.h>
#include <stdio.h>
#include <sys/time.h>
#include <unistd.h>
#include <aalib.h>
#include "general.h"
#include "fli.h"
#define NAMELEN 256
struct OPTIONS {
char filename[NAMELEN]; /* filename given on command line */
char fast; /* 1 = play without delays */
char verbose; /* 1 = show info about flic file */
char release; /* 1 = don't keep frames in memory */
char firstp; /* 1 = process frames while loading */
char blank; /* 1 = keep black screen while loading */
char stdinp; /* 1 = take flic file from stdin */
int speed; /* speed gotten from command line (-1 if nothing gotten) */
int playrep; /* nr of times to play animation */
} options;
struct FLI_FRAMECHUNK {
long size; /* Size of chunk data part */
long file_offset; /* Offset of chunk data part into flic file */
int subchunks; /* Number of subchunks in data part */
void *cd; /* Pointer to memory containing data part, */
/* is NULL if data not kept in memory */
};
struct FLI {
char filename[NAMELEN]; /* filename of fli file */
char flc; /* 0 = fli, 1 = flc */
int mode; /* vgalib mode number to be used */
int scr_width; /* width of screen mode used */
int scr_height; /* guess */
int current; /* current frame index */
long time; /* time of last processed frame in usec */
FILE *f; /* file pointer of opened flic file */
struct FLI_HEADER h; /* 128 byte fli file header structure */
struct FLI_FRAMECHUNK *frame;
/* pointer to an allocated 'array' of
<frames> FLI_FRAMECHUNK structs */
} fli;
static aa_palette pal;
static aa_context *context;
static aa_renderparams *params;
static char *graph_mem;
static void dcd_color_64( char *data ) {
uchar start = 0;
int ops;
int count;
int i;
/* puts( "color_64" ); */
ops = *(short int *)data;
data = (void *)(((short int *)data) + 1);
while( ops-- > 0 ) {
start += *(uchar *)data;
data = (void *) ((uchar *)data + 1);
if( (count = (int)*(uchar *)data) == 0 )
count = 256;
data = (void *) ((uchar *)data + 1);
for( i=0; i<count; i++ ) {
/* (s)vgalib requires a table of ints for setting a group
* of colors quickly, but we've got a table of chars :(
* so we have to set each color individually (slow) */
aa_setpalette(pal, start + i,
((int)*(uchar *)data)*4,
((int)*((uchar *)data+1)*4),
((int)*((uchar *)data+2)*4)
);
data = (void *)((uchar *)data + 3);
}
start += count;
}
}
static void dcd_color_256( char *data ) {
uchar start = 0;
int ops;
int count;
int i;
/* puts( "color_256" ); */
ops = *(short int *)data;
data = (void *)((short int *)data + 1);
while( ops-- > 0 ) {
start += *(uchar *)data;
data = (void *)((uchar *)data + 1);
if( (count = (int)*(uchar *)data) == 0 )
count = 256;
data = (void *)((uchar *)data + 1);
for( i=0; i<count; i++ ) {
aa_setpalette(pal, start + i,
*(uchar *)data >> 2,
*((uchar *)data+1) >> 2,
*((uchar *)data+2) >> 2
);
data = (void *)((uchar *)data + 3);
}
start += count;
}
}
void *memsetw( unsigned short *target, unsigned short w, int count ) {
while( count-->0 ) {
*target++ = w;
}
return( target );
}
static void dcd_delta_flc( struct FLI *fli, char *data ) {
short int line;
short int nrlines;
char *index;
short packets;
short type;
int x;
uchar lastbyte;
char setlastbyte;
/* puts( "delta flc" ); */
/* get nr of lines in chunk */
nrlines = *(short int *)data;
data = (void *)((short int *)data + 1);
line = 0;
setlastbyte = 0;
lastbyte = 0; /* this is just to get rid of a compiler warning */
index = graph_mem;
while( nrlines>0 ) { /* don't put nrlines-- here, the continues don't allow it */
type = *(short *)data;
data = (void *)((short *)data + 1);
/* the 2 highest bits of type indicate how to interpret it */
if( type<0 ) {
if( type&0x4000 ) {
/* add to the line number and act as if nothing
* happened.
* documentation says it's all right just to
* add the abs. value of the word, which is the
* same as subtracting the word as it is always
* negative.
*/
line -= type;
index += fli->scr_width * (-type);
continue;
}
/* the low byte contains a lastbyte (the last byte
* on a line in odd-width resolution flic files),
* this word is followed by the packet count
*/
setlastbyte = 1;
lastbyte = (uchar)(type & 0x00FF);
packets = *(short *)data;
data = (void *)((short *)data + 1);
/* packets can be 0 now if just the last byte
* changes for this line
*/
}
if( type>=0 ) {
/* the word contains the nr of packets
* we can just assign this to packets because the
* high bits are zero
*/
packets = type;
}
/* decode packets */
x = 0;
while( packets-->0 ) {
/* get & decode packet */
x += *(uchar *)data;
data = (void *)((uchar *)data + 1);
type = *(char *)data;
data = (void *)((uchar *)data + 1);
if( (char)type>=0 ) {
/* copy ptype words */
type <<= 1;
memcpy( index + x, data, type );
x += type;
data = (void *)((uchar *)data + type);
continue;
}
type = -(char)type;
memsetw( (ushort *)(index + x), *(ushort *)data, type );
x += type<<1;
data = (void *)((ushort *)data + 1);
}
if( !setlastbyte ) {
index = (char *)((uchar *)index + fli->scr_width);
nrlines--;
continue;
}
/* put lastbyte at end of line */
*(uchar *)(index + fli->scr_width - 1) = lastbyte;
setlastbyte = 0;
index = (char *)((uchar *)index + fli->scr_width);
nrlines--;
}
}
static void dcd_delta_fli( struct FLI *fli, char *data ) {
short int line;
short int nrlines;
char *index;
uchar packets;
int index_x;
char type;
/* puts( "delta fli" ); */
line = *(short int *)data;
data = (void *)((short int *)data + 1);
index = graph_mem + line * fli->scr_width;
nrlines = *(short int *)data;
data = (void *)((short int *)data + 1);
while( nrlines-- > 0 ) {
index_x = 0;
packets = *(uchar *)data;
data = (void *)((uchar *)data + 1);
while( packets > 0 ) {
index_x += *(uchar *)data;
data = (void *)((uchar *)data + 1);
type = *(char *)data;
data = (void *)((char *)data + 1);
if( type >= 0 ) {
memcpy( index + index_x, data, type );
index_x += type;
data = (void *)((uchar *)data + type);
packets--;
continue;
}
memset( index + index_x, *(uchar *)data, -type );
index_x -= type;
data = (void *)((uchar *)data + 1);
packets--;
}
index += fli->scr_width;
}
}
static void dcd_byte_run( struct FLI *fli, char *data ) {
int lines;
int width;
char type;
int index;
int index_x;
/* puts( "byte run" ); */
lines = fli->h.height;
width = fli->h.width;
index = 0;
while( lines-->0 ) {
data = (void *)((uchar *)data + 1); /* skip byte containing number of packets */
/* start a loop to decode packets until end of line is reached */
index_x = 0;
while ( index_x < width ) {
type = *((char *)data++);
if( type<0 ) {
/* type now contains nr of bytes to copy to video */
memcpy( graph_mem + index + index_x, (uchar *)data, -type );
index_x -= type;
data = (void *)((uchar *)data - type);
}
else {
memset( graph_mem + index + index_x, *(uchar *)data++, type );
index_x += type;
}
}
index += fli->scr_width;
}
}
static void dcd_black( struct FLI *fli, char *data ) {
/* puts( "black" ); */
int l;
uchar *index;
l = fli->h.height;
index = graph_mem;
while( l-- > 0 ) {
memset( index, 0, fli->h.width );
index += fli->scr_width;
}
}
static void dcd_literal( struct FLI *fli, char *data ) {
int l;
/* puts( "literal" ); */
l = fli->h.height;
{
/* linear video memory */
char *index;
index = graph_mem;
while( l-- > 0 ) {
memcpy( index, data, fli->h.width );
data = (void *)((uchar *)data + fli->h.width);
index += fli->scr_width;
}
}
}
static void dcd_pstamp( char *data ) {
/* puts( "pstamp" ); */
}
static void showhelp( void ) {
puts( "FLI Player for Linux (version 0.2a) by John Remyn" );
puts( "modified version for aalib by Jan Hubicka" );
puts( "Now it is ascii arted FLI Player for text mode" );
puts( "Usage:" );
puts( " flip [switch] <filename>" );
puts( "Valid switches are :" );
puts( " -f Switch off clock synchronization." );
puts( " -v Show information on flic file." );
puts( " -? -h Show help." );
puts( " -a Don't keep frames in memory." );
puts( " -b Process frames when they are loaded." );
puts( " -c Keep a blank screen while frames are being loaded." );
puts( " -n <number> Play the animation sequence <n> times." );
puts( " -s <delay> Set delay between frames to <delay> miliseconds." );
puts( " - Read flic file from standard input." );
puts( "also standard aalib options are supported" );
puts( " -dim, -bold, -reverse, -normal for enabling attributes");
puts( " -nodim, -nobold, -noreverse, -nonormal for disabling");
puts( "Press H for help on keys while playing." );
}
static void parse_cmdln( int argc, char *argv[], struct OPTIONS *options ) {
int i,j;
options->filename[0] = '\0';
options->fast = 0;
options->verbose = 0;
options->release = 0;
options->firstp = 0;
options->blank = 0;
options->playrep = 1;
options->speed = -1;
options->stdinp = 0;
for( i=1; i<argc; i++ ) {
if( *argv[i]=='-' ) {
char c;
int k;
/* argv[i] contains options */
if( *(argv[i]+1)=='\0' ) {
options->stdinp = 1;
}
j = 1;
k = 0;
while( (c = *(argv[i]+j))!='\0' ) {
switch( c ) {
case 'f' : options->fast = 1; break;
case 'v' : options->verbose = 1; break;
case 'a' : options->release = 1; break;
case 'b' : options->firstp = 1; break;
case 'c' : options->blank = 1; break;
case '?' :
case 'h' : showhelp(); exit( 0 ); break;
case 'n' : if( i+k+1<argc ) {
k++;
options->playrep = abs( atoi( argv[i+k] ) );
}
break;
case 's' : if( i+k+1<argc ) {
k++;
options->speed = abs( atoi( argv[i+k] ) );
/* adjust to some reasonable value */
if (options->speed > 1000) options->speed = 1000;
/* convert to usec */
options->speed *= 1000;
}
break;
default : showhelp();
puts( "Unknown option." );
exit( -1 );
}
j++;
}
i = i+k;
}
else {
if( argv[i]!=NULL ) {
/* argv[i] is the filename of the flic file */
strncpy( options->filename, argv[i], NAMELEN );
}
}
}
if( options->filename[0]=='\0' && options->stdinp==0 ) {
showhelp();
puts( "No filename given." );
exit( -1 );
}
}
static int open_fli( struct FLI *fli, struct OPTIONS *options ) {
/* open file and read the header */
if( !options->stdinp ) {
fli->f = fopen( fli->filename, "rb" );
if( !fli->f ) {
return 0;
}
}
else {
fli->f = stdin;
}
freadblock( fli->f, sizeof( fli->h.size ), &(fli->h.size) );
freadblock( fli->f, sizeof( fli->h.type ), &(fli->h.type) );
freadblock( fli->f, sizeof( fli->h.frames ), &(fli->h.frames) );
freadblock( fli->f, sizeof( fli->h.width ), &(fli->h.width) );
freadblock( fli->f, sizeof( fli->h.height ), &(fli->h.height) );
freadblock( fli->f, sizeof( fli->h.depth ), &(fli->h.depth) );
freadblock( fli->f, sizeof( fli->h.flags ), &(fli->h.flags) );
freadblock( fli->f, sizeof( fli->h.speed ), &(fli->h.speed) );
freadblock( fli->f, sizeof( fli->h.reserved0 ), &(fli->h.reserved0) );
freadblock( fli->f, sizeof( fli->h.created ), &(fli->h.created) );
freadblock( fli->f, sizeof( fli->h.creator ), &(fli->h.creator) );
freadblock( fli->f, sizeof( fli->h.updated ), &(fli->h.updated) );
freadblock( fli->f, sizeof( fli->h.updater ), &(fli->h.updater) );
freadblock( fli->f, sizeof( fli->h.aspectx ), &(fli->h.aspectx) );
freadblock( fli->f, sizeof( fli->h.aspecty ), &(fli->h.aspecty) );
freadblock( fli->f, sizeof( fli->h.reserved1 ), &(fli->h.reserved1) );
freadblock( fli->f, sizeof( fli->h.oframe1 ), &(fli->h.oframe1) );
freadblock( fli->f, sizeof( fli->h.oframe2 ), &(fli->h.oframe2) );
freadblock( fli->f, sizeof( fli->h.reserved2 ), &(fli->h.reserved2) );
/* now check if it's a flc or a fli and take necessary precautions */
if( (unsigned)fli->h.type==FLITYPE ) {
/* it's a fli. convert as much as possible to flc */
fli->flc = 0;
/* convert frame rate from 1/70 sec to usec */
fli->h.speed *= 100;
fli->h.speed /= 7;
fli->h.speed *= 1000;
/* ascpect ratio is ignored, but fix it anyway */
fli->h.aspectx = 6;
fli->h.aspecty = 5;
/* can't convert frame offsets */
}
else if( (unsigned)fli->h.type==FLCTYPE ) {
fli->flc = 1;
fli->h.speed *= 1000; /* convert msec to usec */
}
else {
puts( "File type not recognized." );
exit( -1 );
}
return 1;
};
static void describe_fli( struct FLI *fli ) {
printf( "Filename %s\n", fli->filename );
printf( "size %li\n", fli->h.size );
printf( "type %x\n", fli->h.type );
printf( "frames %i\n", fli->h.frames );
printf( "width %i\n", fli->h.width );
printf( "height %i\n", fli->h.height );
printf( "depth %i\n", fli->h.depth );
printf( "flags %x\n", fli->h.flags );
printf( "speed %li\n", fli->h.speed );
printf( "aspectx %i\n", fli->h.aspectx );
printf( "aspecty %i\n", fli->h.aspecty );
printf( "oframe1 %li\n", fli->h.oframe1 );
printf( "oframe2 %li\n", fli->h.oframe2 );
};
static void readchunkheader( FILE *f, struct FLI_CHUNK_HEADER *buf ) {
freadblock( f, sizeof( buf->size ), &buf->size );
freadblock( f, sizeof( buf->type ), &buf->type );
freadblock( f, sizeof( buf->chunks ), &buf->chunks );
freadblock( f, sizeof( buf->reserved ), &buf->reserved );
}
static void scan_to_frame( struct FLI *fli ) {
struct FLI_CHUNK_HEADER buf;
struct FLI_FRAMECHUNK *fc;
do {
readchunkheader( fli->f, &buf );
if( buf.type==0xF1FA ) break;
fseek( fli->f, buf.size - FLI_CHUNK_HEADERLEN, SEEK_CUR );
} while ( buf.type!=0xF1FA );
fc = fli->frame + fli->current;
fc->size = buf.size - FLI_CHUNK_HEADERLEN;
fc->subchunks = buf.chunks;
fc->file_offset = ftell( fli->f );
fc->cd = NULL;
}
static void getframechunkdata( struct FLI *fli ) {
struct FLI_FRAMECHUNK *fc;
void *data;
fc = fli->frame + fli->current;
data = fc->cd;
if( data )
return; /* frame chunk data already loaded */
if(fc->size) {
data = malloc( fc->size );
if( !data ) {
printf( "cannot allocate memory for frame data\n" );
exit( 1 );
}
fseek( fli->f, fc->file_offset, SEEK_SET );
freadblock( fli->f, fc->size, data );
} else data=NULL;
fc->cd = data;
}
static void releaseframechunkdata( struct FLI *fli ) {
struct FLI_FRAMECHUNK *fc;
fc = fli->frame + fli->current;
if( fc->cd ) {
free( fc->cd );
fc->cd = NULL;
}
}
static void processframechunk( struct FLI *fli ) {
struct FLI_FRAMECHUNK *fc;
void *data;
int i;
fc = fli->frame + fli->current;
data = fc->cd;
for( i=0; i<fc->subchunks; i++ ) {
/* switch( chunktype ) */
switch( *((short int *)((char *)data+4)) ) {
case COLOR_256 :
dcd_color_256( (char *)data + 6 );
break;
case DELTA_FLC :
dcd_delta_flc( fli, (char *)data + 6 );
break;
case COLOR_64 :
dcd_color_64( (char *)data + 6 );
break;
case DELTA_FLI :
dcd_delta_fli( fli, (char *)data + 6 );
break;
case BLACK :
dcd_black( fli, (char *)data + 6 );
break;
case BYTE_RUN :
dcd_byte_run( fli, (char *)data + 6 );
break;
case LITERAL :
dcd_literal( fli, (char *)data + 6 );
break;
case PSTAMP :
dcd_pstamp( (char *)data + 6 );
break;
default :
puts( "unknown subchunk" );
}
data = (void *)((char *)data + *(long *)data);
}
}
long gettime(void) {
struct timeval t;
gettimeofday(&t, NULL);
return(t.tv_usec);
}
int await() {
#define T 10000 /* process key every 10ms */
int i;
long t;
t = gettime();
if (t < fli.time) t = t + 1E6;
t = fli.h.speed - (t - fli.time);
if (t > 0) {
if (t > T) {
for (i = 0; i < (t / T); i++) {
usleep(T);
if (f_getkey() == 'q') return(1);
}
usleep(t % T);
}
else usleep(t);
}
return(f_getkey() == 'q');
}
static void fastscale(char *b1, char *b2, int x1, int x2, int y1, int y2, int width1, int width2)
{
int ddx1, ddx, spx = 0, ex;
int ddy1, ddy, spy = 0, ey;
int x;
char *bb1 = b1;
width2 -= x2;
if (!x1 || !x2 || !y1 || !y2)
return;
ddx = x1 + x1;
ddx1 = x2 + x2;
if (ddx1 < ddx)
spx = ddx / ddx1, ddx %= ddx1;
ddy = y1 + y1;
ddy1 = y2 + y2;
if (ddy1 < ddy)
spy = (ddy / ddy1) * width1, ddy %= ddy1;
ey = -ddy1;
for (; y2; y2--) {
ex = -ddx1;
for (x = x2; x; x--) {
*b2 = *b1;
b2++;
b1 += spx;
ex += ddx;
if (ex > 0) {
b1++;
ex -= ddx1;
}
}
b2 += width2;
bb1 += spy;
ey += ddy;
if (ey > 0) {
bb1 += width1;
ey -= ddy1;
}
b1 = bb1;
}
}
static int resized;
static void resize(aa_context * c)
{
aa_resize(c);
resized = 1;
}
static int yesno(int x, int y, char *string)
{
char c;
aa_puts(context, x, y, AA_SPECIAL, string);
aa_flush(context);
while ((c = tolower(aa_getkey(context, 1))) != 'y' && c != 'n');
return (c == 'y');
}
static int getnum(char *string)
{
unsigned char c;
aa_puts(context, 0, 0, AA_SPECIAL, string);
aa_flush(context);
while ((c = tolower(aa_getkey(context, 1))) < '0' || c > '9');
return (c - '0');
}
static void selectfont(aa_context * c)
{
int i = 0, i1;
char string[255];
for (i = 0; aa_fonts[i] != NULL; i++) {
sprintf(string, "%i - %-40s", i, aa_fonts[i]->name);
aa_puts(context, 0, i, AA_SPECIAL, string);
}
i1 = getnum("");
if (i1 < i)
aa_setfont(c, *(aa_fonts + i1));
}
#if AA_LIB_VERSION==1 && AA_LIB_MINNOR==0
#define SUPPORTED c->driver->params.supported
#else
#define SUPPORTED c->driverparams.supported
#endif
static void selectsupported(aa_context * c)
{
int supported = c->params.supported;
char text[40];
int ch;
do {
char *texts[]={
"Normal characters",
"Half bright (dim)",
"Double bright (bold)",
"Bold font",
"Reversed",
"8 bit ascii",
"Control characters"};
int masks[]={AA_NORMAL_MASK,AA_DIM_MASK,AA_BOLD_MASK,AA_BOLDFONT_MASK,AA_REVERSE_MASK,AA_EIGHT,AA_ALL};
int i;
for(i=0;i<7;i++)
{
sprintf(text,"%i %-20s:%-12s",i+1,texts[i],(SUPPORTED&masks[i])?((supported&masks[i])?"On":"Off"):"Unsupported");
aa_puts(c,0,i,AA_SPECIAL,text);
}
aa_puts(c,0,i,AA_SPECIAL,"8 Leave this menu");
aa_flush(c);
while ((ch = tolower(aa_getkey(context, 1))) < '1' || ch > '8');
ch-='1';
if(ch<7) supported^=masks[ch];
} while (ch<7);
aa_setsupported(c, supported);
}
int f_getkey(void)
{
int c=aa_getkey(context,0);
switch(c) {
case 'h':
case 'H':
aa_puts(context,0,0,AA_SPECIAL," aaflip - an ascii art fli/flc player ");
aa_puts(context,0,1,AA_SPECIAL," ");
aa_puts(context,0,2,AA_SPECIAL," ';' '\\' - gamma '<' '>' - bright ");
aa_puts(context,0,3,AA_SPECIAL," '[' ']' - Random dithering',' '.' - contrast ");
aa_puts(context,0,4,AA_SPECIAL," 'I' 'i' - inversion ");
aa_puts(context,0,5,AA_SPECIAL," ");
aa_puts(context,0,6,AA_SPECIAL," 'm' - Dithering method 'q' - quit ");
aa_puts(context,0,7,AA_SPECIAL," 'u' - Select attributes 'g' - font ");
aa_flush(context);
aa_getkey(context,1);
break;
case ';':
params->gamma /= 1.05;
break;
case '\'':
params->gamma *= 1.05;
break;
case '<':
params->bright -= 4;
break;
case '>':
params->bright += 4;
break;
case '[':
params->randomval -= 4;
break;
case ']':
params->randomval += 4;
break;
case ',':
params->contrast -= 2;
break;
case '.':
params->contrast += 2;
break;
case 'm':
params->dither = (params->dither + 1) % AA_DITHERTYPES;
break;
case 'i':
params->inversion = 1;
break;
case 'I':
params->inversion = 0;
break;
case 'u':
selectsupported(context);
break;
case 'g':
selectfont(context);
break;
}
return(c);
}
int main( int argc, char *argv[] ) {
int quit = 0;
int playstartframe = 0;
int first=1;
long t, tdelta;
aa_parseoptions(NULL,NULL,&argc,argv);
parse_cmdln( argc, argv, &options );
strcpy( fli.filename, options.filename );
/* open flic and get header information */
if( !open_fli( &fli, &options ) ) {
puts( "cannot open fli file" );
exit( 1 );
}
/* show header */
if( options.verbose==1 ) {
describe_fli( &fli );
}
/* optionally set delays */
if( options.speed>=0 ) {
fli.h.speed = options.speed;
}
/* optionally reduce delays to 0 (this overrides the set delay option) */
if( options.fast==1 ) {
fli.h.speed = 0;
}
/* silly but might happen */
if( options.playrep<=0 ) {
exit( 0 );
}
/* determine graphics mode to use */
/* set mode */
context=aa_autoinit(&aa_defparams);
if(context==NULL) {
printf("Failed to initialize aalib\n");
exit(1);
}
aa_hidecursor(context);
aa_autoinitkbd(context,0);
aa_resizehandler(context,resize);
params=aa_getrenderparams();
fli.scr_width = fli.h.width;
fli.scr_height = fli.h.height;
graph_mem=malloc(fli.scr_width*fli.scr_height);
fli.frame = (struct FLI_FRAMECHUNK *)malloc( (fli.h.frames+1) * sizeof( struct FLI_FRAMECHUNK ) );
if( fli.frame==NULL ) {
puts( "cannot allocate enough memory to store frame information\n" );
exit( 1 );
}
fli.current = 0;
/* preloading */
/* first the 1st frame which is a full screen frame */
scan_to_frame( &fli );
if( !options.blank ) {
getframechunkdata( &fli );
processframechunk( &fli );
releaseframechunkdata( &fli );
playstartframe = 1;
}
else {
getframechunkdata( &fli );
playstartframe = 0;
if( options.release ) {
releaseframechunkdata( &fli );
}
}
fli.current++;
first=1;
while( fli.current<=fli.h.frames && !quit ) {
scan_to_frame( &fli );
getframechunkdata( &fli );
if( options.firstp ) {
fli.time = gettime();
processframechunk( &fli );
}
if( options.release ) {
releaseframechunkdata( &fli );
}
if(first||options.firstp) {
fastscale(graph_mem,context->imagebuffer,
fli.scr_width,aa_imgwidth(context),
fli.scr_height,aa_imgheight(context),
fli.scr_width,aa_imgwidth(context));
aa_renderpalette(context,pal,params,0,0,aa_imgwidth(context),aa_imgheight(context));
if(first&&!options.firstp)
aa_puts(context,0,0,AA_SPECIAL,"Preloading...");
aa_flush(context);
}
fli.current++;
first=0;
if( f_getkey()=='q' ) quit = 1;
if(options.firstp&&!quit) quit = await();
}
if(!quit) {
if( options.firstp ) {
options.playrep--;
if( options.playrep==0 ) {
quit = 1;
}
}
fli.current = playstartframe;
while( !quit ) {
fli.time = gettime();
getframechunkdata( &fli );
processframechunk( &fli );
if( options.release ) {
releaseframechunkdata( &fli );
}
fli.current++;
fastscale(graph_mem,context->imagebuffer,
fli.scr_width,aa_imgwidth(context),
fli.scr_height,aa_imgheight(context),
fli.scr_width,aa_imgwidth(context));
aa_renderpalette(context,pal,params,0,0,aa_imgwidth(context),aa_imgheight(context));
aa_flush(context);
if( fli.current>fli.h.frames ) {
fli.current = 1;
options.playrep--;
if( options.playrep==0 ) {
quit = 1;
break;
}
}
quit = await();
}
}
/* restore textmode */
aa_close(context);
/* close flic */
if( !options.stdinp ) {
fclose( fli.f );
}
fli.f = NULL;
return 0;
};