SuperVGA Pascal Programmer's graphics library 
Copyleft (C) 1998-1999 Virtual Research i. g.
------------------------------------------------------------------------------
Revision 4
------------------------------------------------------------------------------

LFB256 unit: Programmer's Manual
==============================================================================

[ CONTENTS ]

1. What is LFB256? Why use it?
2. What do I need to use LFB256?
3. Procedures and functions to your service
        3.1 Initialization stuff
        3.2 Drawing stuff
        3.3 Bitmaps
        3.4 Palettes
        3.5 Virtual screens
        3.6 Virtual display
                3.6.1 Scrolling
                3.6.2 Page flipping
        3.7 Image files
        3.8 Fonts and text
                3.8.1 Working with font libraries
        3.9 Miscellaneous routines
4. Global variables and constants
5. Future improvements
6. Contacting the author
------------------------------------------------------------------------------

[ 1. What the hey is LFB256? Why use it? ]


        LFB256 is a graphics library for TMT Pascal compiler v 2.02 or later.
It is called LFB256 because it only supports Linear FrameBuffer 8 bpp (256
colors) video modes via VESA 2.0 API (what actually is all that you need).
LFB256 is a part of VRg SuperVGA Pascal Programmer's library, but it also may
be distributed separately.
        LFB256 can be used either as a standalone graphics library, or
as an add-on, simultaneously with standard TMT GRAPH unit.
        Here are some LFB256 features, that may make you want to use it:

         Some drawing procedures are about 4 times faster then similar
          from GRAPH;
         Included set of procedures for PCX files handling - loading to
          screen, buffer, and saving to disk;
         Useful palette manipulation procedures included;
         Virtual screens management is here for you, even if you don't
          have registered version of compiler;
         Full source code included;
         It is absolutely free.

        LFB256 is freeware. You do not have to pay neither for compiled
binaries nor for source code. You may change the source and use it in any kind
of projects you like to. Actually, you may do _whatever you want_ with it
(except distributing for money, of course). You may think this is very cool
policy. Well, yes, it is. But you also should realize, that author(s) of this
product give(s) no warranties of any kind and take(s) no liability for any
bad things caused by use, misuse or disuse of this product.
------------------------------------------------------------------------------

[ 2. What do I need to use LFB256? ]


        To use LFB256 unit in your projects, you absolutely need the following
things:

[ Hardware: ]

        - 386 or better computer with 80x87 math co-processor;
        - SuperVGA videocard providing VESA 2.0 BIOS extensions, with at least
          1 Mb of videomemory on it (*);
        - Appropriate SuperVGA monitor;
        - At least 2 Mb of system RAM (**).

[ Software: ]

        - TMT Pascal compiler, v. 2.0 or later (registered is preferred);
        - DPMILIB.FPD library (***);
        - GRAPH.FPD library (**); 
        - PMWSTUB loader for TMT Pascal (you can use included
          TMTL, which is also PMODE/W based and is freeware) (**).

[ Notes: ]

        (*) - If your videocard does not provide VESA 2.0 interface you may
              try to use appropriate software emulation, like SciTech's
              Display Doctor (aka UniVBE). It should work for most of modern
              videocards.
              Also, standard VGA 320x200x256 is supported without VESA
              interface.
       (**) - These components aren't really necessary, but _extremely_
              recommended.
      (***) - DPMILIB contains interface to general DPMI functions. If you
              don't have DPMILIB, calls to its functions in LFB256 may be
              relatively easily replaced with direct DPMI calls, or you may
              use some other freeware DPMI interface unit.

[ Important: ]

        LFB256 needs DPMI services in order to call some VESA functions in
real mode. PMWSTUB provides enough of DPMI functions for LFB256, but other
extenders may appear not to have complete DPMI kernel implemented. In this
case, if you don't have PMWSTUB, you need to use external 32-bit DPMI host,
providing DPMI services at least compliant to v. 0.9 of DPMI specification.
        Critical thing here is DPMI function 800h. Currently far not all DOS
extenders provide this service. Check out documentation for your DOS extender
to see if function 800h of INT 31h is supported. If it is not, then you most
likely will have problems with graphics (e. g. lockup or merely blank screen)
when running your program in Protected Mode environment with paging turned on.
------------------------------------------------------------------------------

[ 3. Procedures and functions to your service, and how to use them ]


[ 3.1 Initialization stuff ]


        Initialization procedure differs depending on whether you want to
use LFB256 as a stand-alone or as an add-on graphics library. Also separate
initialization procedure is used when you only want to enable standard VGA
320x200x256 videomode 13h.
        If using LFB256 as a standalone graphics library, you must call
_VBE2_Init procedure before all. You may call it only once. It will search
for VESA extensions, find all available LFB 8 bpp videomodes and set up some
global variables (see more about global variables in the specific section
later). _VBE2_Init has no input parameters. After it finishes, _NumberOfModes
global variable will contain actual number of LFB modes. Even if
_NumberOfModes is set to zero, 320x200 standard VGA mode 13h is always
supported. (But note, that if VESA 2.0 is not present, you won't be able to
use even standard 320x200 videomode, program just terminate with 'Fatal error'
message). Particular videomode number and parameters (like screen resolution)
may be then obtained from _ModeList array. Look at  [ Global variables ]
section for further information.
        If you only want to use standard VGA 320x200 videomode, call
