{ > 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.