JiNX 2D Graphics System (J2D) - By Mark Hodson, 1996-99

This library is freeware.  The only provision is that the programme using this
code must display in its credits (if it has any) an acknowledgement of the use
and original source of this code.

ie. "JiNX 2D Graphics System by Mark Hodson".


Introduction
~~~~~~~~~~~~
This library is designed to make high resolution 2D graphics programming under
DOS a breeze.  It runs on any VESA 1.2 or 2.0 compliant video card.

The paradigm behind the system is "assumed success" - whereby you request a
video mode and the J2D system will, short of some serious failure, allow you
to use that mode even if it is not supported in hardware.

This is achieved by picking the closest mode to that which you requested, and
performing the necessary colour depth and size conversions when it comes time
to update the screen.  This may sound like a significant overhead, but in fact
the J2D system chooses an alternative mode which minimises recalculation time.
Sometimes the alternative updates faster than the original mode!


Compatibility Algorithm
~~~~~~~~~~~~~~~~~~~~~~~
When requesting an 8bit mode, the following algorithm is employed to find a
suitable hardware mode:

  Does the exact 8bit mode exist?
    YES -> Success (direct).
    NO -> Pick the closest 8bit mode larger in both x and y dimensions.
      FOUND SUCH A MODE -> Success (with 8bit scaling).
      NO SUCH MODE -> Is the mode requested 320x200?
        YES -> Success (MCGA compatibility).
        NO -> Failure.

When requesting a 24bit mode, the following algorithm is employed to find a
suitable hardware mode:

  Does the exact 24bit mode exist?
    YES -> Success (direct).
    NO -> Does an 8bit mode of the same dimensions exist?
      YES -> Success (24bit to 8bit conversion)
      NO -> Pick the closest 8bit mode larger in both x and y dimensions.
        FOUND SUCH A MODE -> Success (with conversion and 8bit scaling).
        NO SUCH MODE -> Is the mode requested 320x200?
          YES -> Success (conversion and MCGA compatibility).
          NO -> Failure.

This guarentees you will always get some sort of mode of equal or better
resolution than you requested, although it may have reduced colour depth.

The 24bit->8bit conversion uses a standard palette, and palette allocation is
transparent to the user, who still assumes a 24bit screen.

If you only request a resolution of 320x200, then even if no VESA hardware
exists, you will be guarenteed success, at worst using the MCGA 320x200x256c
standard VGA video mode.


Functions
~~~~~~~~~
Unless otherwise specified, each J2D function returns a character value, which
is 0 for no error, or non-zero for an error.  If a non-zero value is returned,
it can be used to access an error string array to obtain a description of the
error.

  extern char *J2D_ErrorString[];


Initialisation and Deinitialisation:

  char J2D_MakeWorkspace(void);

    This function simply allocates a few K of realmode memory for interfacing
    with the VESA hardware.  It should be the first function which you call.

  char J2D_KillWorkspace(void);

    This function deallocates the same realmode memory.  It should be the last
    function which you call.


Hardware Information Routines:

  char J2D_GetControllerInfo(J2D_ControllerInfo *info);

    This function obtains information about your video card, using the VESA
    interface.  It should be the 2nd function you call.  You must have
    allocated the memory for the controller info structure yourself.

  char J2D_GetGraphicsMode(J2D_ModeInfo *info, int x_size, int y_size, int type);

    This function requests a video mode of your specification.  The mode will
    be "x_size" pixels across, "y_size" pixels high, and "type" specifies the
    bit depth of each pixel by use of the defines "J2D_8BIT" and "J2D_24BIT".
    As above the memory for the mode info structure must have been allocated,
    and the J2D_GetControllerInfo function must have previously been called.

  char J2D_Compatibility(void);

    This function returns a bit vector telling you what compatibility measures
    the J2D system is taking to give you the requested mode.

    If bit 0 (mask 1) is set, then your 24bit requested mode is being emulated
      in 8bits.
    If bit 1 (mask 2) is set, then your requested mode is being rescaled to
      meet the size of the nearest available mode.
    If bit 2 (mask 4) is set, then the J2D system is running in MCGA mode,
      either because it was the closest match or there is no VESA hardware.


Mode Setting Routines:

  void J2D_DisableLFB(void);

    This function stops the J2D system from using a linear frame buffer if
    there is one.  Can't think of any good reason why you'd want to do this.

  void J2D_SetMode(void);

    All the previous functions do is prepare the J2D system for entering the
    chosen graphics mode.  They do not actually change the hardware screen
    mode itself.

    This function is the function which finally changes the hardware screen
    mode.  All checks for errors have been done in previous functions, so this
    one will always succeed.


Hardware Screen Size and Display Start Routines:

  char J2D_SetScanlineWidth(short pixels_per_scanline);

    This function attempts to change the physical number of pixels on each
    scanline.  The default is the same number as are viewable, but on most
    video cards this value can be increased, allowing some sort of horizontal
    scrolling of the viewable area within a larger screen.

    This function could have unpredictable results if you are in any sort of
    compatibility mode.

  char J2D_SetDisplayWindow(short x_coord, short y_coord);

    This function sets the top left-hand corner of the display window,
    allowing hardware scrolling.  The default is (0,0).

    Again this function could have unpredictable results if you are in any
    sort of compatibility mode.  Software scrolling is much more reliable.
    

Palette Routines:

  char J2D_SetPalette6bit(char *palette);

    Sets the palette using 6bit values stored in a 1K RGBx (x ignored) format.
    Hence each value for R, G and B must range from 0 to 63.  The reason the
    1K palette format is used rather than a 768 byte packed structure is that
    VESA 2.0 has an inbuilt function for setting the palette which requires
    this format.


Virtual Screen Clearing and Updating Routines:

  void J2D_SetVirtualScreenSize(int vsc_x_size, int vsc_y_size);

    It is up to you to allocate memory for your virtual screens, of which you
    will need at least 1.  The virtual screen format used by the J2D system is
    a packed-bytes format.

    8bit 256c screens therefore require vsc_x_size*vsc_y_size bytes, and 24bit
    16Mc screens require 3*vsc_x_size*vsc_y_size bytes.

    Before plotting your virtual screen you must tell the J2D system how large
    it is.  This is achieved using this function.  Your virtual screen may be
    smaller or the same size as the hardware screen you requested, but not
    larger (hence software scrolling cannot be implemented by making an over-
    sized virtual screen).

    You must call this function before any of the following.

  void J2D_Clear256c(char *vsc, char colour);
  void J2D_Clear16Mc(char *vsc, char red, char green, char blue);

    These functions clear the virtual screen (of size previously specified)
    with the colour supplied as parameters.  Which routine you use depends on
    whether you requested an 8bit or 24bit mode.

  void J2D_Copy256c(char *vsc_destination, char *vsc_source);
  void J2D_Copy16Mc(char *vsc_destination, char *vsc_source);

    These functions copy the source screen to the destination screen (of the
    same size) in their entirity.

  void J2D_Update256c(char *vsc, int offset_x, int offset_y);
  void J2D_Update16Mc(char *vsc, int offset_x, int offset_y);

    These functions update (display on the hardware screen) the specified
    virtual screen at the specified offset.  The offset can be other than
    (0,0) if the virtual screen is smaller than the hardware screen and the
    offset is still sufficiently small that the virtual screen will still fit
    entirely within the hardware screen.

    eg. Hardware screen size requested = (x_size, y_size)
        Virtual screen size = (vsc_x_size, vsc_y_size)

        Then offset can range up to (x_size-vsc_x_size, y_size-vsc_y_size)

    The J2D system has been known to hang if an invalid offset is used, so
    be a little bit careful!