_VGA13_Init instead of _VBE2_Init. This procedure will not look for VESA
BIOS extensions. It sets _NumberOfModes to zero, as well as _VESA_Version,
and _VideoMemory to 64 Kb. Only one videomode (_320x200) is then available.
        If using LFB256 as an add-on to GRAPH library, you _must not_ call
to _VBE2_Init. Instead of it, you have to set up one of available 256-colors
LFB videomodes, for example, via SetSVGAMode function; then, after mode is
set, you have to call _InitGraph procedure from LFB256. This procedure will
set up all needed global variables. After that you may call procedures from
both LFB256 and GRAPH units. _InitGraph has 4 input parameters: XResolution,
YResolution:word - respective resolutions for current mode; VideoMemory:word -
amount of on-card videomemory in Kilobytes; LFB_Address:longint - LFB physical
address. All these values can be obtained via respective GRAPH functions, see
TMT documentation for details.

[ Example: how to use LFB256 and GRAPH in the same time ]

uses LFB256,GRAPH;

begin
 SetSVGAMode(640,480,8,LFBOnly);
 _InitGraph(640,480,TotalVBEMemory shr 10,GetLFBAddress);
  (* That's all *)
  .
  .
  .
end.
..............................................................................

[ 3.2 Drawing stuff ]


        There are set of drawing routines provided by LFB256. You may've found
that in older units from SuperVGA library 1.0 procedures, functions, global
variables and constants were named in some special way: all identifiers were
starting with unit name, written in lower case letters. It was intended to
differ SuperVGA library units identifiers from other BP7 and TMTP units
identifiers without qualifiers usage. But this is not always convenient.
        Nevertheless, LFB256 identifiers must be in some way easily
recognizable and different to standard GRAPH identifiers. Thus, all of LFB256
global identifiers are started with underline sign "_".
        However, some functions/procedures names are started with double
underline "__". This means, that they are drawing routines with clipping
implemented. For example, when you call _Line procedure, coordinates values
_must_ be positive numbers within virtual display coordinates range. But when
you call __Line procedure, you may give anything you want to it, even negative
numbers - they will be clipped in clipwindow bounds if necessary. Clipwindow
bounds are set by call to _SetWindow procedure (see section  [ Miscellaneous
routines ]  below).
        Well, now let's get to drawing stuff.

        NOTE: Also defined XOR versions for all the drawing routines:
              _XORPixel,_XORTransparentPixel,_XORLine,_XORMaskedLine,
              _XORHLine,_XORVLine,_XOREllipse,_XORFilledEllipse,
              _XORRectangle,_XORBar,_XORTriangle,_XORFilledTriangle,
              _XORFillPoly and corresponding routines with clipping.

[ Putting and getting pixel values ]

        There are five procedures:

 procedure _PutPixel(x,y:word;Color:byte);
 procedure __PutPixel(x,y:integer;Color:byte);
 procedure _PutTransparentPixel(x,y:word;Color;byte);
 procedure __PutTransparentPixel(x,y:integer;Color:byte);
 function  _GetPixel(x,y:word):byte;

        _PutPixel puts a pixel of specified color at specified screen
coordinates. Coordinates must be positive integer values somewhere in current
logical display bounds. __PutPixel does the same, but with clipping to
currently set clipwindow. Coordinates here may take negative values.
_PutTransparentPixel and __PutTransparentPixel will not plot a pixel, if its
color equals to _TransparentColor variable. Finally, _GetPixel function will
return color of the pixel at specified logical display coordinates. Note,
that logical display may exceed physical screen bounds. The only restriction
is that (logical screen width)*(logical screen height) must be less or equal
to amount of onboard videomemory. See more details about it below in
_SetLogicalWidth procedure description.

[ Drawing lines ]

        There are 8 procedures:

 procedure _Line(x1,y1,x2,y2:word;Color:byte);
 procedure __Line(x1,y1,x2,y2:integer;Color:byte);
 procedure _MaskedLine(x1,y1,x2,y2:word;Color:byte;Mask:word);
 procedure __MaskedLine(x1,y1,x2,y2:integer;Color:byte;Mask:word);
 procedure _HLine(x1,x2,y:word;Color:byte);
 procedure __HLine(x1,x2,y:integer;Color:byte);
 procedure _VLine(x,y1,y2:word;Color:byte);
 procedure __VLine(x,y1,y2:integer;Color:byte);

        _Line is a general-purpose line procedure. It draws a line from
(x1,y1) to (x2,y2); x1, y1, x2 and y2 values are not limited by special
conditions, except that they must be positive numbers somewhere in virtual
display area. __Line does the same, but clips line within specified
clipwindow. _MaskedLine works similar to line, and __MaskedLine works similar
to __Line, but they allow you to define custom line mask; for example, to draw
dash line set Mask parameter to F0F0h = 1111000011110000b, in that case four
pixels will be visible, next four invisible etc. To draw dash-dot line, set
Mask to CFFCh = 1100111111111100b. I hope you got the idea.
        _HLine and _VLine are specific fast implementations for horizontal and
vertical lines respectively. _HLine draws horizontal line from (x1,y) to
(x2,y). Note, that x1 _must_ be greater or equal to x2, otherwise it won't
work. _VLine draws vertical line from (x,y1) to (x,y2). Again, y1 _must_ be
greater or equal to y2. __HLine and __VLine do the same but with clipping. You
should use _HLine, _VLine, __HLine and __VLine only if you have extremely
speed-critical task. In other cases use _Line and __Line procedures.

[ Drawing ellipses (circles) ]

        There are four procedures:

 procedure _Ellipse(xc,yc,rx,ry:word;Color:byte);
 procedure __Ellipse(xc,yc,rx,ry:integer;Color:byte);
 procedure _FilledEllipse(xc,yc,rx,ry:word;Color:byte);
 procedure __FilledEllipse(xc,yc,rx,ry:integer;Color:byte);

        _Ellipse draws an ellipse with center at (xc,yc), horizontal radius
rx and vertical radius ry, in specified Color. __Ellipse does the same with
clipping (xc,yc,rx and ry may also take negative values). _FilledEllipse and
__FilledEllipse draw an ellipse filled with specified Color.

[ Boxes (aka Rectangles and Bars) ]

        There are 4 procedures for boxes:

 procedure _Rectangle(x1,y1,x2,y2:word;Color:byte);
 procedure __Rectangle(x1,y1,x2,y2:integer;Color:byte);
 procedure _Bar(x1,y1,x2,y2:word;Color:byte);
 procedure __Bar(x1,y1,x2,y2:integer;Color:byte);

        Note, that unlike in SVGA unit, in LFB256 bar and rectangle are
split in two different routines. This speeds things up a little.
        _Rectangle draws a rectangle with upper left corner at (x1,y1) and
lower right corner at (x2,y2). Order of corners _is_ significant! I. e., x1
_must_ be less or equal to x2, and y1 _must_ be less or equal to y2. Otherwise
unpleasant things may happen.
        __Rectangle does the same but with clipping.
        _Bar draws a bar (filled rectangle), filled with specified Color.
Meaning of input parameters is the same that in _Rectangle procedure. __Bar
draws a bar clipped within current clipwindow.

[ Triangles ]

        There are four procedures:

 procedure _Triangle(x1,y1,x2,y2,x3,y3:word;Color:byte);
 procedure __Triangle(x1,y1,x2,y2,x3,y3:integer;Color:byte);
 procedure _FillTriangle(x1,y1,x2,y2,x3,y3:integer;Color:byte);
 procedure __FillTriangle(x1,y1,x2,y2,x3,y3:integer;Color:byte);

        They will draw wireframe or filled triangle respectively, with vertexes
at specified coordinates. Vertexes order is not significant.


[ Polygons ]

        There are only two procedures:

 procedure _FillPoly(var VertexArray;NumOfVertexes,Color:byte);
 procedure __FillPoly(var VertexArray;NumOfVertexes,Color:byte);

        VertexArray must point to array of vertexes coordinates, something
like var VA:array[1..NumOfVertexes,1..2] of word, where VA[,1] is
x-coordinate and VA[,2] is y-coordinate. NumOfVertexes is, naturally, the
number of vertexes, and Color is the color with which polygon will be filled.
This procedure has two _restrictions_: vertexes must be ordered clockwise, and
polygon must be convex.

        That's all about drawing stuff. If you need something more complicated,
you may emulate it with _PutPixel. Or send a message by netmail (see addresses
in section 7 of this document), and I will include needed routine in the next
version of SuperVGA library (huh-ha... nice joke, yeap).
..............................................................................

[ 3.3 Bitmaps ]


        What is bitmaps? Bitmap is a rectangular piece of image, stored
somewhere in memory (in "buffer", if you like like it sounds :) There are many
other names for them, like "images", "sprites" etc. Well, we will call them
"bitmaps", period.
        There are several procedures in LFB256 intended to work with bitmaps,
i. e. get part of the screen to buffer and put bitmap from buffer back to 
screen. Procedures for rescaling and rotating bitmaps are contained in
separate unit BMFX. Procedures for translucent bitmaps are contained in
TRANS256 unit.

        Here go the procs:

 procedure _GetImage(x,y,Width,Height:word;Address:pointer);
 procedure __GetImage(x,y:integer;Width,Height:word;Address:pointer);
 procedure _PutImage(x,y,Width,Height:word;Address:pointer);
 procedure __PutImage(x,y:integer;Width,Height:word;Address:pointer);
 procedure _XORImage(x,y,Width,Height:word;Address:pointer);
 procedure __XORImage(x,y:integer;Width,Height:word;Address:pointer);
 procedure _PutTransparentImage(x,y,Width,Height:word;Address:pointer);
 procedure __PutTransparentImage(x,y:integer;Width,Height:word;
                                  Address:pointer);

        _GetImage copies part of screen to previously allocated memory
buffer; (x,y) specify upper left corner of bitmap, and Width and Height are
bitmap's width and height in pixels. Address is linear address of buffer,
where bitmap will be stored. Address is obtained from GetMem or New
procedures.
        Memory needed for bitmap is Width*Height bytes.
        _PutImage puts previously grabbed image back to screen. Meaning of
parameters is the same that in _GetImage.
        _XORImage will take previously copied to buffer image and XOR its
pixels with those from screen. The trick here is that when you call _XORImage
twice with the same coordinates and the same image, it will disappear from the
screen. It is primarily intended for mouse cursor emulation.
        _PutTransparentImage will not put those pixels from bitmap, which
color is equal to _TransparentColor (see  [ Global variables and constants ]
section). This allows you to create animated sprites easily (however, it is
better to use AND and OR sprite masks for this purpose, for speed reasons).
        __GetImage, __PutImage, __XORImage and __PutTransparentImage are the
"clipped" versions of _PutImage and _PutTransparentImage. Bitmap will be
clipped within current clipwindow. In case of __GetImage, stripped bitmap
parts will left unfilled, if you want to fill them with some specific color,
you must call FillChar for image buffer before calling __GetImage; otherwise
they most likely will appear to be "garbage".
..............................................................................

[ 3.4 Palettes ]


        Some neat tricks could be done by merely reprogramming VGA palette
registers (i. e. DAC color registers). LFB256 gives you twelve procedures for
this. Every complicated palette-programming procedure may be built on their
basis. These procedures are:

 procedure _GetPalette(var Palette);
 procedure _SetPalette(var Palette);
 procedure _Fade(var StartPalette,EndPalette;Speed:real);
 procedure _InitStepFade(var StartPalette,EndPalette;Speed:real);
 function  _StepFade:boolean;
 procedure _SetRGB(Color,R,G,B:byte);
 procedure _GetRGB(Color:byte;var R,G,B:byte);
 procedure _Convert8bppcTo6bppc(var Palette);
 function  _RGB2YUV(RGB:TRGB):TYUV;
 function  _YUV2RGB(YUV:TYUV):TRGB;
 procedure _GammaCorrect(var Palette;Gamma:single);
 procedure _GammaCorrectRGB(var Palette;Gamma:single);

        _GetPalette gets current contents of 256 color registers and puts it
to Palette variable. This variable may be of any type, but its size should be
at least 768 bytes.  (TRGB and TPalette types are provided for convenience
in LFB256 interface part). Each byte represents single color component (Red,
Green or Blue) for each of 256 colors. For example, if Palette is an array
(var Palette:array[0..255][0..2] of byte) then Palette[0][0] will represent
Red component for color 0; Palette[1][2] - Blue component for color 1 etc.
Only 6 lower bytes of each color component are valid, i. e. Palette array
entries may vary in range [0..63].
        _SetPalette copies color components values from Palette variable to
256 VGA color registers.
        Procedures _SetRGB and _GetRGB do basically the same that _SetPalette
and _GetPalette, but for single defined color.
        Procedure _Fade performs so called fade effect. Current display
palette will be smoothly changed from StartPalette to EndPalette. Speed
determines fading speed (the bigger the slower). To perform "fade out" effect,
first get current palette with _GetPalette, then use it as StartPalette and
use _BlankPalette constant as EndPalette. To "fade in" do vice-versa. NOTE:
_Fade procedure needs about 10 K of free stack space.
        _InitStepFade and _StepFade routines allow you to perform palette
fading while doing some other screen manipulations at the same time. You
must call _InitStepFade once, with the same parameters that conventional
_Fade procedure. Then you keep calling _StepFade function until it returns
false. At each call to _StepFade new corresponding palette will be set,
a bit closer to final palette. If _StepFade returns false it means that
fading process is finished. Usually you should do a loop constructions
like "while _StepFade do ... end;".
        _Convert8bppcTo6bppc(var Palette) converts palette from 8 bits per
primary color format (extended 24-bit DAC) to 6 bits per primary color
(standard VGA 18-bit DAC). All LFB256 routines use standard 6 bppc format.
File image processing routines will do this conversion automatically, so
normally you should not use this procedure.
        _RGB2YUV(RGB:TRGB) and _YUV2RGB(YUV:TYUV) will perform color space
conversion. TRGB and TYUV are both records of three bytes each, representing
corresponding color components in different color spaces. YUV color space is
used in some professional graphic images formats, like JPEG.
        _GammaCorrect and _GammaCorrectRGB will perform gamma correction
under given palette. Gamma is a real number in range [0.5..2.0], which
represents graphics-displaying device nonlinearity. These functions may be
necessary for palettes retrieved from scanned images, because scanner and
monitor usually have different nonlinearity factors. _GammaCorrect will
correct luminance of each color, while _GammaCorrectRGB will correct every
component (Red, Green and Blue) of each color.
..............................................................................
        
[ 3.5 Virtual screens ]


        Virtual screen is a memory area somewhere in physical address space,
which is considered as a framebuffer. When you put something to the screen
it actually goes to virtual framebuffer rather then to videomemory. This
feature is extremely useful for animation or slideshow effects.
        LFB256 gives you 4 procedures to deal with virtual screens:

 procedure _SetVirtualOutput(Address:pointer);
 procedure _FlushVirtualScreen(Address:pointer);
 procedure _MoveToVirtualScreen(Address:pointer);
 procedure _SetNormalOutput;

        For first you have to allocate memory block big enough to hold the
entire image. Memory block size should be more or equal to
(_LogicalScreenWidth*_LogicalScreenHeight). See more about these variables
in next section. To allocate memory use GetMem or New procedures, or any
low-level routines from DPMI services. You may allocate as many virtual
screens as you wish, the only limit is amount of available memory.
        Now, when you have allocated memory block and got its linear address,
merely type _SetVirtualOutput(Address). Voila - all further screen output
will be redirected to Address! But, hey, how can we _see_ what we have drawn?
Just use _FlushVirtualScreen(Address) (with correct address, of course) and
virtual screen contents will be instantly displayed. You also can move
currently displayed image to virtual screen, modify it and display later; for
this use _MoveToVirtualScreen(Address). Note, that in every case "Address" is
_virtual screen address_, nothing else. When everything you needed is already
drawn on virtual screen you may return to normal drawing mode by calling to
_SetNormalOutput procedure, without input parameters.
        Here is also one important thing. _FlushVirtualScreen and
_MoveToVirtualScreen always transfer (_LogicalScreenWidth*_LogicalScreenHeight)
bytes, i. e. full virtual display (see next section about virtual display).
After call to _SetLogicalWidth logical screen height will be automatically
set to maximal allowed value. For example, if you have 2 Mb videomemory,
current videomode is 640x480 and you call _SetLogicalWidth(640),
then _LogicalScreenHeight will be set to 2097512/640=3276 pixels. Now, when
you call _FlushVirtualScreen or _MoveToVirtualScreen, 2 Mb of data will be
transferred, even if all that you want is only move 640x480 picture. In
short words, if you do not use any scrolling/pageflipping effects, you
better set _LogicalScreenHeight:=_ModeList[_ModeIndex].YResolution manually
before performing any virtual screen operations.
..............................................................................

[ 3.6 Virtual display ]


        Virtual display is logical screen area, which size may be bigger or
equal to physical display resolution. Maximal virtual display size depends on
videomemory amount. Having virtual display bigger then physical screen allows
you to perform scrolling and/or pageflipping effects.
        There are two procedures in LFB256:

 function _SetLogicalWidth(NewWidth:word):integer;
 function _SetDisplayOrigin(x,y:word):integer;

        As you can see, they both are functions, and return zero on success
or an error code if failed. See  [ Global variables and constants ]  for error
codes description.
        The _SetLogicalWidth function will set new logical width for virtual
display. Input parameter specifies new display width in pixels. Global
variables _LogicalScreenWidth and _LogicalScreenHeight will be automatically
adjusted after call to this function. Note, that _LogicalScreenHeight will
always be set to maximum possible value for given screen width (depending on
amount of videomemory). You may modify _LogicalScreenHeight variable freely,
because it is not related to hardware functionality, unlike
_LogicalScreenWidth, which only should be modified by call to
_SetLogicalWidth.
        The _SetDisplayOrigin will move (x,y) point of virtual display to
the (0,0) point of physical display, thus shifting the entire displayed image.
This function is a key to scrolling effects and pageflipping.
        Note that this functions most likely will not work in standard VGA
320x200 mode.

[ 3.6.1 Virtual scrolling ]

        This thing is called "virtual scrolling" by SciTech, but, actually,
there is nothing virtual in it, because it is pure'n'true scrolling effect.
Here is an example for 640x480:

        ... (* Init stuff here *)
        _SetLogicalWidth(1280); (* Need 1 M or more of videomemory for this *)
        ... (* Drawing stuff here *)
        i:=0;
        for i:=0 to (_LogicalScreenWidth-640) do 
         _SetDisplayOrigin(i,0); (* Do horizontal scrolling *)
        for i:=0 to (_LogicalScreenHeight-480) do
         _SetDisplayOrigin(_LogicalScreenWidth-640,i); (* Do vertical
                                                          scrolling *)
        ... (* Finalization stuff here *)

[ 3.6.2 Pageflipping ]

        Pageflipping is great for animation effects. Here is how to do it:

        procedure SetActivePage(PageNumber:byte);
         (* PageNumber must be in [0..NumOfPages-1] *)
        begin
         _SetVirtualOutput(Ptr(dword(FlatModeList[_ModeIndex].BufferAddress)+
                           dword(_XResolution)*_YResolution*PageNumber));
        end;

        procedure SetVisualPage(PageNumber:byte);
        begin
         _SetDisplayOrigin(0,_YResolution*PageNumber);
        end;

        ... (* Init stuff here *)
        _SetLogicalWidth(640); (* Now we got proper logical height *)
        NumOfPages:=_LogicalScreenHeight div 480;
        ... (* Drawing stuff here *)
        for i:=0 to NumOfPages-1 do begin
         SetVisualPage(i);
         ReadKey; (* wait for keypress *)
        end;
        ... (* Finalization stuff here *)

        Though animation also can be performed with virtual screens,
pageflipping is faster on some videocards, and it also saves memory, because
you don't need to allocate additional virtual screen buffers.
        GRAPH unit contains somewhat more convenient interface for scrolling
and pageflipping; actually, these procedures in LFB256 are just remainder of 
previous LFB256 (FLATVESA) versions.
..............................................................................

[ 3.7 Image files ]


        LFB256 provides a set of functions for managing image-containing
files in PCX format. PCX is an RLE-compressed bitmap. Note, that RLE
compression gives good results only for "cartoon-style" pictures with large
areas filled with the same color, but not for "photographic-style" pictures,
which can even take more disk space then uncompressed. Certain type of images
can only be compressed with JPEG algorithm, which is very complicated, and, I
believe, will never be implemented in SuperVGA library :). But I think, for
now, PCX should be quite enough.
        Here go the functions for image files handling:

 function  _PCX_Display(FileName:string;FileOffset:dword;x,y:word):integer;
 function  _PCX_Buffer(FileName:string;FileOffset:dword;
                        Address:pointer):integer;
 function  _SavePCX(FileName:string;x1,y1,x2,y2:word):integer;
 function  _Get_PCX_Palette(FileName:string;var Palette):integer;
 function  _Get_PCX_Size(FileName:string;FileOffset:dword;
                          var Size:TWindow):integer;

        _PCX_Display(FileName:string;FileOffset:dword;x,y:word) loads
