1 
2 /* Copyright 1993 J. Remyn */
3 /* This program is freely distributable, but there is no warranty */
4 /* of any kind. */
5 /* version 0.3 */
6 /* Modified for aaflip version 1.0 by Jan Hubicka*/
7 
8 #include <stdlib.h>
9 #include <stdio.h>
10 #include <sys/time.h>
11 #include <unistd.h>
12 #include <aalib.h>
13 
14 #include "general.h"
15 #include "fli.h"
16 
17 #define NAMELEN 256
18 
19 struct OPTIONS {
20 	char filename[NAMELEN];	/* filename given on command line */
21 	char fast;		/* 1 = play without delays */
22 	char verbose;		/* 1 = show info about flic file */
23 	char release;		/* 1 = don't keep frames in memory */
24 	char firstp;		/* 1 = process frames while loading */
25 	char blank;		/* 1 = keep black screen while loading */
26 	char stdinp;		/* 1 = take flic file from stdin */
27 	int speed;		/* speed gotten from command line (-1 if nothing gotten) */
28 	int playrep;		/* nr of times to play animation */
29 } options;
30 
31 struct FLI_FRAMECHUNK {
32 	long size;		/* Size of chunk data part */
33 	long file_offset;	/* Offset of chunk data part into flic file */
34 	int subchunks;		/* Number of subchunks in data part */
35 	void *cd;		/* Pointer to memory containing data part, */
36 				/* is NULL if data not kept in memory */
37 };
38 
39 struct FLI {
40 	char filename[NAMELEN]; /* filename of fli file */
41 	char flc;		/* 0 = fli, 1 = flc */
42 	int mode;		/* vgalib mode number to be used */
43 	int scr_width;		/* width of screen mode used */
44 	int scr_height;		/* guess */
45 	int current;		/* current frame index */
46 	long time;		/* time of last processed frame in usec */
47 	FILE *f;		/* file pointer of opened flic file */
48 	struct FLI_HEADER h;	/* 128 byte fli file header structure */
49 	struct FLI_FRAMECHUNK *frame;
50 				/* pointer to an allocated 'array' of
51 				   <frames> FLI_FRAMECHUNK structs */
52 } fli;
53 
54 
55 static aa_palette pal;
56 static aa_context *context;
57 static aa_renderparams *params;
58 static char *graph_mem;
59 
60 
dcd_color_64(char * data)61 static void dcd_color_64( char *data ) {
62 uchar start = 0;
63 int ops;
64 int count;
65 int i;
66 /*	puts( "color_64" ); */
67 	ops = *(short int *)data;
68 	data = (void *)(((short int *)data) + 1);
69 	while( ops-- > 0 ) {
70 		start += *(uchar *)data;
71 		data = (void *) ((uchar *)data + 1);
72 		if( (count = (int)*(uchar *)data) == 0 )
73 			count = 256;
74 		data = (void *) ((uchar *)data + 1);
75 		for( i=0; i<count; i++ ) {
76 			/* (s)vgalib requires a table of ints for setting a group
77 			 * of colors quickly, but we've got a table of chars :(
78 			 * so we have to set each color individually (slow) */
79 			aa_setpalette(pal, start + i,
80 				((int)*(uchar *)data)*4,
81 				((int)*((uchar *)data+1)*4),
82 				((int)*((uchar *)data+2)*4)
83 			);
84 			data = (void *)((uchar *)data + 3);
85 		}
86 		start += count;
87 	}
88 }
89 
dcd_color_256(char * data)90 static void dcd_color_256( char *data ) {
91 uchar start = 0;
92 int ops;
93 int count;
94 int i;
95 /*	puts( "color_256" ); */
96 	ops = *(short int *)data;
97 	data = (void *)((short int *)data + 1);
98 	while( ops-- > 0 ) {
99 		start += *(uchar *)data;
100 		data = (void *)((uchar *)data + 1);
101 		if( (count = (int)*(uchar *)data) == 0 )
102 			count = 256;
103 		data = (void *)((uchar *)data + 1);
104 		for( i=0; i<count; i++ ) {
105 			aa_setpalette(pal, start + i,
106 				*(uchar *)data >> 2,
107 				*((uchar *)data+1) >> 2,
108 				*((uchar *)data+2) >> 2
109 			);
110 			data = (void *)((uchar *)data + 3);
111 		}
112 		start += count;
113 	}
114 }
115 
memsetw(unsigned short * target,unsigned short w,int count)116 void *memsetw( unsigned short *target, unsigned short w, int count ) {
117 	while( count-->0 ) {
118 		*target++ = w;
119 	}
120 	return( target );
121 }
122 
dcd_delta_flc(struct FLI * fli,char * data)123 static void dcd_delta_flc( struct FLI *fli, char *data ) {
124 short int line;
125 short int nrlines;
126 char *index;
127 short packets;
128 short type;
129 int x;
130 uchar lastbyte;
131 char setlastbyte;
132 /*	puts( "delta flc" ); */
133 	/* get nr of lines in chunk */
134 	nrlines = *(short int *)data;
135 	data = (void *)((short int *)data + 1);
136 	line = 0;
137 	setlastbyte = 0;
138 	lastbyte = 0;	/* this is just to get rid of a compiler warning */
139 	index = graph_mem;
140 
141 	while( nrlines>0 ) { /* don't put nrlines-- here, the continues don't allow it */
142 
143 		type = *(short *)data;
144 		data = (void *)((short *)data + 1);
145 		/* the 2 highest bits of type indicate how to interpret it */
146 		if( type<0 ) {
147 			if( type&0x4000 ) {
148 				/* add to the line number and act as if nothing
149 				 * happened.
150 				 * documentation says it's all right just to
151 				 * add the abs. value of the word, which is the
152 				 * same as subtracting the word as it is always
153 				 * negative.
154 				 */
155 				line -= type;
156 				index += fli->scr_width * (-type);
157 				continue;
158 			}
159 			/* the low byte contains a lastbyte (the last byte
160 			 * on a line in odd-width resolution flic files),
161 			 * this word is followed by the packet count
162 			 */
163 			setlastbyte = 1;
164 			lastbyte = (uchar)(type & 0x00FF);
165 			packets = *(short *)data;
166 			data = (void *)((short *)data + 1);
167 			/* packets can be 0 now if just the last byte
168 			 * changes for this line
169 			 */
170 		}
171 		if( type>=0 ) {
172 			/* the word contains the nr of packets
173 			 * we can just assign this to packets because the
174 			 * high bits are zero
175 			 */
176 			packets = type;
177 		}
178 
179 		/* decode packets */
180 		x = 0;
181 		while( packets-->0 ) {
182 			/* get & decode packet */
183 			x += *(uchar *)data;
184 			data = (void *)((uchar *)data + 1);
185 			type = *(char *)data;
186 			data = (void *)((uchar *)data + 1);
187 			if( (char)type>=0 ) {
188 				/* copy ptype words */
189 				type <<= 1;
190 				memcpy( index + x, data, type );
191 				x += type;
192 				data = (void *)((uchar *)data + type);
193 				continue;
194 			}
195 			type = -(char)type;
196 			memsetw( (ushort *)(index + x), *(ushort *)data, type );
197 			x += type<<1;
198 			data = (void *)((ushort *)data + 1);
199 		}
200 		if( !setlastbyte ) {
201 			index = (char *)((uchar *)index + fli->scr_width);
202 			nrlines--;
203 			continue;
204 		}
205 		/* put lastbyte at end of line */
206 		*(uchar *)(index + fli->scr_width - 1) = lastbyte;
207 		setlastbyte = 0;
208 		index = (char *)((uchar *)index + fli->scr_width);
209 		nrlines--;
210 	}
211 }
212 
213 
dcd_delta_fli(struct FLI * fli,char * data)214 static void dcd_delta_fli( struct FLI *fli, char *data ) {
215 short int line;
216 short int nrlines;
217 char *index;
218 uchar packets;
219 int index_x;
220 char type;
221 /*	puts( "delta fli" ); */
222 	line = *(short int *)data;
223 	data = (void *)((short int *)data + 1);
224 	index = graph_mem + line * fli->scr_width;
225 	nrlines = *(short int *)data;
226 	data = (void *)((short int *)data + 1);
227 	while( nrlines-- > 0 ) {
228 		index_x = 0;
229 		packets = *(uchar *)data;
230 		data = (void *)((uchar *)data + 1);
231 		while( packets > 0 ) {
232 			index_x += *(uchar *)data;
233 			data = (void *)((uchar *)data + 1);
234 			type = *(char *)data;
235 			data = (void *)((char *)data + 1);
236 			if( type >= 0 ) {
237 				memcpy( index + index_x, data, type );
238 				index_x += type;
239 				data = (void *)((uchar *)data + type);
240 				packets--;
241 				continue;
242 			}
243 			memset( index + index_x, *(uchar *)data, -type );
244 			index_x -= type;
245 			data = (void *)((uchar *)data + 1);
246 			packets--;
247 		}
248 		index += fli->scr_width;
249 	}
250 }
251 
252 
253 
dcd_byte_run(struct FLI * fli,char * data)254 static void dcd_byte_run( struct FLI *fli, char *data ) {
255 int lines;
256 int width;
257 char type;
258 int index;
259 int index_x;
260 /* 	puts( "byte run" ); */
261 	lines = fli->h.height;
262 	width = fli->h.width;
263 	index = 0;
264 	while( lines-->0 ) {
265 		data = (void *)((uchar *)data + 1);	/* skip byte containing number of packets */
266 		/* start a loop to decode packets until end of line is reached */
267 		index_x = 0;
268 			while ( index_x < width ) {
269 				type = *((char *)data++);
270 				if( type<0 ) {
271 					/* type now contains nr of bytes to copy to video */
272 					memcpy( graph_mem + index + index_x, (uchar *)data, -type );
273 					index_x -= type;
274 					data = (void *)((uchar *)data - type);
275 				}
276 				else {
277 					memset( graph_mem + index + index_x, *(uchar *)data++, type );
278 					index_x += type;
279 				}
280 			}
281 			index += fli->scr_width;
282 	}
283 }
284 
285 
dcd_black(struct FLI * fli,char * data)286 static void dcd_black( struct FLI *fli, char *data ) {
287 /*	puts( "black" ); */
288 		int l;
289 		uchar *index;
290 
291 		l = fli->h.height;
292 		index = graph_mem;
293 		while( l-- > 0 ) {
294 			memset( index, 0, fli->h.width );
295 			index += fli->scr_width;
296 		}
297 }
298 
dcd_literal(struct FLI * fli,char * data)299 static void dcd_literal( struct FLI *fli, char *data ) {
300 int l;
301 /*	puts( "literal" ); */
302 	l = fli->h.height;
303 	{
304 		/* linear video memory */
305 		char *index;
306 		index = graph_mem;
307 		while( l-- > 0 ) {
308 			memcpy( index, data, fli->h.width );
309 			data = (void *)((uchar *)data + fli->h.width);
310 			index += fli->scr_width;
311 		}
312 	}
313 }
314 
dcd_pstamp(char * data)315 static void dcd_pstamp( char *data ) {
316 /*	puts( "pstamp" ); */
317 }
318 
showhelp(void)319 static void showhelp( void ) {
320 	puts( "FLI Player for Linux (version 0.2a) by John Remyn" );
321 	puts( "modified version for aalib by Jan Hubicka" );
322 	puts( "Now it is ascii arted FLI Player for text mode" );
323 	puts( "Usage:" );
324 	puts( " flip [switch] <filename>" );
325 	puts( "Valid switches are :" );
326 	puts( " -f          Switch off clock synchronization." );
327 	puts( " -v          Show information on flic file." );
328 	puts( " -? -h       Show help." );
329 	puts( " -a          Don't keep frames in memory." );
330 	puts( " -b          Process frames when they are loaded." );
331 	puts( " -c          Keep a blank screen while frames are being loaded." );
332 	puts( " -n <number> Play the animation sequence <n> times." );
333 	puts( " -s <delay>  Set delay between frames to <delay> miliseconds." );
334 	puts( " -           Read flic file from standard input." );
335 	puts( "also standard aalib options are supported" );
336 	puts( " -dim, -bold, -reverse, -normal for enabling attributes");
337 	puts( " -nodim, -nobold, -noreverse, -nonormal for disabling");
338 	puts( "Press H for help on keys while playing." );
339 }
340 
parse_cmdln(int argc,char * argv[],struct OPTIONS * options)341 static void parse_cmdln( int argc, char *argv[], struct OPTIONS *options ) {
342 int i,j;
343 
344 	options->filename[0] = '\0';
345 	options->fast = 0;
346 	options->verbose = 0;
347 	options->release = 0;
348 	options->firstp = 0;
349 	options->blank = 0;
350 	options->playrep = 1;
351 	options->speed = -1;
352 	options->stdinp = 0;
353 	for( i=1; i<argc; i++ ) {
354 		if( *argv[i]=='-' ) {
355 			char c;
356 			int k;
357 			/* argv[i] contains options */
358 			if( *(argv[i]+1)=='\0' ) {
359 				options->stdinp = 1;
360 			}
361 			j = 1;
362 			k = 0;
363 			while( (c = *(argv[i]+j))!='\0' ) {
364 				switch( c ) {
365 					case 'f' : options->fast = 1; break;
366 					case 'v' : options->verbose = 1; break;
367 					case 'a' : options->release = 1; break;
368 					case 'b' : options->firstp = 1; break;
369 					case 'c' : options->blank = 1; break;
370 					case '?' :
371 					case 'h' : showhelp(); exit( 0 ); break;
372 					case 'n' : if( i+k+1<argc ) {
373 							k++;
374 							options->playrep = abs( atoi( argv[i+k] ) );
375 						   }
376 						   break;
377 					case 's' : if( i+k+1<argc ) {
378 							k++;
379 						   	options->speed = abs( atoi( argv[i+k] ) );
380 							/* adjust to some reasonable value */
381 							if (options->speed > 1000) options->speed = 1000;
382 							/* convert to usec */
383 							options->speed *= 1000;
384 						   }
385 						   break;
386 					default  : showhelp();
387 						   puts( "Unknown option." );
388 						   exit( -1 );
389 				}
390 				j++;
391 			}
392 			i = i+k;
393 		}
394 		else {
395 			if( argv[i]!=NULL ) {
396 				/* argv[i] is the filename of the flic file */
397 				strncpy( options->filename, argv[i], NAMELEN );
398 			}
399 		}
400 	}
401 	if( options->filename[0]=='\0' && options->stdinp==0 ) {
402 		showhelp();
403 		puts( "No filename given." );
404 		exit( -1 );
405 	}
406 }
407 
open_fli(struct FLI * fli,struct OPTIONS * options)408 static int open_fli( struct FLI *fli, struct OPTIONS *options ) {
409 	/* open file and read the header */
410 	if( !options->stdinp ) {
411 		fli->f = fopen( fli->filename, "rb" );
412 		if( !fli->f ) {
413 			return 0;
414 		}
415 	}
416 	else {
417 		fli->f = stdin;
418 	}
419 	freadblock( fli->f, sizeof( fli->h.size      ), &(fli->h.size)      );
420 	freadblock( fli->f, sizeof( fli->h.type      ), &(fli->h.type)      );
421 	freadblock( fli->f, sizeof( fli->h.frames    ), &(fli->h.frames)    );
422 	freadblock( fli->f, sizeof( fli->h.width     ), &(fli->h.width)     );
423 	freadblock( fli->f, sizeof( fli->h.height    ), &(fli->h.height)    );
424 	freadblock( fli->f, sizeof( fli->h.depth     ), &(fli->h.depth)     );
425 	freadblock( fli->f, sizeof( fli->h.flags     ), &(fli->h.flags)     );
426 	freadblock( fli->f, sizeof( fli->h.speed     ), &(fli->h.speed)     );
427 	freadblock( fli->f, sizeof( fli->h.reserved0 ), &(fli->h.reserved0) );
428 	freadblock( fli->f, sizeof( fli->h.created   ), &(fli->h.created)   );
429 	freadblock( fli->f, sizeof( fli->h.creator   ), &(fli->h.creator)   );
430 	freadblock( fli->f, sizeof( fli->h.updated   ), &(fli->h.updated)   );
431 	freadblock( fli->f, sizeof( fli->h.updater   ), &(fli->h.updater)   );
432 	freadblock( fli->f, sizeof( fli->h.aspectx   ), &(fli->h.aspectx)   );
433 	freadblock( fli->f, sizeof( fli->h.aspecty   ), &(fli->h.aspecty)   );
434 	freadblock( fli->f, sizeof( fli->h.reserved1 ), &(fli->h.reserved1) );
435 	freadblock( fli->f, sizeof( fli->h.oframe1   ), &(fli->h.oframe1)   );
436 	freadblock( fli->f, sizeof( fli->h.oframe2   ), &(fli->h.oframe2)   );
437 	freadblock( fli->f, sizeof( fli->h.reserved2 ), &(fli->h.reserved2) );
438 
439 	/* now check if it's a flc or a fli and take necessary precautions */
440 	if( (unsigned)fli->h.type==FLITYPE ) {
441 		/* it's a fli. convert as much as possible to flc */
442 		fli->flc = 0;
443 		/* convert frame rate from 1/70 sec to usec */
444 		fli->h.speed *= 100;
445 		fli->h.speed /= 7;
446 		fli->h.speed *= 1000;
447  		/* ascpect ratio is ignored, but fix it anyway */
448 		fli->h.aspectx = 6;
449 		fli->h.aspecty = 5;
450 		/* can't convert frame offsets */
451 	}
452 	else if( (unsigned)fli->h.type==FLCTYPE ) {
453 		fli->flc = 1;
454 		fli->h.speed *= 1000;	/* convert msec to usec */
455 	}
456 	else {
457 		puts( "File type not recognized." );
458 		exit( -1 );
459 	}
460 	return 1;
461 };
462 
463 
describe_fli(struct FLI * fli)464 static void describe_fli( struct FLI *fli ) {
465 	printf( "Filename  %s\n",  fli->filename );
466 	printf( "size      %li\n", fli->h.size );
467 	printf( "type      %x\n",  fli->h.type );
468 	printf( "frames    %i\n",  fli->h.frames );
469 	printf( "width     %i\n",  fli->h.width );
470 	printf( "height    %i\n",  fli->h.height );
471 	printf( "depth     %i\n",  fli->h.depth );
472 	printf( "flags     %x\n",  fli->h.flags );
473 	printf( "speed     %li\n", fli->h.speed );
474 	printf( "aspectx   %i\n",  fli->h.aspectx );
475 	printf( "aspecty   %i\n",  fli->h.aspecty );
476 	printf( "oframe1   %li\n", fli->h.oframe1 );
477 	printf( "oframe2   %li\n", fli->h.oframe2 );
478 };
479 
480 
readchunkheader(FILE * f,struct FLI_CHUNK_HEADER * buf)481 static void readchunkheader( FILE *f, struct FLI_CHUNK_HEADER *buf ) {
482 	freadblock( f, sizeof( buf->size     ), &buf->size );
483 	freadblock( f, sizeof( buf->type     ), &buf->type );
484 	freadblock( f, sizeof( buf->chunks   ), &buf->chunks );
485 	freadblock( f, sizeof( buf->reserved ), &buf->reserved );
486 }
487 
scan_to_frame(struct FLI * fli)488 static void scan_to_frame( struct FLI *fli ) {
489 struct FLI_CHUNK_HEADER buf;
490 struct FLI_FRAMECHUNK *fc;
491 	do {
492 		readchunkheader( fli->f, &buf );
493 		if( buf.type==0xF1FA ) break;
494 		fseek( fli->f, buf.size - FLI_CHUNK_HEADERLEN, SEEK_CUR );
495 	} while ( buf.type!=0xF1FA );
496 	fc = fli->frame + fli->current;
497 	fc->size = buf.size - FLI_CHUNK_HEADERLEN;
498 	fc->subchunks = buf.chunks;
499 	fc->file_offset = ftell( fli->f );
500 	fc->cd = NULL;
501 }
502 
getframechunkdata(struct FLI * fli)503 static void getframechunkdata( struct FLI *fli ) {
504 struct FLI_FRAMECHUNK *fc;
505 void *data;
506 	fc = fli->frame + fli->current;
507 	data = fc->cd;
508 	if( data )
509 		return;	/* frame chunk data already loaded */
510 	if(fc->size) {
511 	data = malloc( fc->size );
512 	if( !data ) {
513 		printf( "cannot allocate memory for frame data\n" );
514 		exit( 1 );
515 	}
516 	fseek( fli->f, fc->file_offset, SEEK_SET );
517 	freadblock( fli->f, fc->size, data );
518 	} else data=NULL;
519 	fc->cd = data;
520 }
521 
releaseframechunkdata(struct FLI * fli)522 static void releaseframechunkdata( struct FLI *fli ) {
523 struct FLI_FRAMECHUNK *fc;
524 	fc = fli->frame + fli->current;
525 	if( fc->cd ) {
526 		free( fc->cd );
527 		fc->cd = NULL;
528 	}
529 }
530 
processframechunk(struct FLI * fli)531 static void processframechunk( struct FLI *fli ) {
532 struct FLI_FRAMECHUNK *fc;
533 void *data;
534 int i;
535 	fc = fli->frame + fli->current;
536 	data = fc->cd;
537 	for( i=0; i<fc->subchunks; i++ ) {
538 		/* switch( chunktype ) */
539 		switch( *((short int *)((char *)data+4)) ) {
540 			case COLOR_256 :
541 				dcd_color_256( (char *)data + 6 );
542 				break;
543 			case DELTA_FLC :
544 				dcd_delta_flc( fli, (char *)data + 6 );
545 				break;
546 			case COLOR_64 :
547 				dcd_color_64( (char *)data + 6 );
548 				break;
549 			case DELTA_FLI :
550 				dcd_delta_fli( fli, (char *)data + 6 );
551 				break;
552 			case BLACK :
553 				dcd_black( fli, (char *)data + 6 );
554 				break;
555 			case BYTE_RUN :
556 				dcd_byte_run( fli, (char *)data + 6 );
557 				break;
558 			case LITERAL :
559 				dcd_literal( fli, (char *)data + 6 );
560 				break;
561 			case PSTAMP :
562 				dcd_pstamp( (char *)data + 6 );
563 				break;
564 			default :
565 				puts( "unknown subchunk" );
566 		}
567 		data = (void *)((char *)data + *(long *)data);
568 	}
569 }
570 
gettime(void)571 long gettime(void) {
572 struct timeval t;
573         gettimeofday(&t, NULL);
574         return(t.tv_usec);
575 }
576 
await()577 int await() {
578 #define T 10000   /* process key every 10ms */
579 int i;
580 long t;
581 	t = gettime();
582 	if (t < fli.time) t = t + 1E6;
583 	t = fli.h.speed - (t - fli.time);
584 	if (t > 0) {
585 		if (t > T) {
586 			for (i = 0; i < (t / T); i++) {
587 				usleep(T);
588 				if (f_getkey() == 'q') return(1);
589 			}
590 			usleep(t % T);
591 		}
592 		else usleep(t);
593 	}
594 	return(f_getkey() == 'q');
595 }
596 
fastscale(char * b1,char * b2,int x1,int x2,int y1,int y2,int width1,int width2)597 static void fastscale(char *b1, char *b2, int x1, int x2, int y1, int y2, int width1, int width2)
598 {
599     int ddx1, ddx, spx = 0, ex;
600     int ddy1, ddy, spy = 0, ey;
601     int x;
602     char *bb1 = b1;
603     width2 -= x2;
604     if (!x1 || !x2 || !y1 || !y2)
605 	return;
606     ddx = x1 + x1;
607     ddx1 = x2 + x2;
608     if (ddx1 < ddx)
609 	spx = ddx / ddx1, ddx %= ddx1;
610     ddy = y1 + y1;
611     ddy1 = y2 + y2;
612     if (ddy1 < ddy)
613 	spy = (ddy / ddy1) * width1, ddy %= ddy1;
614     ey = -ddy1;
615     for (; y2; y2--) {
616 	ex = -ddx1;
617 	for (x = x2; x; x--) {
618 	    *b2 = *b1;
619 	    b2++;
620 	    b1 += spx;
621 	    ex += ddx;
622 	    if (ex > 0) {
623 		b1++;
624 		ex -= ddx1;
625 	    }
626 	}
627 	b2 += width2;
628 	bb1 += spy;
629 	ey += ddy;
630 	if (ey > 0) {
631 	    bb1 += width1;
632 	    ey -= ddy1;
633 	}
634 	b1 = bb1;
635     }
636 }
637 static int resized;
resize(aa_context * c)638 static void resize(aa_context * c)
639 {
640     aa_resize(c);
641     resized = 1;
642 }
643 
yesno(int x,int y,char * string)644 static int yesno(int x, int y, char *string)
645 {
646     char c;
647     aa_puts(context, x, y, AA_SPECIAL, string);
648     aa_flush(context);
649     while ((c = tolower(aa_getkey(context, 1))) != 'y' && c != 'n');
650     return (c == 'y');
651 }
getnum(char * string)652 static int getnum(char *string)
653 {
654     unsigned char c;
655     aa_puts(context, 0, 0, AA_SPECIAL, string);
656     aa_flush(context);
657     while ((c = tolower(aa_getkey(context, 1))) < '0' || c > '9');
658     return (c - '0');
659 }
selectfont(aa_context * c)660 static void selectfont(aa_context * c)
661 {
662     int i = 0, i1;
663     char string[255];
664     for (i = 0; aa_fonts[i] != NULL; i++) {
665 	sprintf(string, "%i - %-40s", i, aa_fonts[i]->name);
666 	aa_puts(context, 0, i, AA_SPECIAL, string);
667     }
668     i1 = getnum("");
669     if (i1 < i)
670 	aa_setfont(c, *(aa_fonts + i1));
671 }
672 
673 #if AA_LIB_VERSION==1 && AA_LIB_MINNOR==0
674 #define SUPPORTED c->driver->params.supported
675 #else
676 #define SUPPORTED c->driverparams.supported
677 #endif
selectsupported(aa_context * c)678 static void selectsupported(aa_context * c)
679 {
680     int supported = c->params.supported;
681     char text[40];
682     int ch;
683     do {
684     char *texts[]={
685       "Normal characters",
686       "Half bright (dim)",
687       "Double bright (bold)",
688       "Bold font",
689       "Reversed",
690       "8 bit ascii",
691       "Control characters"};
692     int masks[]={AA_NORMAL_MASK,AA_DIM_MASK,AA_BOLD_MASK,AA_BOLDFONT_MASK,AA_REVERSE_MASK,AA_EIGHT,AA_ALL};
693     int i;
694     for(i=0;i<7;i++)
695     {
696       sprintf(text,"%i %-20s:%-12s",i+1,texts[i],(SUPPORTED&masks[i])?((supported&masks[i])?"On":"Off"):"Unsupported");
697       aa_puts(c,0,i,AA_SPECIAL,text);
698     }
699     aa_puts(c,0,i,AA_SPECIAL,"8 Leave this menu");
700     aa_flush(c);
701     while ((ch = tolower(aa_getkey(context, 1))) < '1' || ch > '8');
702     ch-='1';
703     if(ch<7) supported^=masks[ch];
704     } while (ch<7);
705 
706     aa_setsupported(c, supported);
707 }
f_getkey(void)708 int f_getkey(void)
709 {
710   int c=aa_getkey(context,0);
711   switch(c) {
712         case 'h':
713         case 'H':
714 	    aa_puts(context,0,0,AA_SPECIAL," aaflip - an ascii art fli/flc player           ");
715 	    aa_puts(context,0,1,AA_SPECIAL,"                                                ");
716 	    aa_puts(context,0,2,AA_SPECIAL," ';' '\\'  - gamma           '<' '>' - bright    ");
717 	    aa_puts(context,0,3,AA_SPECIAL," '[' ']'  - Random dithering',' '.' - contrast  ");
718 	    aa_puts(context,0,4,AA_SPECIAL," 'I' 'i'  - inversion                           ");
719 	    aa_puts(context,0,5,AA_SPECIAL,"                                                ");
720 	    aa_puts(context,0,6,AA_SPECIAL,"   'm'    - Dithering method  'q'   - quit      ");
721 	    aa_puts(context,0,7,AA_SPECIAL,"   'u'    - Select attributes 'g'   - font      ");
722 	    aa_flush(context);
723 	    aa_getkey(context,1);
724 	    break;
725         case ';':
726             params->gamma /= 1.05;
727             break;
728         case '\'':
729             params->gamma *= 1.05;
730             break;
731         case '<':
732             params->bright -= 4;
733             break;
734         case '>':
735             params->bright += 4;
736             break;
737         case '[':
738             params->randomval -= 4;
739             break;
740         case ']':
741             params->randomval += 4;
742             break;
743         case ',':
744             params->contrast -= 2;
745             break;
746         case '.':
747             params->contrast += 2;
748             break;
749         case 'm':
750             params->dither = (params->dither + 1) % AA_DITHERTYPES;
751             break;
752         case 'i':
753             params->inversion = 1;
754 	    break;
755         case 'I':
756             params->inversion = 0;
757 	    break;
758         case 'u':
759 	    selectsupported(context);
760 	    break;
761         case 'g':
762 	    selectfont(context);
763 	    break;
764   }
765   return(c);
766 }
767 
main(int argc,char * argv[])768 int main( int argc, char *argv[] ) {
769 int quit = 0;
770 int playstartframe = 0;
771 int first=1;
772 long t, tdelta;
773 	aa_parseoptions(NULL,NULL,&argc,argv);
774 	parse_cmdln( argc, argv, &options );
775 	strcpy( fli.filename, options.filename );
776 
777 	/* open flic and get header information */
778 	if( !open_fli( &fli, &options ) ) {
779 		puts( "cannot open fli file" );
780 		exit( 1 );
781 	}
782 
783 	/* show header */
784 	if( options.verbose==1 ) {
785 		describe_fli( &fli );
786 	}
787 
788 	/* optionally set delays */
789 	if( options.speed>=0 ) {
790 		fli.h.speed = options.speed;
791 	}
792 
793 	/* optionally reduce delays to 0 (this overrides the set delay option) */
794 	if( options.fast==1 ) {
795 		fli.h.speed = 0;
796 	}
797 
798 
799 	/* silly but might happen */
800 	if( options.playrep<=0 ) {
801 		exit( 0 );
802 	}
803 
804 	/* determine graphics mode to use */
805 	/* set mode */
806 	context=aa_autoinit(&aa_defparams);
807 	if(context==NULL) {
808 	  printf("Failed to initialize aalib\n");
809 	  exit(1);
810 	}
811 	aa_hidecursor(context);
812 	aa_autoinitkbd(context,0);
813 	aa_resizehandler(context,resize);
814 	params=aa_getrenderparams();
815 	fli.scr_width = fli.h.width;
816 	fli.scr_height = fli.h.height;
817 	graph_mem=malloc(fli.scr_width*fli.scr_height);
818 
819 	fli.frame = (struct FLI_FRAMECHUNK *)malloc( (fli.h.frames+1) * sizeof( struct FLI_FRAMECHUNK ) );
820 	if( fli.frame==NULL ) {
821 		puts( "cannot allocate enough memory to store frame information\n" );
822 		exit( 1 );
823 	}
824 
825 	fli.current = 0;
826 	/* preloading */
827 	/* first the 1st frame which is a full screen frame */
828 	scan_to_frame( &fli );
829 
830 	if( !options.blank ) {
831 		getframechunkdata( &fli );
832 		processframechunk( &fli );
833 		releaseframechunkdata( &fli );
834 		playstartframe = 1;
835 	}
836 	else {
837 		getframechunkdata( &fli );
838 		playstartframe = 0;
839 		if( options.release ) {
840 			releaseframechunkdata( &fli );
841 		}
842 	}
843 	fli.current++;
844 	first=1;
845 	while( fli.current<=fli.h.frames && !quit ) {
846 		scan_to_frame( &fli );
847 		getframechunkdata( &fli );
848 		if( options.firstp ) {
849 			fli.time = gettime();
850 			processframechunk( &fli );
851 		}
852 		if( options.release ) {
853 			releaseframechunkdata( &fli );
854 		}
855 		if(first||options.firstp) {
856 			fastscale(graph_mem,context->imagebuffer,
857 			  	  fli.scr_width,aa_imgwidth(context),
858 			  	  fli.scr_height,aa_imgheight(context),
859 			  	  fli.scr_width,aa_imgwidth(context));
860 			aa_renderpalette(context,pal,params,0,0,aa_imgwidth(context),aa_imgheight(context));
861 			if(first&&!options.firstp)
862 		  	  aa_puts(context,0,0,AA_SPECIAL,"Preloading...");
863 			aa_flush(context);
864 		}
865 		fli.current++;
866 		first=0;
867 		if( f_getkey()=='q' ) quit = 1;
868                 if(options.firstp&&!quit) quit = await();
869 	}
870 
871 	if(!quit) {
872 
873  	if( options.firstp ) {
874 		options.playrep--;
875 		if( options.playrep==0 ) {
876 			quit = 1;
877 		}
878 	}
879 
880 	fli.current = playstartframe;
881 	while( !quit ) {
882 		fli.time = gettime();
883 		getframechunkdata( &fli );
884 		processframechunk( &fli );
885 		if( options.release ) {
886 			releaseframechunkdata( &fli );
887 		}
888 		fli.current++;
889 		fastscale(graph_mem,context->imagebuffer,
890 			  fli.scr_width,aa_imgwidth(context),
891 			  fli.scr_height,aa_imgheight(context),
892 			  fli.scr_width,aa_imgwidth(context));
893 		aa_renderpalette(context,pal,params,0,0,aa_imgwidth(context),aa_imgheight(context));
894 		aa_flush(context);
895 		if( fli.current>fli.h.frames ) {
896 			fli.current = 1;
897 			options.playrep--;
898 			if( options.playrep==0 ) {
899 				quit = 1;
900 				break;
901 			}
902 		}
903                 quit = await();
904 
905 	}
906 	}
907 
908 	/* restore textmode */
909 	aa_close(context);
910 
911 	/* close flic */
912 	if( !options.stdinp ) {
913 		fclose( fli.f );
914 	}
915 	fli.f = NULL;
916 	return 0;
917 };
918 
919 
920 
921