(*
                            FASTWR 4.0

 The FASTWR unit contains five fast, snow-and-flicker-free routines for
 writing directly to (or reading from) the video memory of IBM PC/XT/AT's
 and close compatibles. This new version takes advantage of several new
 features in Turbo Pascal 4.0, notably the new unit capability and the
 ability to link in standard .OBJ files. For an example of how to use
 the routines in FASTWR.TPU, see the demonstration program that follows.

 Routines:
 ---------
 FastWrite : The old standby. Writes strings anywhere on the screen, in any
   screen attribute, as rapidly as possible.
 FastWriteNA : A version of FastWrite that uses the existing screen
   attributes, so that you don't have to specify one. NA stands for No
   Attribute.
 ChangeAttribute : Changes the video attribute in the specified region of
   the screen, leaving the characters untouched. I use this in moving bar
   menus, myself.
 MoveToScreen, MoveFromScreen : These are slightly optimized versions of
   Bela Lubkin's routines of the same name. They differ in several minor
   respects, most notably (a) the Length parameter asks for the number of
   WORDS to move rather than BYTES and (b) they are a bit faster with snow
   prevention off.
 CurrentDisplay : This routine is new to FASTWR 4.0. It returns a scalar
   value indicating whether the current display is a mono card (or Herc),
   a CGA (or compatible), an EGA, MCGA, or VGA. This routine is used by
   ReinitFastWrite when setting WaitForRetrace.
 ReinitFastWrite : This routine is also new. It provides an easy means of
   reinitializing the global variables BaseOfScreen and WaitForRetrace.
   It is called automatically before your program gains control, so it is
   normally needed only in memory resident programs.

 Global variables:
 -----------------
 WaitForRetrace : Comparable to the CheckSnow flag in the standard CRT unit.
   MUST be false if writing to a monochrome display.
 BaseOfScreen : Always either $B000 or $B800, unless you change it. Note
   that ReinitFastWrite, like the CRT unit, assumes the current display page
   is 0.

 Missing routines:
 -----------------
 A couple of routines found in earlier versions of FASTWR are now gone.
 EgaInstalled has been replaced by the more informative CurrentDisplay
 function. GetVideoMode's main function was to initialize WaitForRetrace
 and BaseOfScreen; it has been replaced by ReinitFastWrite. FastWriteV is no
 longer necessary, due to changes in the way that the compiler passes string
 arguments. Plain FastWrite is now just as fast as FastWriteV was.

 Notes:
 ------
 Two penalties are imposed by the use of external assembly language
 routines, as opposed to inline. (1) The order of the parameters passed to
 external routines cannot be changed easily. If you want to change them,
 you'll need MASM (or a compatible assembler). (2) The compiler's "smart
 linking" feature does not work on external routines, since it has no sure
 way of knowing where they end. Although FASTWR.TPU contains less than 600
 bytes of code, you may want to eliminate one or more routines if you're
 certain you'll never use them (FastWriteNA for example). (Again, to do this
 you'll need MASM.) I've used externals for two reasons, by the way: (1) it
 makes it easier for multiple routines to share code (see the CalcOffset
 routine in FASTWR.ASM); (2) string parameters, when passed by value, can be
 accessed as rapidly as VAR parameters, since the compiler cannot generate a
 local copy of the string (saves code and stack space as well as time).

 FASTWR does not support multiple display pages, nor does it work in
 anything other than 80-column text modes. If you need screen writing
 routines that have these capabilities (or even if you don't), you might be
 interested in Turbo Professional 4.0, a powerful library of over 400
 routines designed especially for Turbo Pascal 4.0. Among other things,
 Turbo Professional contains a plug-in replacement for the standard CRT unit
 that incorporates all of the features found in FASTWR and more. For more
 information, contact TurboPower Software at the number shown below.

 Thanks to Marshall Brain, whose own FASTWR.PAS was the basis for mine, and
 to Bela Lubkin and Kim Kokkonen, who helped.


 Copyright (c) 1986,1987 by Brian Foley
 These routines may be freely used and distributed, for both private and
 commercial use, so long as the routines themselves are not sold for profit.

 Brian Foley, CompuServe [76317,3247]
 TurboPower Software
 408-438-8608
 9-5 (PST) Monday-Friday
*)

program FastWriteDemo;
  {-FastWrite demonstration}

uses
  Crt,
  FastWr;

var
  Fore, Back,
  I, Attr : Byte;
  ScreenBuffer : array[1..2000] of Word;
  N : Word;
  C : Char;
const
  Bullet : String = '* FASTER THAN A SPEEDING BULLET! *';

  function  Attribute(Foreground, Background : Byte) : Byte;
    {-Translates foreground and background colors into video attributes.
     "and $7F" masks out the blink bit. Add $80 to the result to set it.}
  begin
    Attribute := ((Background shl 4) + Foreground) and $7F;
  end;

begin
  if WaitForRetrace then begin
    Write('Does your screen generate snow? ');
    C := ReadKey;
    WaitForRetrace := (Upcase(C) = 'Y');
  end;

  if Lo(LastMode) = 3 then begin
    Fore := White;            {make these whatever you want}
    Back := Magenta;
  end
  else begin
    Fore := White;
    Back := Black;
  end;
  Attr := Attribute(Fore, Back);
  TextColor(Fore);
  TextBackground(Back);
  ClrScr;

  FastWrite('FastWriting is still even...', 6, 26, Attr);
  Delay(1000);
  FastWrite('**********************************', 9, 23, Attr);
  for I := 10 to 20 do
    FastWrite(Bullet, I, 23, Attr);
  FastWrite('**********************************', 21, 23, Attr);

  {now save the entire screen}
  MoveFromScreen(Mem[BaseOfScreen:0], ScreenBuffer, 2000);

  {now let's play with the saved screen, setting blink bits}
  for N := 1 to 2000 do
    ScreenBuffer[N] := ScreenBuffer[N] xor $8000;
  Delay(1000);
  FastWrite('Changing attribute bytes....', 6, 26, Attr);
  Delay(1000);
  Attr := Attribute(Back, Fore);

  {now some reverse video}
  ChangeAttribute(2000, 1, 1, Attr);
  for I := 10 to 20 do
    FastWrite('IS PRETTY DARNED FAST NOW TOO!', I, 25, Attr);
  Delay(1000);
  FastWrite('But who says you need to....', 6, 26, Attr);
  Delay(1000);

  {now write fast without messing with attributes}
  for I := 10 to 20 do
    FastWriteNA('MESS WITH THE ATTRIBUTE BYTES?', I, 25);
  Delay(1000);

  {now restore the blinking version of the screen we saved}
  MoveToScreen(ScreenBuffer, Mem[BaseOfScreen:0], 2000);
end.