image from specified file and immediately shows it on the screen. You must
set proper palette before calling this function. FileOffset is offset to
PCX file start in somewhat larger data file (library). If loading from single
image file, FileOffset should be set to 0. (x,y) specify coordinates of image's
upper left corner. Image will be clipped if necessary. File format check is
performed.
        _PCX_Buffer(FileName:string;FileOffset:dword;Address:pointer) loads
image to previously allocated memory buffer, so it can be displayed later
with _PutImage procedure. Address is buffer address. FileOffset has the same
meaning that in _PCX_Display function. Buffer must be big enough to hold
entire uncompressed image (i. e. Width*Height bytes). File format check is
performed.
        _SavePCX(FileName:string;x1,y1,x2,y2:word) saves specified part of
screen to PCX file. (x1,y1) is upper left corner and (x2,y2) is lower right
corner of screen part to be saved (order IS significant!). If file with given
name already exists, it _will be overwritten_!
        _Get_PCX_Palette(FileName:string;var Palette) gets image file palette
from specified PCX file and puts it to Palette variable, which must be at
least 768 bytes in size.
        _Get_PCX_Size(FileName:string;FileOffset:dword;var Size:TWindow)
returns image dimensions in Size structure. Size structure contains
corresponding values retrieved from PCX file header. File format check is
performed.
        All functions return zero on success or an error code if failed. See
