/************************************************************************
   Проссмотр файлов FLI и FLC. Размер откомпиллированой программы 838 байт.
   Программа выводит изображение только в формате 320х200.
   Программу написал Михаил Шекер (Fido 2:5021/3.111) 8 августа 1998года.
*************************************************************************/
?parsecommandline TRUE
?resize TRUE
?use80386
?codesize
?jumptomain NONE

?include "WRITE.H--"
?include "VIDEO.H--"
?include "KEYCODES.H--"
?include "FILE.H--"

?define LOOPFLI TRUE

word HANDL;					//Номер обработчика файла
word PAUSE;				//Длина паузы между картинками
word DATA_COUNT;	//Счетчик для LC
dword OFSFRAIM;		//начало следующ кадра
word TEMP;
byte C256;

main()
{
	IF(@PARAMCOUNT()!=0){
		SETVIDEOMODE(0X13);
		DX=PARAMSTR(0);
		PLAYFLI();
		SETVIDEOMODE(3);
	}
	ELSE @WRITESTR("FLI Player.\nNo file name in command string!\n");
}

PLAYFLI()
{
	@GETMEM(0x1000);	//блок памяти под буфер
	FS=AX;
	HANDL=@FOPEN(char 0);	//открыть файл
	IF(AX==0)return();
	READFAR(,HANDL,128,FS);	//считать заголовок
	IF(FSWORD[4]==0XAF11)TEMP=1;	//это FLI
	ELSE TEMP=2;
	PAUSE=FSWORD[16];     //скорость
	OFSFRAIM=128;
	for(;;){
		@LSEEK(,HANDL,DSWORD[#OFSFRAIM+2],DSWORD[#OFSFRAIM]);
		READFAR(,,16,FS);//считать кадр
		if(AX==16){
			OFSFRAIM+=FSDWORD[0];
			CX=FSWORD[6];       //число блоков в кадре
			IF(CX==0)continue;	//если кадр пустой то следующий
			IF(FSWORD[4]==0XF100)continue;	//пропустить этот кадр
			loop(CX){						//вывод блоков
				$PUSH CX
				IF(@BIOSKEYCHECK()!=0){  // проверить на окончание
					@BIOSREADKEY();
					$POP CX
					BREAK 1;
				}
				PAUSE_FLI();
				READFAR(,HANDL,6,FS);   //заголовок блока
				DI=FSWORD[4];	//тип блока
				READFAR(,,FSWORD[0]-6,FS);//загрузить блок
				SWITCH(DI){  //разбор типов блоков
					CASE 11:
						C256=FALSE;
						FLI_COLOR();
						BREAK;
					CASE 4:
						C256=TRUE;
						FLI_COLOR();
						BREAK;
					CASE 15:
						FLI_BRUN();
						BREAK;
					CASE 12:
						FLI_LC();
						BREAK;
					CASE 7:
						FLI_DELTA();
						BREAK;
					CASE 16:
						FLI_COPY();
				}
				$POP CX
			}
		}
		ELSE{
			IF(LOOPFLI==FALSE)BREAK;	//прервать если однократное проигрывание
			OFSFRAIM=128;     //Указатель на повторное проигрывание
		}
	}
//END:
	@FCLOSE(,HANDL);
	@FREEMEM(FS);
}

PAUSE_FLI()
//задержка
{
	DX=PAUSE;
	CX=TEMP;
	AH=0X86;
	$INT 0X15
}

FLI_LC()
{
	ES=0XA000;
	SI=0;
	DS=FS;
	$LODSW    //начальная строка
	AX=AX*320;
	DI><AX;
	$LODSW    //число изменяемых строк
	CSWORD[#DATA_COUNT]=AX;
	DX=DI;
	do{
		DI=DX;
		$LODSB	//число пакетов
		BL=AL;
		WHILE(BL!=0){
			$LODSB //смещение в строке
			AH=0;
			DI+=AX;
			$LODSB //число байт
			IF(char AL<0){
				-AL;   //повторение
				CX><AX;
				$LODSB
				$REP
				$STOSB
			}
			ELSE{
				CX><AX; //копирование
				$REP
				$MOVSB
			}
			BL--;
		}
		DX+=320;
		CSWORD[#DATA_COUNT]--;
	}while(NOTZEROFLAG);
	DS=CS;
}

FLI_BRUN()
{
	ES=0XA000;
	SI=0;
	DX=0;
	DS=FS;
	do{
		DI=DX;
		$LODSB //число пакетов в строке
		BL=AL;
		WHILE(BL!=0){
			AH=0;
			$LODSB //число ,байт
			IF(char AL<0){ //копировать
				-AL;
				CX><AX;
				$REP
				$MOVSB
			}
			ELSE{
				CX><AX; //повторить
				$LODSB
				$REP
				$STOSB
			}
			BL--;
		}
		DX+=320;
	}while(DX<64000);
	DS=CS;
}

FLI_DELTA()
{
	ES=0XA000;
	DS=FS;
	SI=0;
	DI=0;
	$LODSW	//всего сжатых строк
	CX><AX;
	loop(CX){
		$PUSH CX
LL1:
		$LODSW	//число пакетов в стоке
		IF(int AX <0){//если отрицательное
			-AX;        //пропускаем строки
			AX=AX*320;
			DI+=AX;
			GOTO LL1;
		}
		CX=AX;
		$PUSH DI
		loop(CX){
			$PUSH CX
			$LODSB //смещение в строке
			AH=0;
			DI+=AX;
			$LODSB //число слов
			IF(char AL < 0){ //если отрицательное
				-AL;
				CX><AX;
				$LODSW        //слово-образ
				$REP          //повторить на экране
				$STOSW
			}
			ELSE{          //иначе
				CX><AX;       //скопировать на экран
				$REP
				$MOVSW
			}
			$POP CX
		}
		$POP DI
		DI+=320;
		$POP CX
	}
	DS=CS;
}

FLI_COLOR()
//установка палитры
{
	SI=0;
	DS=FS;
	$LODSW	//всего блоков
	CX><AX;
	DI=0;
	loop(CX){
		$PUSH CX
		AH=0;
		$LODSB	//пропустить цветов
		DI+=AX;
		BX=DI;	//стартовый цвет
		$LODSB  //всего цветов
		IF(AL==0)AH=1;
		CX=AX;
		CX<<=1;
		CX+=AX;	//умножить на 3
		DI+=AX; //начальный номер цвета в след цикле
		DX=0X3C8;
		AL=BL;
		$OUT DX,AL
		DX++;
		loop(CX){
			$LODSB
			IF(CSBYTE[#C256]!=FALSE)$SHR AL,2	//если 4 тип то делить на 4
			$OUT DX,AL
		}
		$POP CX
	}
	DS=CS;
}

FLI_COPY()
{
	ES=0XA000;
	DS=FS;
	SI=0;
	DI=0;
	CX=16000;
	$REP
	$MOVSD
	DS=CS;
}
