[Back to EGAVGA SWAG index] [Back to Main SWAG index] [Original]
{
> Where can I get TP7 or TP6 source code for playing back FLI animations? If
> there aren't any, is there an efficient, quick, and unnoticeable way to do
> a shell to DOS and run a FLI player program? Any and all help is greatly
> appreciated. Please, if possible, email to the address in my .sig below.
Here is my the unit I use to play FLI files. Hope it Helps.
From: JOHARROW@homeloan.demon.co.uk (John O'Harrow)
}
{----------Written by John O'Harrow 1994----------}
{$G+}
UNIT FliPlay;
INTERFACE
PROCEDURE AAPlay(Filename : String); {Play FLI at default speed}
TYPE
PFliPlayer = ^TFliPlayer;
TFliPlayer = OBJECT
CONSTRUCTOR Init;
DESTRUCTOR Done; VIRTUAL;
PROCEDURE SetSpeed(Speed : Integer); VIRTUAL; {0=Fastest}
PROCEDURE ClearSpeed; VIRTUAL;
PROCEDURE Play(Filename : String); VIRTUAL;
PRIVATE
Buffer : Pointer;
Interval : Integer;
FliFile : File;
END; {TFliPlayer}
IMPLEMENTATION
USES
Crt;
CONST
Clock_Hz = 4608; {Frequency of clock}
Monitor_Hz = 70; {Frequency of monitor}
Clock_Scale = Clock_Hz DIV Monitor_Hz;
CData = $40; {Port number of timer 0}
CMode = $43; {Port number of timer control word}
BufSize = 65528; {Frame buffer size - Must be even}
MCGA = $13; {Number for MCGA mode}
TYPE
MainHeaderRec = RECORD
Padding1 : LongInt;
ID : Word;
Frames : Word;
Padding2 : LongInt;
Padding3 : LongInt;
Speed : Word;
Padding4 : ARRAY[1..110] OF Char; {Pad to 128 Bytes}
END; {MainHeaderRec}
FrameHeaderRec = RECORD
Size : LongInt;
Padding1 : Word;
Chunks : Word;
Padding2 : ARRAY[1..8] OF Char; {Pad to 16 Bytes}
END; {FrameHeaderRec}
{---------------------------------------------------------------------------}
PROCEDURE VideoMode(Mode : Word);
INLINE ($58/$CD/$10); {POP AX/INT 10}
PROCEDURE InitClock; ASSEMBLER; {Taken from the FLILIB source}
ASM
mov al,00110100b
out CMode,al
xor al,al
out CData,al
out CData,al
END; {InitClock}
FUNCTION GetClock : LongInt; ASSEMBLER; {Taken from the FLILIB source}
{this routine returns a clock with occassional spikes where time
will look like its running backwards 1/18th of a second. The resolution
of the clock is 1/(18*256) = 1/4608 second. 66 ticks of this clock
are supposed to be equal to a monitor 1/70 second tick.}
ASM
mov ah,0 {get tick count from Dos and use For hi 3 Bytes}
int 01ah {lo order count in DX, hi order in CX}
mov ah,dl
mov dl,dh
mov dh,cl
mov al,0 {read lo Byte straight from timer chip}
out CMode,al {latch count}
mov al,1
out CMode,al {set up to read count}
in al,CData {read in lo Byte (and discard)}
in al,CData {hi Byte into al}
neg al {make it so counting up instead of down}
END; {GetClock}
PROCEDURE DrawFrame(Buffer : Pointer; Chunks : Word); ASSEMBLER;
{this is the routine that takes a frame and put it on the screen}
ASM
cli {disable interrupts}
push ds
push es
lds si,Buffer {let DS:SI point at the frame to be drawn}
@Fli_Loop: {main loop that goes through all the chunks in a
frame}
cmp Chunks,0 {are there any more chunks to draw?}
je @Exit
dec Chunks {decrement Chunks For the chunk to process now}
mov ax,[Word ptr ds:si+4] {let AX have the ChunkType}
add si,6 {skip the ChunkHeader}
cmp ax,0Bh {is it a FLI_COLor chunk?}
je @Fli_Color
cmp ax,0Ch {is it a FLI_LC chunk?}
je @Fli_Lc
cmp ax,0Dh {is it a FLI_BLACK chunk?}
je @Fli_Black
cmp ax,0Fh {is it a FLI_BRUN chunk?}
je @Fli_Brun
cmp ax,10h {is it a FLI_COPY chunk?}
je @Fli_Copy
jmp @Fli_Loop {This command should not be necessary }
@Fli_Color:
mov bx,[Word ptr ds:si] {number of packets in this chunk (always 1?)}
add si,2 {skip the NumberofPackets}
mov al,0 {start at color 0}
xor cx,cx {reset CX}
@Color_Loop:
or bx,bx {set flags}
jz @Fli_Loop {Exit if no more packages}
dec bx {decrement NumberofPackages For the package to
process now}
mov cl,[Byte ptr ds:si+0] {first Byte in packet tells how many colors to
skip}
add al,cl {add the skiped colors to the start to get the
new start}
mov dx,$3C8 {PEL Address Write Mode Register}
out dx,al {tell the VGA card what color we start changing}
inc dx {at the port abow the PEL_A_W_M_R is the PEL
Data Register}
mov cl,[Byte ptr ds:si+1] {next Byte in packet tells how many colors to
change}
or cl,cl {set the flags}
jnz @Jump_Over {if NumberstoChange=0 then NumberstoChange=256}
inc ch {CH=1 and CL=0 => CX=256}
@Jump_Over:
add al,cl {update the color to start at}
mov di,cx {since each color is made of 3 Bytes (Red, Green
& Blue) we have to -}
shl cx,1 {- multiply CX (the data counter) With 3}
add cx,di {- CX = old_CX shl 1 + old_CX (the fastest way
to multiply With 3)}
add si,2 {skip the NumberstoSkip and NumberstoChange
Bytes}
rep outsb {put the color data to the VGA card FAST!}
jmp @Color_Loop {finish With this packet - jump back}
@Fli_Lc:
mov ax,0A000h
mov es,ax {let ES point at the screen segment}
mov di,[Word ptr ds:si+0] {put LinestoSkip into DI -}
mov ax,di {- to get the offset address to this line we
have to multiply With 320 -}
shl ax,8 {- DI = old_DI shl 8 + old_DI shl 6 -}
shl di,6 {- it is the same as DI = old_DI*256 + old_DI*64
= old_DI*320 -}
add di,ax {- but this way is faster than a plain mul}
mov bx,[Word ptr ds:si+2] {put LinestoChange into BX}
add si,4 {skip the LinestoSkip and LinestoChange Words}
xor cx,cx {reset cx}
@Line_Loop:
or bx,bx {set flags}
jz @Fli_Loop {Exit if no more lines to change}
dec bx
mov dl,[Byte ptr ds:si] {put PacketsInLine into DL}
inc si {skip the PacketsInLine Byte}
push di {save the offset address of this line}
@Pack_Loop:
or dl,dl {set flags}
jz @Next_Line {Exit if no more packets in this line}
dec dl
mov cl,[Byte ptr ds:si+0] {put BytestoSkip into CL}
add di,cx {update the offset address}
mov cl,[Byte ptr ds:si+1] {put BytesofDatatoCome into CL}
or cl,cl {set flags}
jns @Copy_Bytes {no SIGN means that CL number of data is to come
-}
{- else the next data should be put -CL number
of times}
mov al,[Byte ptr ds:si+2] {put the Byte to be Repeated into AL}
add si,3 {skip the packet}
neg cl {Repeat -CL times}
rep stosb
jmp @Pack_Loop {finish With this packet}
@Copy_Bytes:
add si,2 {skip the two count Bytes at the start of the
packet}
rep movsb
jmp @Pack_Loop {finish With this packet}
@Next_Line:
pop di {restore the old offset address of the current
line}
add di,320 {offset address to the next line}
jmp @Line_Loop
@Fli_Black:
mov ax,0A000h
mov es,ax {let ES:DI point to the start of the screen}
xor di,di
mov cx,32000 {number of Words in a screen}
xor ax,ax {color 0 is to be put on the screen}
rep stosw
jmp @Fli_Loop {jump back to main loop}
@Fli_Brun:
mov ax,0A000h
mov es,ax {let ES:DI point at the start of the screen}
xor di,di
mov bx,200 {numbers of lines in a screen}
xor cx,cx
@Line_Loop2:
mov dl,[Byte ptr ds:si] {put PacketsInLine into DL}
inc si {skip the PacketsInLine Byte}
push di {save the offset address of this line}
@Pack_Loop2:
or dl,dl {set flags}
jz @Next_Line2 {Exit if no more packets in this line}
dec dl
mov cl,[Byte ptr ds:si] {put BytesofDatatoCome into CL}
or cl,cl {set flags}
js @Copy_Bytes2 {SIGN meens that CL number of data is to come -}
{- else the next data should be put -CL number
of times}
mov al,[Byte ptr ds:si+1] {put the Byte to be Repeated into AL}
add si,2 {skip the packet}
rep stosb
jmp @Pack_Loop2 {finish With this packet}
@Copy_Bytes2:
inc si {skip the count Byte at the start of the packet}
neg cl {Repeat -CL times}
rep movsb
jmp @Pack_Loop2 {finish With this packet}
@Next_Line2:
pop di {restore the old offset address of the current
line}
add di,320 {offset address to the next line}
dec bx {any more lines to draw?}
jnz @Line_Loop2
jmp @Fli_Loop {jump back to main loop}
@Fli_Copy:
mov ax,0A000h
mov es,ax {let ES:DI point to the start of the screen}
xor di,di
mov cx,32000 {number of Words in a screen}
rep movsw
jmp @Fli_Loop {jump back to main loop}
@Exit:
sti {enable interrupts}
pop es
pop ds
END; {DrawFrame}
CONSTRUCTOR TFliPlayer.Init;
BEGIN
IF MemAvail < BufSize THEN Fail;
GetMem(Buffer,BufSize);
ClearSpeed;
END; {Init}
DESTRUCTOR TFliPlayer.Done;
BEGIN
FreeMem(Buffer,BufSize);
END; {Done}
PROCEDURE TFliPlayer.SetSpeed(Speed : Integer);
BEGIN
Interval := Speed * Clock_Scale;
END; {SetSpeed}
PROCEDURE TFliPlayer.ClearSpeed;
BEGIN
Interval := -1;
END; {ClearSpeed}
PROCEDURE TFliPlayer.Play(Filename : String);
VAR
MainHeader : MainHeaderRec;
FrameHeader : FrameHeaderRec;
FrameSize : LongInt;
RestartPos : LongInt;
Frame : Word;
Timeout : LongInt;
FUNCTION ReadHeader : Boolean;
BEGIN
BlockRead(FliFile,MainHeader,SizeOf(MainHeader)); {Read header record}
WITH MainHeader DO
IF ID <> $AF11 THEN
ReadHeader := FALSE {Not a .FLI File}
ELSE
BEGIN
IF Interval = -1 THEN {Read speed from header}
Interval := Speed * Clock_Scale;
ReadHeader := TRUE;
END;
END; {ReadHeader}
PROCEDURE ReadFrame;
BEGIN
BlockRead(FliFile,FrameHeader,SizeOf(FrameHeader));
FrameSize := FrameHeader.Size - SizeOf(FrameHeader);
END; {ReadFrame}
PROCEDURE ProcessFrame;
BEGIN
BlockRead(FliFile,Buffer^,FrameSize);
DrawFrame(Buffer,FrameHeader.Chunks);
END; {ProcessFrame}
BEGIN {Play}
{$I-}
Assign(FLiFile,Filename);
Reset(FliFile,1);
IF (IOResult = 0) THEN
BEGIN
IF ReadHeader THEN
BEGIN
VideoMode(MCGA);
InitClock;
ReadFrame;
RestartPos := SizeOf(MainHeader) + SizeOf(FrameHeader) + FrameSize;
ProcessFrame;
REPEAT
Frame := 1;
REPEAT
Timeout := GetClock + Interval;
ReadFrame;
IF FrameSize <> 0 THEN
ProcessFrame;
REPEAT UNTIL GetClock > Timeout;
Inc(Frame);
UNTIL (Frame > MainHeader.Frames) OR Keypressed;
Seek(FliFile,RestartPos);
UNTIL Keypressed;
VideoMode(CO80);
END;
Close(FliFile);
END;
{$I+}
END; {Play}
{---------------------------------------------------------------------------}
FUNCTION Is286Able: Boolean; ASSEMBLER;
ASM
PUSHF
POP BX
AND BX,0FFFH
PUSH BX
POPF
PUSHF
POP BX
AND BX,0F000H
CMP BX,0F000H
MOV AX,0
JZ @@1
MOV AX,1
@@1:
END; {Is286Able}
FUNCTION IsVGA : Boolean; ASSEMBLER;
ASM
MOV AX,1A00h
MOV BL,10h
INT 10h
CMP BL,8
MOV AX,1
JZ @@1
MOV AX,0
@@1:
END; {IsVGA}
PROCEDURE AAPlay(Filename : String);
VAR
Player : TFliPlayer;
BEGIN
IF Is286Able AND IsVga THEN
WITH Player DO
IF Init THEN
BEGIN
Play(Filename);
Done;
END;
END; {AAPlay}
{===========================================================================}
END.
[Back to EGAVGA SWAG index] [Back to Main SWAG index] [Original]