[ Global variables and constants ]  for error codes.

        There are some specifics for PCX management functions:
        1) _Only_ 256 colors PCX's will be processed, otherwise "Invalid
           file type" will be returned.
        2) _Get_PCX_Palette does not accept FileOffset parameter; the actual
           palette will always be read from the _end_ of file, no matter where
           PCX image is really located. This is because PCX files holds their
           palette at the end of file, and if file is a part of large library,
           it is difficult to locate its end. So, if you have combined several
           PCX files into one library, _Get_PCX_palette will return palette of
           the _last_ file in the library. 

[ Restrictions ]

PCX images with width exceeding 4096 pixels will not be processed. I hope this
is _more_ than enough.
..............................................................................

[ 3.8 Fonts and text ]


        LFB256 supports text output with custom 8x16 bitmap fonts. Font
format is similar to used in BIOS, i. e. just a 4096 bytes of raw data, each
16 bytes represent one character and each byte represents one character line,
in top-to-bottom order. You can create your own fonts with third-party font
editors.
        There are several procedures for fonts handling and text writing:

 procedure _SetFont(Font:pointer);
 procedure _WriteTransparentText(x,y:word;S:string;Color:byte);
 procedure __WriteTransparentText(x,y:word;S:string;Color:byte);
 procedure _WriteOverlappedText(x,y:word;S:string;Color,BkColor:byte);
 procedure __WriteOverlappedText(x,y:word;S:string;Color,BkColor:byte);

        _SetFont will set current font, Font must point to font data. Several
