[Back to MISC SWAG index] [Back to Main SWAG index] [Original]

    {$G+}

    Program FliPlayer;

    {  v1.1 made by Thaco   }
    { (c) EPOS, August 1992 }

    Const
      CLOCK_HZ              =4608;                   { Frequency of clock }
      MONItoR_HZ            =70;                     { Frequency of monitor }
      CLOCK_SCALE           =CLOCK_HZ div MONItoR_HZ;

      BUFFERSIZE            =$FFFE;                  { Size of the framebuffer, must be an even number }
      CDATA                 =$040;                   { Port number of timer 0 }
      CMODE                 =$043;                   { Port number of timers control Word }
      CO80                  =$3;                     { Number For standard Text mode }
      KEYBOARD              =28;                     { Numbers returned by PorT[$64] indicating what hardware caused inT 09/the - }
      MOUSE                 =60;                     { - number on PorT[$60] }
      MCGA                  =$13;                    { Number For MCGA mode }
      MCGACheck:Boolean     =True;                   { Variable For MCGA checking }
      UseXMS:Boolean        =True;                   { Variable For XMS usage }
      XMSError:Byte         =0;                      { Variable indicating the errornumber returned from the last XMS operation }

    Type
      EMMStructure          =Record
                               BytestoMoveLo,              { Low Word of Bytes to move. NB: Must be even! }
                               BytestoMoveHi,              { High Word of Bytes to move }
                               SourceHandle,               { Handle number of source (SH=0 => conventional memory) }
                               SourceoffsetLo,             { Low Word of source offset, or ofS if SH=0 }
                               SourceoffsetHi,             { High Word of source offset, or SEG if SH=0 }
                               DestinationHandle,          { Handle number of destination (DH=0 => conventional memory) }
                               DestinationoffsetLo,        { Low Word of destination offset, or ofS if DH=0 }
                               DestinationoffsetHi  :Word; { High Word of destination offset, or SEG if DH=0 }
                             end;
      HeaderType            =Array[0..128] of Byte;  { A bufferType used to read all kinds of headers }

    Var
      Key,                                           { Variable used to check if a key has been pressed }
      OldKey                :Byte;                   { Variable used to check if a key has been pressed }
      XMSRecord             :EMMStructure;           { Variable For passing values to the XMS routine }
      InputFile             :File;                   { Variable For the incomming .FLI File }
      Header                :HeaderType;             { Buffer used to read all kinds of headers }
      Counter,                                       { General purpose counter }
      Speed                 :Integer;                { Timedifference in video tics from one frame to the next }
      FileCounter,                                   { Variable telling the point to read from in the File stored in XMS }
      FileSize,                                      { Size of the .FLI-File }
      FrameSize,                                     { Variable indicating the datasize of current frame }
      NextTime,                                      { Variable saying when it is time to move on to the next frame }
      TimeCounter,                                   { Holding the current time in video tics }
      SecondPos             :LongInt;                { Number of Bytes to skip from the start of the .FLI File when starting - }
                                                     { - from the beginning again }
      Buffer,                                        { Pointer to the Framebuffer }
      XMSEntryPoint         :Pointer;                { Entry point of the XMS routine in memory }
      SpeedString           :String[2];              { String used to parse the -sNN command }
      FileName              :String[13];             { String holding the name of the .FLI-File }
      BufferHandle,                                  { Handle number returned from the XMS routine }
      BytesRead,                                     { Variable telling the numbers of Bytes read from the .FLI File }
      FrameNumber,                                   { Number of the current frame }
      Frames,                                        { total number of frames }
      Chunks                :Word;                   { total number of chunks in a frame }

    Function UpCaseString(Streng:String):String;
    { takes a String and convert all letters to upperCase }
    Var
      DummyString           :String;
      Counter               :Integer;
    begin
      DummyString:='';
      For Counter:=1 to Length(Streng) do
        DummyString:=DummyString+UpCase(Streng[Counter]);
      UpCaseString:=DummyString;
    end;

    Procedure InitMode(Mode:Word); Assembler;
    { Uses BIOS interrupts to set a videomode }
    Asm
      mov  ax,Mode
      int  10h
    end;

    Function ModeSupport(Mode:Word):Boolean; Assembler;
    { Uses BIOS interrupts to check if a videomode is supported }
    Label Exit, Last_Modes, No_Support, Supported;
    Var
      DisplayInfo           :Array[1..64] of Byte;   { Array For storing Functionality/state inFormation }
    Asm
      push es

      mov  ah,1Bh                                    { the Functionality/state inFormation request at int 10h }
      mov  bx,0                                      { 0 = return Functionality/state inFormation }
      push ds                                        { push DS on the stack and pop it into ES so ES:DI could be used to - }
      pop  es                                        { - address DisplayInfo, as demanded of the interrupt Function }
      mov  di,offset DisplayInfo
      int  10h

      les  di,[dWord ptr es:di]                      { The first dWord in the buffer For state inFormation is the address - }
                                                     { - of static funtionality table }
      mov  cx,Mode                                   { Can only check For the 0h-13h modes }
      cmp  cx,13h
      ja   No_Support                                { Return 'no support' For modes > 13h }

      mov  ax,1                                      { Shift the right Byte the right - }
                                                     { - times and test For the right - }
      cmp  cx,10h                                    { - bit For knowing if the       - }
      jae  Last_Modes                                { - videomode is supported       - }
                                                     { -                                }
      shl  ax,cl                                     { -                                }
      test ax,[Word ptr es:di+0]                     { -                                }
      jz   No_Support                                { -                                }
      jmp  Supported                                 { -                                }
                                                     { -                                }
    Last_Modes:                                      { -                                }
      sub  cx,10h                                    { -                                }
      shl  ax,cl                                     { -                                }
      test al,[Byte ptr es:di+2]                     { -                                }
      jz   No_Support                                { -                                }

    Supported:
      mov  al,1                                      { AL=1 makes the Function return True }
      jmp  Exit

    No_Support:
      mov  al,0                                      { AL=0 makes the Function return True }

    Exit:
      pop  es
    end;

    Function NoXMS:Boolean; Assembler;
    { checks out if there is a XMS driver installed, and in Case it initialize the
      XMSEntryPoint Variable }
    Label JumpOver;
    Asm
      push es

      mov  ax,4300h                                  { AX = 4300h => inSTALLATION CHECK }
      int  2Fh                                       { use int 2Fh Extended MEMorY SPECifICATION (XMS) }
      mov  bl,1                                      { use BL as a flag to indicate success }
      cmp  al,80h                                    { is a XMS driver installed? }
      jne  JumpOver
      mov  ax,4310h                                  { AX = 4310h => GET DRIVER ADDRESS }
      int  2Fh
      mov  [Word ptr XMSEntryPoint+0],BX             { initialize low Word of XMSEntryPoint }
      mov  [Word ptr XMSEntryPoint+2],ES             { initialize high Word of XMSEntryPoint }
      mov  bl,0                                      { indicate success }
    JumpOver:
      mov  al,bl                                     { make the Function return True (AH=1) or False (AH=0) }

      pop  es
    end;

    Function XMSMaxAvail:Word; Assembler;
    { returns size of largest contiguous block of XMS in kilo (1024) Bytes }
    Label JumpOver;
    Asm
      mov  ah,08h                                    { 'Query free Extended memory' Function }
      mov  XMSError,0                                { clear error Variable }
      call [dWord ptr XMSEntryPoint]
      or   ax,ax                                     { check For error }
      jnz  JumpOver
      mov  XMSError,bl                               { errornumber stored in BL }
    JumpOver:                                        { AX=largest contiguous block of XMS }
    end;

    Function XMSGetMem(SizeInKB:Word):Word; Assembler;
    { allocates specified numbers of kilo (1024) Bytes of XMS and return a handle
      to this XMS block }
    Label JumpOver;
    Asm
      mov  ah,09h                                    { 'Allocate Extended memory block' Function }
      mov  dx,SizeInKB                               { number of KB requested }
      mov  XMSError,0                                { clear error Variable }
      call [dWord ptr XMSEntryPoint]
      or   ax,ax                                     { check For error }
      jnz  JumpOver
      mov  XMSError,bl                               { errornumber stored in BL }
    JumpOver:
      mov  ax,dx                                     { return handle number to XMS block }
    end;

    Procedure XMSFreeMem(Handle:Word); Assembler;
    Label JumpOver;
    Asm
      mov  ah,0Ah                                    { 'Free Extended memory block' Function }
      mov  dx,Handle                                 { XMS's handle number to free }
      mov  XMSError,0                                { clear error Variable }
      call [dWord ptr XMSEntryPoint]
      or   ax,ax                                     { check For error }
      jnz  JumpOver
      mov  XMSError,bl                               { errornumber stored in BL }
    JumpOver:
    end;

    Procedure XMSMove(Var EMMParamBlock:EMMStructure); Assembler;
    Label JumpOver;
    Asm
      push ds
      push es
      push ds
      pop  es
      mov  ah,0Bh                                    { 'Move Extended memory block' Function }
      mov  XMSError,0                                { clear error Variable }
      lds  si,EMMParamBlock                          { DS:SI -> data to pass to the XMS routine }
      call [dWord ptr es:XMSEntryPoint]
      or   ax,ax                                     { check For error }
      jnz  JumpOver
      mov  XMSError,bl                               { errornumber stored in BL }
    JumpOver:
      pop  es
      pop  ds
    end;

    Procedure ExitDuetoXMSError;
    begin
      InitMode(CO80);
      WriteLn('ERRor! XMS routine has reported error ',XMSError);
      XMSFreeMem(BufferHandle);
      Halt(0);
    end;

    Procedure GetBlock(Var Buffer; Size:Word);
    { reads a specified numbers of data from a diskFile or XMS into a buffer }
    Var
      XMSRecord             :EMMStructure;
      NumberofBytes         :Word;
    begin
      if UseXMS then
      begin
        NumberofBytes:=Size;
        if Size MOD 2=1 then
          Inc(NumberofBytes);  { one must allways ask For a EQUAL number of Bytes }
        With XMSRecord do
        begin
          BytestoMoveLo      :=NumberofBytes;
          BytestoMoveHi      :=0;
          SourceHandle       :=BufferHandle;
          SourceoffsetLo     :=FileCounter MOD 65536;
          SourceoffsetHi     :=FileCounter div 65536;
          DestinationHandle  :=0;
          DestinationoffsetLo:=ofs(Buffer);
          DestinationoffsetHi:=Seg(Buffer);
        end;
        XMSMove(XMSRecord);
        if XMSError<>0 then
          ExitDuetoXMSError;
        Inc(FileCounter,Size);
      end
      else
        BlockRead(InputFile,Buffer,Size);
    end;

    Procedure InitClock; Assembler; {Taken from the FLILIB source}
    Asm
      mov  al,00110100b                                 { put it into liNear count instead of divide by 2 }
      out  CMODE,al
      xor  al,al
      out  CDATA,al
      out  CDATA,al
    end;

    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;

    Procedure TreatFrame(Buffer:Pointer;Chunks:Word); Assembler;
    { this is the 'workhorse' routine that takes a frame and put it on the screen }
    { chunk by chunk }
    Label
      Color_Loop, Copy_Bytes, Copy_Bytes2, Exit, Fli_Black, Fli_Brun, Fli_Color,
      Fli_Copy, Fli_Lc, Fli_Loop, Jump_Over, Line_Loop, Line_Loop2, Next_Line,
      Next_Line2, Pack_Loop, Pack_Loop2;
    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 since the Program should make one - }
                                                     { - of the other jumps }

    Fli_Color:
      mov  bx,[Word ptr ds:si]                       { number of packets in this chunk (allways 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;

    begin
      WriteLn;
      WriteLn('.FLI-Player v1.1 by Thaco');
      WriteLn('  (c) EPOS, August 1992');
      WriteLn;
      if ParamCount=0 then                           { if no input parameters then Write the 'usage Text' }
      begin
        WriteLn('USAGE: FLIPLAY <options> <Filename>');
        WriteLn('                   '+#24+'         '+#24);
        WriteLn('                   ³         ÀÄÄ  Filename of .FLI File');
        WriteLn('                   ÀÄÄÄÄÄÄÄÄÄÄÄÄ  -d   = Do not use XMS');
        WriteLn('                                  -i   = InFormation about the Program');
        WriteLn('                                  -n   = No checking of MCGA mode support');
        WriteLn('                                  -sNN = Set playspeed to NN video ticks (0-99)');
        WriteLn('                                         ( NN=70 ÷ frame Delay of 1 second )');
        Halt(0);
      end;

      For Counter:=1 to ParamCount do                { search through the input parameters For a -Info option }
        if Pos('-I',UpCaseString(ParamStr(Counter)))<>0 then
        begin
          WriteLn('Program inFormation:');
          WriteLn('This Program plays animations (sequences of pictures) made by Programs like',#10#13,
                  'Autodesk Animator (so called .FLI-Files). The Program decodes the .FLI File,',#10#13,
                  'frame by frame, and Uses the systemclock For mesuring the time-Delay between',#10#13,
                  'each frame.');
          WriteLn('Basis For the Program was the FliLib package made by Jim Kent, but since the',#10#13,
                  'original source was written in C, and I am not a good C-Writer, I decided',#10#13,
                  'to Write my own .FLI-player in Turbo Pascal v6.0.');
          WriteLn('This Program was made by Eirik Milch Pedersen (thaco@solan.Unit.no).');
          WriteLn('Copyright Eirik Pedersens Own SoftwareCompany (EPOS), August 1992');
          WriteLn;
          WriteLn('Autodesk Animator is (c) Autodesk Inc');
          WriteLn('FliLib is (c) Dancing Flame');
          WriteLn('Turbo Pascal is (c) Borland International Inc');
          Halt(0);
        end;

      Speed:=-1;
      Counter:=1;
      While (Copy(ParamStr(Counter),1,1)='-') and (ParamCount>=Counter) do { search through the input parameters to assemble them }
      begin
       if Pos('-D',UpCaseString(ParamStr(Counter)))<>0 then  { do not use XMS For storing the File into memory }
         UseXMS:=False
       else
         if Pos('-N',UpCaseString(ParamStr(Counter)))<>0 then  { do not check For a vga card present }
           MCGACheck:=False
         else
           if Pos('-S',UpCaseString(ParamStr(Counter)))<>0 then { speed override has been specified }
           begin
             SpeedString:=Copy(ParamStr(Counter),3,2);  { cut out the NN parameter }
             if not(SpeedString[1] in ['0'..'9']) or    { check if the NN parameter is legal }
                (not(SpeedString[2] in ['0'..'9',' ']) and (Length(SpeedString)=2)) then
             begin
               WriteLn('ERRor! Can not parse speed ''',SpeedString,'''.');
               Halt(0);
             end;
             Speed:=Byte(SpeedString[1])-48;  { take the first number, in ASCII, and convert it to a standard number }
             if Length(SpeedString)=2 then    { if there is two numbers then multiply the first With 10 and add the next }
               Speed:=Speed*10+Byte(SpeedString[2])-48;
             Speed:=Speed*CLOCK_SCALE;        { convert the speed to number of clock tics }
           end;
       Inc(Counter);
      end;

      if ParamCount<Counter then
      begin
        WriteLn('ERRor! No Filename specified.');
        Halt(0);
      end;

      FileName:=UpCaseString(ParamStr(Counter));
      if Pos('.',FileName)=0 then  { find out if there exist a . in the Filename }
        FileName:=FileName+'.FLI'; { if not then add the .FLI extension on the Filename }

      if MaxAvail<BUFFERSIZE then   { check if there is enough memory to the frame buffer }
      begin
        WriteLn('ERRor! Can not allocate enough memory to a frame buffer.');
        Halt(0);
      end;

      GetMem(Buffer,BUFFERSIZE);
      Assign(InputFile,FileName);
      Reset(InputFile,1);
      if Ioresult<>0 then  { has an error occured during opening the File? }
      begin
        WriteLn('ERRor! Can not open File ''',FileName,'''.');
        Halt(0);
      end;

      if not(MCGACheck) or ModeSupport(MCGA) then
        InitMode(MCGA)
      else
      begin
        WriteLn('ERRor! Video mode 013h - 320x200x256 colors - is not supported.');
        Halt(0);
      end;

      BlockRead(InputFile,Header,128);  { read the .FLI main header }

      if not((Header[4]=$11) and (Header[5]=$AF)) then  { check if the File has got the magic number }
      begin
        InitMode(CO80);
        WriteLn('ERRor! File ''',FileName,''' is of a wrong File Type.');
        Halt(0);
      end;

      if NoXMS then  { if no XMS driver present then do not use XMS }
        UseXMS:=False;

      if UseXMS then
      begin
        FileSize:=Header[0]+256*(LongInt(Header[1])+256*(LongInt(Header[2])+256*LongInt(Header[3])));
        if XMSMaxAvail<=(FileSize+1023) SHR 10 then  { is there enough XMS (rounded up to Nearest KB) availible? }
        begin
          WriteLn('ERRor! not enough XMS For the File');
          Halt(0);
        end
        else
        begin
          Seek(InputFile,0);  { skip back to start of .FLI-File to put it all into XMS }
          BufferHandle:=XMSGetMem((FileSize+1023) SHR 10);  { allocate XMS For the whole .FLI File }
          FileCounter:=0;
          Repeat
            BlockRead(InputFile,Buffer^,BUFFERSIZE,BytesRead);  { read a part from the .FLI File }
            if BytesRead MOD 2=1 then  { since BUFFERSIZE shoud be an even number, the only time this triggers is the last part }
              Inc(BytesRead);          { must be done because the XMS routine demands an even number of Bytes to be moved }
            if BytesRead<>0 then
            begin
              With XMSRecord do  { put data into the XMSRecord }
              begin
                BytestoMoveLo      :=BytesRead;
                BytestoMoveHi      :=0;
                SourceHandle       :=0;
                SourceoffsetLo     :=ofs(Buffer^);
                SourceoffsetHi     :=Seg(Buffer^);
                DestinationHandle  :=BufferHandle;
                DestinationoffsetLo:=FileCounter MOD 65536;
                DestinationoffsetHi:=FileCounter div 65536;
              end;
              XMSMove(XMSRecord);   { move Bytes to XMS }
              if XMSError<>0 then   { have any XMS errors occured? }
                ExitDuetoXMSError;
              Inc(FileCounter,BytesRead);  { update the offset into XMS where to put the next Bytes }
            end;
          Until BytesRead<>BUFFERSIZE;  { Repeat Until Bytes read <> Bytes tried to read => end of File }
        end;
        FileCounter:=128;  { we continue (after reading the .FLI File into XMS) right after the .FLI main header }
      end;

      Frames:=Header[6]+Header[7]*256;  { get the number of frames from the .FLI-header }
      if Speed=-1 then                  { if speed is not set by a speed override then get it from the .FLI-header }
        Speed:=(Header[16]+Integer(Header[17])*256)*CLOCK_SCALE;
      InitClock;  { initialize the System Clock }
      OldKey:=PorT[$60];  { get the current value from the keyboard }
      Key:=OldKey;        { and set the 'current key' Variable to the same value }

      GetBlock(Header,16);  { read the first frame-header }
      FrameSize:=Header[0]+256*(LongInt(Header[1])+256*(LongInt(Header[2])+256*LongInt(Header[3])))-16;  { calculate framesize }
      SecondPos:=128+16+FrameSize;  { calculate what position to skip to when the .FLI is finished and is going to start again - }
                                    { the position = .FLI-header + first_frame-header + first_framesize }
      Chunks:=Header[6]+Header[7]*256;  { calculate number of chunks in frame }
      GetBlock(Buffer^,FrameSize);  { read the frame into the framebuffer }
      TreatFrame(Buffer,Chunks);  { treat the first frame }

      TimeCounter:=GetClock;  { get the current time }

      {
        The first frame must be handeled separatly from the rest. This is because the rest of the frames are updates/changes of the
        first frame.
        At the end of the .FLI-File there is one extra frame who handles the changes from the last frame to the first frame.
      }

      Repeat
        FrameNumber:=1;  { we start at the first frame (after the initial frame) }
        Repeat
          GetBlock(Header,16);  { read frame-header }
          FrameSize:=Header[0]+256*(LongInt(Header[1])+256*(LongInt(Header[2])+256*LongInt(Header[3])))-16;  { size of frame }
          if FrameSize<>0 then  { sometimes there are no changes from one frame to the next (used For extra Delays). In such - }
                                { - Cases the size of the frame is 0 and we don't have to process them }
          begin
            Chunks:=Header[6]+Header[7]*256;  { calculate number of chunks in the frame }
            GetBlock(Buffer^,FrameSize);  { read the frame into the framebuffer }
            TreatFrame(Buffer,Chunks);  { treat the frame }
          end;

          NextTime:=TimeCounter+Speed;   { calculate the Delay to the next frame }
          While TimeCounter<NextTime do  { wait For this long }
            TimeCounter:=GetClock;

          if PorT[$64]=KEYBOARD then   { check if the value at the keyboard port is caused by a key pressed }
            Key:=PorT[$60];            { get the current value from the keyboard }
          Inc(FrameNumber);  { one frame finished, over to the next one }
        Until (FrameNumber>Frames) or (Key<>OldKey);  { Repeated Until we come to the last frame or a key is pressed }

        if UseXMS then
          FileCounter:=SecondPos
        else
          Seek(InputFile,SecondPos);  { set current position in the File to the second frame }

      Until Key<>OldKey;  { Exit the loop if a key has been pressed }

      InitMode(CO80);  { get back to Text mode }

      Close(InputFile);            { be a kind boy and close the File beFore we end the Program }
      FreeMem(Buffer,BUFFERSIZE);  { and free the framebuffer }

      if UseXMS then
        XMSFreeMem(BufferHandle);
    END.

[Back to MISC SWAG index] [Back to Main SWAG index] [Original]