'===========================================================================
' Subject: OPENFLI VERSION 0.1 Date: 12-22-98 (21:56)
' Author: Yousuf Philips Code: QB, QBasic, PDS
' Origin: philipz@emirates.net.ae Packet: GRAPHICS.ABC
'===========================================================================
''''''''''''''''''''''''''''''''''''''''
' Program : Plays FLI Files '
' Name : OPENFLI Version 0.1 '
' Programmer : Yousuf Philips '
' Company : Y P I '
' Updated On : 10th of Dec. 1998 '
' Email - [philipz85@hotmail.com] '
' [http://members.xoom.com/Philipz/] '
''''''''''''''''''''''''''''''''''''''''
'/* Do not edit this file if you distribute it. */'
'/* (c) Copyrighted by YPI in 1998 | All Rights Reserved | Public Domain */'
'/* This program has been created by YPI (Basic Programming Incorporation) */'
'/* as a utility to play FLI animation files. In 1996 Carl Gorringe */'
'/* created a similar type of program which played FLI and FLC but it was */'
'/* called slooooow. I have been in contact with Carl and he told me that */'
'/* in 1997 Denis Boyles created VIEWFLI2.BAS which is a replica of his */'
'/* FLI player but used assembly to speed up the display of the frames. */'
'/* Without any assembly just good old BASIC, YPI has created an FLI player*/'
'/* which is as fast as VIEWFLI2.BAS but also works in QBASIC 1.0. I would */'
'/* like to give credit and special thanks to Carl Gorringe. */'
'/* Minor editing was done because of a bug found by Carl Gorringe. Thanks */'
'/* If you use any of this code in your program then you must credit YPI */'
'/* and also Carl Gorringe. This program has been placed in Public Domain */'
'/* and All Rights Are Reserved. */'
'/* YPI has also created a BMP loader and an PCX loader. The source can be */'
'/* gotten from our website */'
'/* The YPI Website has programs for beginners, tutorials and utilities. */'
'/* Carl Gorringe's Email is */'
DECLARE SUB ShowFLI (FileName$)
CLS
PRINT
PRINT " FLI Player for QBASIC - By YPI BASIC Programming Incorporation"
PRINT " Press Any Key When You Want The Program To End"
INPUT " Enter File Name - ", FileName$
IF LEN(LTRIM$(FileName$)) = 0 THEN
END
ELSEIF INSTR(FileName$, ".") = 0 THEN
FileName$ = FileName$ + ".fli"
END IF
CALL ShowFLI(FileName$)
SUB FileFormat
'Flic Files (.FLI) Format description:
'
' The details of a FLI file are moderately complex, but the
'idea behind it is simple: don't bother storing the parts of a
'frame that are the same as the last frame. Not only does this
'save space, but it's very quick. It's faster to leave a pixel
'alone than to set it.
'
' A FLI file has a 128-byte header followed by a sequence of
'frames. The first frame is compressed using a bytewise run-length
'compression scheme. Subsequent frames are stored as the
'difference from the previous frame. (Occasionally the first
'frame and/or subsequent frames are uncompressed.) There is one
'extra frame at the end of a FLI which contains the difference
'between the last frame and the first frame.
'
' The FLI header:
'
' byte size name meaning
' offset
'
' 0 4 size Length of file, for programs that want
' to read the FLI all at once if possible.
' 4 2 magic Set to hex AF11. Please use another
' value here if you change format (even to
' a different resolution) so Autodesk
' Animator won't crash trying to read it.
' 6 2 frames Number of frames in FLI. FLI files have
' a maxium length of 4000 frames.
' 8 2 width Screen width (320).
' 10 2 height Screen height (200).
' 12 2 depth Depth of a pixel (8).
' 14 2 flags Must be 0.
' 16 2 speed Number of video ticks between frames.
' 18 4 next Set to 0.
' 22 4 frit Set to 0.
' 26 102 expand All zeroes -- for future enhancement.
'
' Next are the frames, each of which has a header:
'
' byte size name meaning
' offset
' 0 4 size Bytes in this frame. Autodesk Animator
' demands that this be less than 64K.
' 4 2 magic Always hexadecimal F1FA
' 6 2 chunks Number of 'chunks' in frame.
' 8 8 expand Space for future enhancements. All
' zeros.
'
' After the frame header come the chunks that make up the
'frame. First comes a color chunk if the color map has changed
'>from the last frame. Then comes a pixel chunk if the pixels have
'changed. If the frame is absolutely identical to the last frame
'there will be no chunks at all.
'
' A chunk itself has a header, followed by the data. The
'chunk header is:
'
' byte size name meaning
' offset
' 0 4 size Bytes in this chunk.
' 4 2 type Type of chunk (see below).
'
' There are currently five types of chunks you'll see in a FLI
'file.
'
' 11 FLI_COLOR Compressed color map
' 12 FLI_LC Line compressed -- the most common type
' of compression for any but the first
' frame. Describes the pixel difference
' from the previous frame.
' 13 FLI_BLACK Set whole screen to color 0 (only occurs
' on the first frame).
' 15 FLI_BRUN Bytewise run-length compression -- first
' frame only
' 16 FLI_COPY Indicates uncompressed 64000 bytes soon
' to follow. For those times when
' compression just doesn't work!
'
' The compression schemes are all byte-oriented. If the
'compressed data ends up being an odd length a single pad byte is
'inserted so that the FLI_COPY's always start at an even address
'for faster DMA.
'
'FLI_COLOR Chunks
' The first word is the number of packets in this chunk. This
'is followed directly by the packets. The first byte of a packet
'says how many colors to skip. The next byte says how many colors
'to change. If this byte is zero it is interpreted to mean 256.
'Next follows 3 bytes for each color to change (one each for red,
'green and blue).
'
'FLI_LC Chunks
' This is the most common, and alas, most complex chunk. The
'first word (16 bits) is the number of lines starting from the top
'of the screen that are the same as the previous frame. (For
'example, if there is motion only on the bottom line of screen
'you'd have a 199 here.) The next word is the number of lines
'that do change. Next there is the data for the changing lines
'themselves. Each line is compressed individually; among other
'things this makes it much easier to play back the FLI at a
'reduced size.
'
' The first byte of a compressed line is the number of packets
'in this line. If the line is unchanged from the last frame this
'is zero. The format of an individual packet is:
'
'skip_count
'size_count
'data
'
' The skip count is a single byte. If more than 255 pixels
'are to be skipped it must be broken into 2 packets. The size
'count is also a byte. If it is positive, that many bytes of data
'follow and are to be copied to the screen. If it's negative a
'single byte follows, and is repeated -skip_count times.
'
' In the worst case a FLI_LC frame can be about 70K. If it
'comes out to be 60000 bytes or more Autodesk Animator decides
'compression isn't worthwhile and saves the frame as FLI_COPY.
'
'FLI_BLACK Chunks
' These are very simple. There is no data associated with
'them at all. In fact they are only generated for the first frame
'in Autodesk Animator after the user selects NEW under the FLIC
'menu.
'
'FLI_BRUN Chunks
' These are much like FLI_LC chunks without the skips. They
'start immediately with the data for the first line, and go line-
'by-line from there. The first byte contains the number of
'packets in that line. The format for a packet is:
'
'size_count
'data
'
' If size_count is positive the data consists of a single byte
'which is repeated size_count times. If size_count is negative
'there are -size_count bytes of data which are copied to the
'screen. In Autodesk Animator if the "compressed" data shows signs
'of exceeding 60000 bytes the frame is stored as FLI_COPY instead.
'
'FLI_COPY Chunks
' These are 64000 bytes of data for direct reading onto the
'screen.
'
'-----------------------------------------------------------------------
'And here's the PRO extensions:
'-----------------------------------------------------------------------
'
'This is supplemental info on the AutoDesk Animator FLI and FLC formats.
'
'The following is an attempt at describing the newer chunks and frames
'that are not described in the Turbo C FLI library documentation.
'
' Chunk type Chunk ID
' ---------- -----------
' FLI_DELTA 7 (decimal)
'
' First WORD (16 bits) is the number of compressed lines to follow. Next
' is the data for the changing lines themselves, always starting with the
' first line. Each line is compressed individually.
'
' The first WORD (16 bits) of a compressed line is the number of packets in
' the line. If the number of packets is a negative skip -packets lines.
' If the number of packets is positive, decode the packets. The format of
' an individual packet is:
'
' skip_count
' size_count
' data
'
' The skip count is a single byte. If more than 255 pixels are to be
' skipped, it must be broken into 2 packets. The size_count is also a byte.
' If it is positive, that many WORDS of data follow and are to be copied to
' the screen. If it is negative, a single WORDS value follows, and is to be
' repeated -size_count times.
'
' Chunk type Chunk ID
' ---------- -----------
' FLI_256_COLOR 4 (decimal)
'
' The first WORD is the number of packets in this chunk. This is followed
' directly by the packets. The first byte of a packet is how many colors
' to skip. The next byte is how many colors to change. If this number is
' 0, (zero), it means 256. Next follow 3 bytes for each color to change.
' (One each for red, green and blue).
'
' The only difference between a FLI_256_COLOR chunk (type 4 decimal) and a
' FLI_COLOR chunk (type 11 decimal) is that the values in the type 4 chunk
' range from 0 to 255, and the values in a type 11 chunk range from 0 to 63.
'
' NOTE: WORD refer to a 16 bit int in INTEL (Little Endian) format.
' WORDS refer to two-bytes (16 bits) of consecutive data. (Big Endian)
'
' .FLC special frames and chunks
'
' FLC's may contain all the above chunks plus one other:
'
' Chunk type Chunk ID
' ---------- -----------
' FLI_MINI 18 (decimal) 12 (Hex)
'
' From what I understand, this is a miniture 64 x 32 version of the first
' frame in FLI_BRUN format, used as an button for selecting flc's from
' within Animator Pro. Simply do nothing with this chunk.
'
' FLC New Frame
'
' FLC's also contains a frame with the magic bytes set to hex 00A1. This
' is the first frame in the .flc file. Actually it isn't a frame at all
' but to have several chunks within it that specify file location info
' specific to Animator Pro. IE: filepath, font to use, and .COL file info.
' This FRAME may be skipped while loading. That's right! Ignore it! The
' frame header is the same length as all other frames. So you may read the
' frame header, then skip past the rest of the frame.
'
'
' NOTE: When reading the FLI header on the newer FLI and FLC files, the
' FLI signature bytes are AF12 instead of AF11 used in the older FLI files.
' Also, you cannot ignore the screen width and height they may not be
'320 x 200!
'
' Allowable screen sizes include:
'
' 320 x 200, 640 x 480, 800 x 600, 1280 x 1024
'
'
' NOTE: the delay value between frames appears to be in 1000th's of a
' second instead of 70th's.
END SUB
DEFINT A-Z
SUB ShowFLI (FileName$)
Rep:
OPEN FileName$ FOR BINARY AS #1
IF LOF(1) = 0 THEN
PRINT " FILE IS EMPTY"
CLOSE #255
KILL FileName$
END
END IF
'/* Animation File Header */'
LengthOfFile$ = SPACE$(4): Valid1$ = SPACE$(2): NoOfFrames$ = SPACE$(2)
ScreenWidth$ = SPACE$(2): ScreenHeight$ = SPACE$(2): BitsPerPixel$ = SPACE$(2)
NoOfTicksPerFrame$ = SPACE$(2): Valid2$ = SPACE$(2): EmptySpace$ = SPACE$(110)
GET #1, , LengthOfFile$
GET #1, , Valid1$
GET #1, , NoOfFrames$
GET #1, , ScreenWidth$
GET #1, , ScreenHeight$
GET #1, , BitsPerPixel$
GET #1, , Valid2$
GET #1, , NoOfTicksPerFrame$
GET #1, , EmptySpace$
IF HEX$(CVI(Valid1$)) <> "AF11" THEN
PRINT " INVALID FLI "
SYSTEM
ELSEIF CVI(ScreenWidth$) <> 320 OR CVI(ScreenHeight$) <> 200 THEN
PRINT " FLI IS OF WRONG DIMENSION. WILL NOT PROCEED"
SYSTEM
END IF
SCREEN 13
FOR NumberOfFrames = 1 TO CVI(NoOfFrames$) + 1
'/* Frame Header */'
Bi& = LOC(1) + 1
BytesInFrame$ = SPACE$(4): Valid3$ = SPACE$(2): NoOfChunks$ = SPACE$(2)
EmptySpace$ = SPACE$(8)
GET #1, , BytesInFrame$
GET #1, , Valid3$
GET #1, , NoOfChunks$
GET #1, , EmptySpace$
Bi& = Bi& + CVL(BytesInFrame$)
BytesInChunk$ = SPACE$(4): ChunkType$ = SPACE$(2)
FOR NumberOfChunks = 1 TO CVI(NoOfChunks$)
Di& = LOC(1) + 1
GET #1, , BytesInChunk$
GET #1, , ChunkType$
Di& = Di& + CVL(BytesInChunk$)
ChunkType = CVI(ChunkType$)
IF INKEY$ <> "" THEN END
'/* According to the Chunk Type a different process will be performed */'
IF ChunkType = 11 THEN '/* 11 - FLI_COLOR(64) PALETTE */'
NoOfColorPackets$ = SPACE$(2): NumberOfColorsTOSkip$ = SPACE$(1)
NumberOfColorsToChange$ = SPACE$(1): PaletteRed$ = SPACE$(1)
PaletteGreen$ = SPACE$(1): PaletteBlue$ = SPACE$(1): NoOfColor = 0
IF Repeat = 0 THEN
GET #1, , NoOfColorPackets$
FOR NoOfPacket = 1 TO ASC(NoOfColorPackets$)
GET #1, , NumberOfColorsTOSkip$
GET #1, , NumberOfColorsToChange$
NumberOfColorsToChange = ASC(NumberOfColorsToChange$)
IF NumberOfColorsToChange = 0 THEN NumberOfColorsToChange = 256
NoOfColor = NoOfColor + ASC(NumberOfColorsTOSkip$)
FOR SetPalette = 0 TO NumberOfColorsToChange - 1
GET #1, , PaletteRed$
GET #1, , PaletteGreen$
GET #1, , PaletteBlue$
OUT &H3C8, NoOfColor
OUT &H3C9, ASC(PaletteRed$)
OUT &H3C9, ASC(PaletteGreen$)
OUT &H3C9, ASC(PaletteBlue$)
NoOfColor = NoOfColor + 1
NEXT SetPalette
NEXT NoOfPacket
END IF
ELSEIF ChunkType = 12 THEN '/* 12 - FLI_LC - Line Compressed */'
NoOfLinesNotToChange$ = SPACE$(2): NoOfLinesThatChange$ = SPACE$(2)
NoOfPixelPackets$ = SPACE$(1): NoOfPixelsToSkip$ = SPACE$(1)
NoOfPixels$ = SPACE$(1)
GET #1, , NoOfLinesNotToChange$
GET #1, , NoOfLinesThatChange$
FOR DecodeLine = CVI(NoOfLinesNotToChange$) TO CVI(NoOfLinesThatChange$) + CVI(NoOfLinesNotToChange$) - 1
GET #1, , NoOfPixelPackets$: XPixel = 0
FOR DecodePacket = 1 TO ASC(NoOfPixelPackets$)
GET #1, , NoOfPixelsToSkip$
GET #1, , NoOfPixels$
XPixel = XPixel + ASC(NoOfPixelsToSkip$)
NoOfPixels = ASC(NoOfPixels$)
IF NoOfPixels > 127 THEN
SimilarPixelsColor$ = SPACE$(1)
GET #1, , SimilarPixelsColor$
NoOfPixels = (256 - NoOfPixels)
LINE (XPixel, DecodeLine)-STEP(NoOfPixels - 1, 0), ASC(SimilarPixelsColor$)
XPixel = XPixel + NoOfPixels
ELSE
AllPixels$ = SPACE$(NoOfPixels)
GET #1, , AllPixels$
FOR SetPixel = 0 TO NoOfPixels - 1
PSET (XPixel + SetPixel, DecodeLine), ASC(MID$(AllPixels$, SetPixel + 1, 1))
NEXT SetPixel
XPixel = XPixel + NoOfPixels
END IF
NEXT DecodePacket
NEXT DecodeLine
ELSEIF ChunkType = 13 THEN '/* 13 - FLI_BLACK - Black screen */'
LINE (0, 0)-(319, 199), 0, BF
ELSEIF ChunkType = 15 THEN '/* 15 - FLI_BRUN - Byte Run-Length Compression */'
NoOfPixelPackets$ = SPACE$(1): NoOfPixels$ = SPACE$(1): XPixel% = 0
IF Repeat = 0 THEN
FOR Linez = 0 TO 199
GET #1, , NoOfPixelPackets$
FOR DecodePacket = 1 TO ASC(NoOfPixelPackets$)
GET #1, , NoOfPixels$
NoOfPixels = ASC(NoOfPixels$)
IF NoOfPixels < 128 THEN
SimilarPixelsColor$ = SPACE$(1)
GET #1, , SimilarPixelsColor$
LINE (XPixel, Linez)-STEP(NoOfPixels - 1, 0), ASC(SimilarPixelsColor$)
XPixel = XPixel + NoOfPixels
ELSE
NoOfPixels = (256 - NoOfPixels)
AllPixels$ = SPACE$(NoOfPixels)
GET #1, , AllPixels$
FOR SetPixel = 0 TO NoOfPixels - 1
PSET (XPixel + SetPixel, Linez), ASC(MID$(AllPixels$, SetPixel + 1, 1))
NEXT SetPixel
XPixel = XPixel + NoOfPixels
END IF
NEXT DecodePacket
XPixel = 0
NEXT Linez
END IF
ELSEIF ChunkType = 16 THEN '/* 16 - FLI_COPY - Uncompressed 64000 Bytes */'
PixelColor$ = SPACE$(320)
FOR YPixel = 0 TO 199
GET #1, , PixelColor$
FOR XPixel = 0 TO 319
PSET (XPixel, YPixel), ASC(MID$(PixelColor$, XPixel + 1, 1))
NEXT XPixel
NEXT YPixel
ELSE
PRINT "Invalid FLI Chunk Type.": END
END IF
SEEK #1, Di&
NEXT NumberOfChunks
SEEK #1, Bi&
NEXT NumberOfFrames
CLOSE
Repeat = 1
GOTO Rep:
END SUB