custom fonts are supplied with SuperVGA library distribution. _SetFont must be
called at least once before text-writing procedures.
        _WriteTransparentText will write text string on the screen. (x,y) is
the upper left corner of string area, S is the string itself and Color is
the text color. Text will be 'transparent'. Control characters like CR, LF etc
are not recognized.
        _WriteOverlappedText will do the same, but text will be written in
rectangular area filled with BkColor.

[ 3.8.1 Working with font libraries ]

        FL unit provides the following functions and procedures for working
with fonts assembled to Font Library:

 procedure flCreate(FileName:string;var FL:file);
 function  flGetDir(var FL:file):PFLDir;
 procedure flGetFont(var FL:file;Name:TFontName;Buffer:pointer);
 procedure flAddFont(var FL:file;Name:TFontName;Comment:TComment;Buffer:pointer);
 procedure flDelFont(var FL:file;Name:TFontName);
 procedure flDisposeDir(FLDir:PFLDir);

        Several *.VFL files is supplied with SuperVGA library R4. You can
create your own custom fonts and collect them to a library with FONTLIB.EXE
Font Library Manager. To add description (comment) when adding font to
library, you have to append comment text to the end of font file with DOS
copy utility.
        Here goes the description of FL procedures.
        flCreate(FileName:string;var FL:file) will create new font library.
You must pass path/filename of a new library and a file variable, which will
be assigned to a new font library. File must be untyped and not opened. In all
other routines passed file must be opened as untyped with record length set
to 1 byte.
        flGetDir(var FL:file):PFLDir retrieves directory from a font library
file and returns pointer to it. PFLDir is a pointer to record with following
fields:
        NumEntries:dword;       (* Number of fonts in library *)
        SizeInBytes:dword;      (* Needed for memory management, should
                                   never be modified directly *)
        Entries:array[dword] of TDirEntry;      (* Actual directory. *)
Each directory entry is a record with two fields: FontName:array[0..7] of char
and Comment:array[0..69] of char.
        flGetFont(var FL:file;Name:TFontName;Buffer:pointer) loads font with
specified name from library to specified buffer. Each font occupies 4096 bytes
and, thus, buffer must be able to hold at least 4 K of data.
        flAddFont(var FL:file;Name:TFontName;Comment:TComment;Buffer:pointer)
adds a new font to specified library, with given name and comment. Note, that
no checking is performed if font with given name already exists in library, so
you must be careful.
        flDelFont(var FL:file;Name:TFontName) physically deletes font with a
given name from specified library.
        flDisposeDir(FLDir:PFLDir) frees memory occupied by a font library
directory. FLDir is a pointer returned by flGetDir function.
        If some error occurs when working with font library, its number is
contained in flError global variable after call to a function or procedure,
which caused this error. If no error occurred, flError is zero. Corresponding
error messages are defined in flErrorMessage strings array.
..............................................................................

[ 3.9 Miscellaneous routines ]


        There are several routines, which cannot be included in any of above
sections:

 procedure _SetTextMode;
        Sets 80x25 16-colors text videomode.
 procedure _Fill(Color:byte);
        Fills entire virtual display with specified color.
 procedure _SetWindow(ClipWindow:TWindow);
        Sets current clipwindow. ClipWindow is a record with fields MinX,MinY,
MaxX and MaxY.
 procedure _WaitForVSync;
   Waits for vertical retrace signal. If display is already in retrace state,
this procedure does not perform any delay. Very useful for animation.
 procedure _WaitForVSyncStart;
        Waits for vertical retrace signal. If display already in retrace
state, will wait for next retrace start.
 procedure _Terminate(Message:string;Code:word);
        Sets text videomode 80x25x16 and terminates current program with given
error message and exit code.
 function  Copyleft_Id:string;
        Returns product information string.
------------------------------------------------------------------------------

[ 4. Global variables and constants ]


        Here goes the complete reference to global variables and constants
in LFB256 interface.

 const Version='4.04'; [ Current product version (*) ]
  This is a string containing current library version.

 const _320x200=$13; [ Symbolic names for videomodes (*) ]
        _640x350=$11C;
        _640x400=$100;
        _640x480=$101;
        _800x600=$103;
        _1024x768=$105;
  These are integer values, which are used by BIOS to set particular
  videomode. Full list of available modes should be obtained from
  _ModeList array.

 const ErrorMessage:array[1..16] of string[50]=(..lotsa strings here..);
  [ Descriptions for error codes returned by some functions (*) ]
  This is an array with descriptions of error codes.

 const _WhitePalette:array[0..767] of byte=(63,...); [ Light and dark palettes
        _BlankPalette:array[0..767] of byte=(0,...);    for fading (*) ]
  This is two palettes: with all colors set to black and all colors set
  to bright-white. Should be used for "fade-out" effect.

 type  TModeInfo=record [ Misc. videomodes info. Set by _VBE2_Init (*) ]
         ModeNumber:word; [ current mode number (corresponding to VESA spec.) ]
         XResolution:word; [ current display resolution, horiz. and vert. ]
         YResolution:word;
         BufferAddress:pointer; [ LFB linear address (remapped); this is the 
        end;                      actual pointer to framebuffer ]
  var _ModeList:array[0..255] of TModeInfo;
  This is the list of currently available 256-colors LFB videomodes.
  _ModeList[0] contains description for VGA 320x200 videomode, and _ModeList[1]
  to _ModeList[_NimberOfModes] contain descriptions for VESA LFB videomodes.
  ModeNumber is BIOS mode number; XResolution and YResolution is mode resolution
  in pixels and BufferAddress is linear framebuffer address.

      [ All the following are set by _VBE2_Init ]

     _VESA_Version:word; [ BCD VESA version (*) ]
  This one contains major VESA VBE version in higher byte and minor version
  in lower byte.

     _OEM_String:string; [ VESA OEM string (*) ]
  Contains VESA OEM identifier.

     _VESA_Capabilities:dword; [ Hardware capabilities (*) ]
  This is a bitfield. For more information about this variable see VESA VBE
  specification.

     _VideoMemory:word; [ Videomemory amount in Kb (*) ]
  This is amount of videomemory reported by VESA BIOS.

     _OEM_SoftwareRevision:word;
      [ VESA implementation revision, BCD (*) ]
  Particular VESA VBE implementation version, major in higher byte and
  minor in lower byte.

     _OEM_VendorName:string; [ VESA vendor name (*) ]
  String containing VESA vendor name.

     _OEM_ProductName:string; [ VESA OEM product name (*) ]
  String containing VESA OEM product name. Usually it is videocard model
  for hardware implementations or drivers package name for software
  implementations.

     _OEM_ProductRevision:string; [ VESA OEM product revision (*) ]
  VESA VBE OEM revision, for example 'Rev. A'.

     _Mode:word; [ Current videomode number (*) ]
  Current videomode number used by BIOS.

     _ModeIndex:byte; [ Current mode index in _ModeList (*) ]
  Index of currently set videomode in _ModeList array.

     _XResolution, [ Current X and Y resolution (**) ]
      _YResolution:word;
  Physical resolution for current videomode.

     _MinClipX, [ Clipping window coordinates (**) ]
      _MinClipY, [ they are set up by _SetWindow procedure ]
      _MaxClipX,
      _MaxClipY:word;
  Clipwindow limits for current videomode.

     _LogicalScreenWidth, [ Virtual display size (**) ]
      _LogicalScreenHeight:word;
  Virtual resolution for current videomode.

     _OriginX, [ Virtual display origin (**) ]
      _OriginY:word;            
  Virtual display origin, i. e. upper left screen corner.

 type TWindow=record
   MinX,MinY,MaxX,MaxY:word;
       end;
  var _FullScreen:TWindow; [ Defines fullscreen window, use in _SetWindow (*) ]
  Used to set clipwindow back to full screen size.

     _NumberOfModes:byte; [ Total LFB videomodes supported (*) ]
 Number of VESA LFB 256-colors videomodes. Note that VGA 320x200 is not
 included to this number, however it is always supported.

     _TransparentColor:byte; [ "Transparent" color (***) ]
  Some procedures will not draw pixels if they have this color.

     _FrameBuffer:pointer; [ virtual LFB address (remapped) (*) ]
  This is start address of area where all videodata will be directed.

     _Font:pointer; [ pointer to current font; (**) this one is being
                             set by _SetFont procedure, and is NIL
                             at startup ]
  This one should not be modified directly.

[ Notes: ]
        (*) This items should never be modified by user;
       (**) This items may be modified by user, with _extreme care_,
            but this is not recommended;
      (***) This items may be freely modified by user.
"Modified" means directly assigned a value with ":=" operator, or passed to
procedure as a variable parameter.
Also symbolic names are defined for each error code. Normally you don't need
them, because you may read error code description from _ErrorMessage array.
------------------------------------------------------------------------------

[ 5. Future improvements ]


        To be fair, there are no ideas on my mind. As a basic graphics library
LFB256 is for now complete. Of course I am thinking about 3D stuff, just like
everybody at these days... But it needs some better optimized algorithms that
those used in LFB256, so it will be more likely a separate unit then a LFB256
improvement. Maybe I will add some more procedures, like FloodFill etc.,
though I don't think this is really necessary.
        Also, I have some plans about _very fast_ 320x200 drawing routines
library, which will support standard VGA mode 13h, X-style VGA mode and VESA
LFB 320x200 mode 12Eh. But, you know, I'm sooo lazzzy... ;)
        To decide is up to you. If you think there are some important things
missing or some of implemented things could be implemented in better way,
write to me (see address in the next section). I do not guarantee that your
notes will take any effect... But to try does not hurt.
------------------------------------------------------------------------------

[ 6. Contacting the author ]


        If you really need to say something about VR group graphics library,
write to Alexey Pavluchenko, aka Asp, at

        2:463/304.256@fidonet
        2:463/231.256@fidonet

        Russian, Ukrainian and English language messages accepted.
        Comments, suggestions, bug reports are welcome.

        Thank you for interest to our production.
------------------------------------------------------------------------------

                -- Asp / Virtual Research independent group
                   Written in Anno Domini MCMXCVIII
                   Last updated in July 1999

