LibGGI
  Steve Cheng, elmert@ipoline.com
  $Date: 1998/02/17 10:53:35 $

  This document describes LibGGI, a flexible, extensible, dynamic draw-
  ing library developed by the GGI project.

  1.  Introduction


  LibGGI, the dynamic GGI (General Graphics Interface) library is a
  flexible drawing library.

  It provides an opaque interface to the display's acceleration
  functions. It was originally intended to allow user programs to
  interface with KGI, the kernel side of the GGI code, but other display
  types can be easily used by loading the appropriate "display target"
  (e.g. X, memory).

  LibGGI consists of a main library (libggi.so) and a multitude of
  dynamic drivers. The library then loads the necessary "drivers" for
  the requested mode, taking hints from the graphics device if
  necessary. LibGGI can also load extension libraries, e.g. to provide
  enhanced 2D and 3D functions.

  It has been designed after having a look at several existing
  libraries, and so far we have found porting to be quite simple from
  and to most of them.


  1.1.  What is known to work



  o  Modes:

  o  VGA 1bit, 16color, 8bit, and ModeX

  o  text-16, linear-1bit,-8bit,-15/16bit and -32bit frame buffers+ up
     to 16bit ramdacs

  o  Targets:

  o  KGI: Kernel Graphics Interface

  o  X: X Window System (X must be in the same mode as the requested
     visual)

  o  Xlib: X Window alternate method; uses X for primitives

  o  memory: off-screen memory

  o  multi: display on multiple targets at once

  o  AA: AAlib, an ASCII-Art renderer

  o  XF86DGA: XFree86 server Direct Graphics Access

  o  SVGAlib: SUID root console graphics library

  o  GLIDE: 3Dfx

  o  Terminfo: GGI textmodes on terminals

  o  Sub-target: Visual-within-a-visual

  o  Wrappers:

  o  SVGAlib (some functions are missing, but many demos work.)

  o  A number of demos

  The code is still alpha, so things may break overnight or change
  unexpectedly...


  2.  How To Install And Use


  In the libggi directory, do:



       $ ./configure # will be done automatically on first make
       $ make
       $ su -c "make install"




  For some demos of libggi code, see the demos subdirectory which has
  several programs showing around the features of LibGGI.

  The most importent of them is demo.c which we use ourselves for
  checking new features. demo.c is heavily commented to allow people to
  learn LibGGI by example. There is also speed.c which is a speed and
  consistency test application, which can be used if you changed
  something in LibGGI to see if you have broken anything.

  LibGGI will automatically default to the most suitable display target.
  However, this can be overridden using the LIBGGI_DISPLAY environment
  variable, set to the name of the display target, plus any additional
  arguments.

  The LIBGGI_DEBUG environment variable can be set to 0 (default) for no
  debugging information, or 255 for verbose debugging information.


  2.1.  Required Software


  To use LibGGI, you will need:


  o  Most likely GNU Make to build LibGGI.

  o  linuxthreads-0.5 or higher (or glibc-2.0.2) if compiling with
     multi-thread support

  o  ld.so 1.7.14 or higher

  o  GGI Linux kernel if using display-KGI target.

  o  X Window System if using display-X target.

  o  XFree86 if using display-DGA target.

  o  AAlib if using display-AA target.




  3.  LibGGI Functions

  3.1.  Library control

  3.1.1.  int ggiInit(void);


  Initalizes the library. This function must be called before using
  other LibGGI functions; otherwise results will be undefined.

  Return: 0 for OK, otherwise an error code.

  Example:


       ______________________________________________________________________
       ggiInit();
       /* do some libggi stuff */
       ggiExit();
       ______________________________________________________________________





  3.1.2.  void ggiExit(void);


  Uninitializes the library and automatically cleanup. This should be
  called after an application is finished with the library. If any GGI
  functions are called after the use of ggiExit the results will be
  undefined.

  Return: None

  Example:


       ______________________________________________________________________
       ggiInit();
       /* do some libggi stuff */
       ggiExit();
       ______________________________________________________________________





  3.1.3.  void ggiPanic(const char *format, ...);


  Graceful shutdown for fatal errors with reporting. May be used like
  printf(3). It will shut down the graphics modes active, close all
  visuals, print the error message given and then exit the application.

  ggiPanic() should only be used by usermode programs when something is
  really screwed, and they do not know what to do. The same applies for
  libraries, but might be used in rare situations such as corruption of
  critical data structures.

  Return: never returns.

  Example:



  ______________________________________________________________________
  ggiPanic("Aiee! Penguin on fire! ;-) Error code: %d", err);
  ______________________________________________________________________





  3.2.  Visual management


  A visual is simply a thing you can draw on. For example, a VT in
  fullscreen-mode, an X window, an invisible memory area, and a printer.
  It is identified by its handle of type ggi_visual_t, which is given to
  all drawing functions to indicate which visual to operate on.

  Each visual is completely independent of each other. You can use these
  visuals to display on multiple monitors and/or in multiple windows or
  to work on "virtual" graphics devices like in-memory pixmaps or even
  PPM-files on disk.

  ggi_visual_t is opaque to the user. Do not try to access any part of
  the structure directly. It may change without notice.


  3.2.1.  ggi_visual_t ggiOpen(const char *display, ...);


  Opens a visual. This function is given a null terminated list of the
  names of LibGGI dynamic drivers to load. This is usually a display
  target. Once loaded, they will all be associated with the single
  visual. Giving no arguments except the NULL instructs LibGGI to open
  the default display target (e.g. display-X, set by LIBGGI_DISPLAY).

  Return: The opened visual, or NULL for error.

  Example:


       ______________________________________________________________________
       memory_visual = ggiOpen("display-memory", NULL);

       /* Get from LIBGGI_DISPLAY enviroment variable */
       default_visual = ggiOpen(NULL);

       if(!memory_visual || !default_visual)
               return EXIT_FAILURE;
       ______________________________________________________________________





  3.2.2.  int ggiClose(ggi_visual_t vis);


  Releases and destroys the visual and the associated internal control
  structures. This will close X windows, return KGI-consoles to text-
  mode, etc.

  If focus is on the closed visual, focus is set to NULL.

  Return: 0 for OK, otherwise an error code.

  Example:

  ______________________________________________________________________
  memory_visual = ggiOpen("display-memory", NULL);

  /* do some drawing, save image, etc. */

  ggiClose(memory_visual);
  ______________________________________________________________________





  3.3.  Mode management

  3.3.1.  The ggi_mode  struct

  The definition in ggi.h is:


       ______________________________________________________________________

       typedef struct { sint16   x, y; } ggi_coord;

       typedef struct    /* requested by user and changed by driver    */
       {
               uint32          frames;         /* frames needed                    */
               ggi_coord       visible;        /* vis. pixels, may change slightly */
               ggi_coord       virt;           /* virtual pixels, may change       */
               ggi_coord       size;           /* size of visible in mm            */
               ggi_graphtype   graphtype;      /* which mode ?              */
               ggi_coord       dpp;            /* fontsize                      */
       } ggi_mode;
       ______________________________________________________________________




  You don't need to care about the internal definition, if you want to
  set a mode, but it is necessary if you want to find out the mode actu-
  ally set.

  Please note that the visible and virtual size are given in pixels, not
  dots. This makes a difference for text modes, because a character is
  treated as one pixel, but consists of a text.x*text.y sized matrix of
  dots.


  3.3.2.  int ggiSetMode(ggi_visual_t visual, ggi_mode *tm);


  Set any mode (text or graphics).

  Return: 0 for OK, otherwise could not set mode.

  Use this function only if you want something really strange that the
  specific SetModes below cannot give you. You usually do not want to do
  this, unless you really know what you are doing and understand the
  values in ggi_mode.


  3.3.3.  int ggiGetMode(ggi_visual_t visual, ggi_mode *tm);


  Get the current mode. tm will be filled with the current mode on
  return.

  Return: 0 for OK, otherwise an error code.


  3.3.4.  int ggiCheckMode(ggi_visual_t visual, ggi_mode *tm);


  Check any mode (text or graphics).

  Return: A return of 0 means that a setmode call for this mode would
  succeed.  Otherwise, the mode is given cannot be set.

  If the mode can not be set, tm is changed to the suggested mode as
  follows:


  o  Resolutions are always adjusted up. If you want the next lower,
     start out at 1,1 (or somewhere else reasonable) and jump up the
     ladder.

     Only if the maximum resolution would be exceeded, resolutions are
     adjusted down to the maximum.

     The above applies to visible and virtual size. If there is
     interference between them, the visible size is satified first if
     possible, then the virtual size.

  o  Note that the adjustment of one value do not normally affect other
     values. For example, if 320x100 (320x200) is requested, the visible
     size may be adjusted to 320x200, but virtual size will be left
     alone. Of course, if the virtual size becomes less than visible
     size, then it will be adjusted as well. A good rule of thumb is
     that anything returned by ggiCheckMode() is minimally valid.

  o  Font sizes (i.e. the size of the pixel in textmodes) are handled
     the other way round: they are adjusted down except when there is
     nothing below.

  o  Graphtype: Modes are normally card-dependant and not too dependant
     on size (except for maxsize-limits etc.)

     The basic rationale is to change graphtype only, if the card does
     not support it at all. If max-resolution is exceeded, then that is
     adjusted down and not the graphtype. This assumes, that if you
     request true-color, you really want that and not so badly the
     resolution you requested. If this is not the case, you can still
     retry with another graphtype.

     If it is necessary to change to change the type of other visuals,
     the order should be ascending (if possible), i.e.
     1->4->8->15->16->24/32 bit. So you always get a mode which can do
     more than you requested. Only when no better modes are available,
     the type is adjusted down.

  o  It is possible to pass GGI_AUTO as any of the parameters. GGI_AUTO
     is a placeholder (e.g. the program does not care about a specific
     parameter).  The display target will reset GGI_AUTO paramter to a
     default, such as its maximum/preferred/LIBGGI_DEFMODE resolution,
     while being compatible with the other settings. Note that the
     presence of GGI_AUTO is not flagged as an error. If
     ggiSet{Graph/Text}Mode() is given GGI_AUTO as one or more of its
     arguments, it will silently set a mode.





  3.3.5.  int ggiSetTextMode(ggi_visual_t visual, int cols, int rows,
  int vcols, int vrows, int fontx, int fonty);


  Set a textmode with given columns and rows, virtual columns and rows
  and a font of the given size.

  Return: 0 for OK, otherwise could not set mode.

  The fontsize is actually the size of the pixel (ggi_mode.dpp), in
  textmodes.


  3.3.6.  vcols, int vrows, fontx, int fonty, ggi_mode *suggested_mode,
  ...); int ggiCheckTextMode(ggi_visual_t visual, int cols, int rows,
  int


  Check a text mode, with a null-terminated list of mode features. The
  last argument must be NULL.

  Return: A return of 0 means that a setmode call for this mode would
  succeed.  Otherwise, the mode is given cannot be set. In this case, tm
  is changed to the suggested mode:

  If suggested_mode is not NULL, then it will be filled with the
  suggested mode, as documented under ggiCheckMode(). In the future,
  there may be more arguments, but currently there is nothing that may
  be put between the final NULL and suggested_mode.


  3.3.7.  int yv, ggi_graphtype type); int ggiSetGraphMode(ggi_visual_t
  visual, int x, int y, int xv,


  Set a graphics mode with a visible area of size x/y and a virtual area
  of size vx/vy (you can pan aound the virtual area using the
  ggiSetOrigin()) and the specified graphics type.

  Return: 0 for OK, otherwise could not set mode.


  3.3.8.  int yv, ggi_graphtype type, ggi_mode *suggested_mode, ...);
  int ggiCheckGraphMode(ggi_visual_t visual, int x, int y, int xv,


  Check a graphics mode, with a null-terminated list of mode features.
  The last argument must be NULL.

  Return: A return of 0 means that a setmode call for this mode would
  succeed.  Otherwise, the mode is given cannot be set. In this case, tm
  is changed to the suggested mode:

  If suggested_mode is not NULL, then it will be filled with the
  suggested mode, as documented under ggiCheckMode(). In the future,
  there may be more arguments, but currently there is nothing that may
  be put between the final NULL and suggested_mode.

  Example:







  ______________________________________________________________________
  /* Use only my mode... but you really should try to negotiate though */
  err = ggiCheckGraphMode(vis, 320, 200, 320, 200, GT_8BIT, NULL, NULL);
  if(err)
          return EXIT_FAILURE;

  /* OR use a suggested mode */
  err = ggiCheckGraphMode(vis, 320, 200, 320, 200, GT_8BIT, &sug_mode, NULL);
  ggiSetMode(&sug_mode);
  ______________________________________________________________________





  3.4.  Graphics context


  LibGGI has a current context associated with each visual. This is done
  for performance reasons, as LibGGI can set up pointers to optimized
  functions when the GC changes (which can be monitored, as it may only
  be changed by the functions mentioned below).


  3.4.1.  int ggiSetGCForeground(ggi_visual_t vis, ggi_pixel color);


  Sets the current colors for the foreground, used in all normal
  graphics functions.

  Return: 0 for OK, otherwise an error code.


  3.4.2.  int ggiSetGCBackground(ggi_visual_t vis, ggi_pixel color);


  Sets the current colors for the background, used in some 2-color
  operations like drawing text.

  Return: 0 for OK, otherwise an error code.


  3.4.3.  int ggiGetGCForeground(ggi_visual_t vis, ggi_pixel * color);


  Reads the current foreground color.

  Return: 0 for OK, otherwise an error code.


  3.4.4.  int ggiGetGCBackground(ggi_visual_t vis, ggi_pixel * color);


  Reads the current background color.

  Return: 0 for OK, otherwise an error code.


  3.5.  Color and palette


  Visuals may have an indirect mapping off the pixel-value to a color
  via a programmable palette. This is e.g. true for the 8 bit IBM VGA
  modes. But even for "direct-mapped" modes, you will need to know which
  color maps to which pixel-value.

  Please note that palette lookups can be quite expensive (especially
  for palettized modes) and should thus be avoided e.g. by caching
  earlier results.

  The ggi_color struct has 16 bit wide entries for red (.r), green (.g),
  and blue (.b) values. Please scale your palette values as necessary.

  The ggi_pixel is a hardware-dependent representation of a color. It is
  usually calculated from a ggi_color by ggiMapColor or read from the
  visual by ggiGetPixel, and you can safely assume that the relationship
  between a ggi_color and it's associated ggi_pixel value does not
  change unless you change the visual or the mode the current visual is
  in.  You can not do calculations with ggi_pixel values. Well, you can,
  but you should not. The results would be unpredictable and system
  dependent.


  3.5.1.  ggi_pixel ggiMapColor(ggi_visual_t vis, ggi_color * col);


  Gets the pixelvalue for the given color.

  Return: 0 for OK, otherwise an error code.


  3.5.2.  int ggiUnmapPixel(ggi_visual_t vis, ggi_pixel pixel, ggi_color
  *col);


  Gets the color associated with a given pixelvalue.

  Return: 0 for OK, otherwise an error code.


  3.5.3.  int len); int ggiPackColors(ggi_visual_t vis, void *buf,
  ggi_color *cols,


  Converts the colors in cols to pixelvalues in buf.

  Return: 0 for OK, otherwise an error code.


  3.5.4.  int len); int ggiUnpackPixels(ggi_visual_t vis, void *buf,
  ggi_color *cols,


  Converts pixelvalues in buf to individual elements of cols.

  Return: 0 for OK, otherwise an error code.


  3.5.5.  *cmap); int ggiSetPaletteVec(ggi_visual_t vis, int s, int len,
  ggi_color


  Sets a range of palette values, of length len, starting at index
  number s.

  Return: 0 for OK, otherwise an error code.


  3.5.6.  *cmap); int ggiGetPaletteVec(ggi_visual_t vis, int s, int len,
  ggi_color


  Gets a range of palette values, of length len, starting at index
  number s.

  Return: 0 for OK, otherwise an error code.


  3.6.  Primitives


  LibGGI has three basic types of primitives when it comes to filling
  rectangular areas (including the degenerate cases of horizontal and
  vertical lines and single pixels).

  We have found three operations commonly performed on such areas :

  o  Draw: This means you set all contained pixels to the current
     foreground color (maybe modified by the update-operations as set in
     the current graphics context).

  o  Put: Fill the area with pixels of different value from a buffer.

  o  Get: Read pixels from the screen into such a buffer.


  3.6.1.  int ggiDrawPixel(ggi_visual_t vis, int x, int y);

  3.6.2.  int ggiPutPixel(ggi_visual_t vis, int x, int y, ggi_pixel
  col);

  3.6.3.  int ggiGetPixel(ggi_visual_t vis, int x, int y, ggi_pixel
  *col);


  Draws/Puts/Gets a single pixel at x/y.

  Return: 0 for OK, otherwise an error code.


  3.6.4.  int ggiDrawHLine(ggi_visual_t vis, int x, int y, int w);

  3.6.5.  *buf); int ggiPutHLine(ggi_visual_t vis, int x, int y, int w,
  void

  3.6.6.  *buf); int ggiGetHLine(ggi_visual_t vis, int x, int y, int w,
  void


  Draws/Puts/Gets a horizontal line from x/y, extending w pixels in the
  positive x direction (normally left).

  Return: 0 for OK, otherwise an error code.


  3.6.7.  int ggiDrawVLine(ggi_visual_t vis, int x, int y, int h);

  3.6.8.  *buf); int ggiPutVLine(ggi_visual_t vis, int x, int y, int h,
  void

  3.6.9.  *buf); int ggiGetVLine(ggi_visual_t vis, int x, int y, int h,
  void


  Draws/Puts/Gets a vertical line from x/y, extending h pixels in the
  positive y direction (normally down).


  Return: 0 for OK, otherwise an error code.


  3.6.10.  int ggiDrawBox(ggi_visual_t vis, int x, int y, int w, int h);

  3.6.11.  *buf); int ggiPutBox(ggi_visual_t vis, int x, int y, int w,
  int h, void

  3.6.12.  *buf); int ggiGetBox(ggi_visual_t vis, int x, int y, int w,
  int h, void


  Draws/Gets/Puts a filled rectangle at x/y and extending w pixels in
  the positive x direction and h in the positive y direction.

  Return: 0 for OK, otherwise an error code.

  The buffers are filled with the x coordinate walking first.


  3.6.13.  int ggiFillscreen(ggi_visual_t vis);


  Fills the entire virtual screen. May be more efficient than the
  corresponding call to ggiDrawBox().

  Return: 0 for OK, otherwise an error code.


  3.6.14.  int ggiDrawCircle(ggi_visual_t vis, int x, int y, int r);


  Draws a circle of given radius r around x/y.

  Return: 0 for OK, otherwise an error code.

  This will be removed and replaced by a circle routine in libggi2d. It
  gives already a warning.


  3.6.15.  int ggiDrawLine(ggi_visual_t vis, int x, int y, int xe, int
  ye);


  Draws any line from x/y to xe/ye. The line is exact; the pixel set is
  no more than 0.5 pixels off the place it should be.

  Return: 0 for OK, otherwise an error code.


  3.7.  Blits

  3.7.1.  nx, int ny); int ggiCopyBox(ggi_visual_t vis, int x, int y,
  int w, int h, int


  This is a screen-to-screen-blit, all in the same visual. Copy the box
  described by x,y,w,h to the new location nx,ny. This automatically
  takes care of overlaps and optimizes for the given target (e.g. uses
  HW-accel or intermediate buffers as appropriate).

  Return: 0 for OK, otherwise an error code.




  3.7.2.  ggi_visual *dst, int dx, int dy, int dw, int dh); int ggi-
  CrossBlit(ggi_visual *src, int sx, int sy, int sw, int sh,


  Blits a rectangular memory area from one visual to another. This is a
  very complex function as it handles stretching and colorspace-
  conversion.

  Return: 0 for OK, otherwise an error code.

  We try hard to optimize this, but avoid using it if possible. And try
  to keep its work easy. If possible, do not copy between different
  colorspaces or do any stretching.

  This will most probably be removed and replaced by a routine in
  libggi2d.


  3.8.  DirectBuffer


  Dependent on the visual target and runtime environment found,
  applications may be granted direct access to hardware and/or library
  internal buffers. This may significantly enhance performance for
  certain pixel oriented applications or libraries.

  The DirectBuffer is a mechanism in which a LibGGI program can use to
  determine all the characteristics of these buffers (typically the
  framebuffer), including the method of addressing, the stride,
  alignment requirements, and endianness.

  However, use not conforming to this specification will have undefined
  effects and may cause data loss or corruption, program malfunction or
  abnormal program termination. So you don't really want to do this.


  3.8.1.  Types of Buffers

  3.8.1.1.  Framebuffer


  A frame buffer stores a certain number of bits per pixel. Some visual
  targets may store multiple frames in one buffer. If the visual target
  in question does so, the number of bits stored per attribute and pixel
  as well as the attributes and number of pixels stored per frame must
  be the same for all frames. Some attributes, such as depth values, may
  be shared for all frames.  Each attribute, frame and shared attribute
  uses an orthogonal subset of the bits stored per pixel. Hence simple
  masking and shift operations may be used to extract and/or modify the
  attribute values.

  A frame buffer may be organized as several distinct buffers.  Each
  buffer may have a different layout. This means both the addressing
  scheme to be used as well as the addressing parameters may differ from
  buffer to buffer. Within the scope of this document, only pixel linear
  addressing scheme buffers are specified (yet).


  3.8.1.2.  Pixel Linear Buffer


  A linear buffer is a region in the application's virtual memory
  address space. A pixel with the pixel coordinates (<x>,<y>) is
  assigned a pixel number according to the following formula: <pixel
  number> = (<origin_y> + <y>)*<stride> + <origin_x> + <x> In any case
  both <x> and <y> must not be negative, <x> must be less than <size_x>
  and <y> must be less than <size_y>.  For top-left-origin screen
  coordinates, <stride> and <origin_y> will both be positive. For
  bottom-left-origin screen coordinates, <stride> and <origin_y> will
  both be negative.  This will result in the correct pixel number with
  the same formula in both cases. The pixel number will be used to
  address the pixel.

  A certain number <bpp> of bits is stored per pixel. Bit <n> of the
  pixel value for pixel number <i> is stored in bit number <i>*<bpp> +
  <n> of the buffer. Bit <n> of byte <i> in the buffer corresponds to
  bit <i>*8 + <n> of the buffer for host CPU native bit and byte
  ordering. For some targets, the buffer might not be in host CPU native
  format and swapping operations need to be performed before writes or
  after reads.


  3.8.2.  Accessing the Buffer


  Read and write access to the buffer is done using load and store
  instructions of the host CPU. Depending on the visual target, only a
  subset of the possible access widths may be allowed.  Access may need
  to be aligned to integer multiples of the access width but has to be
  at least at 8 bit (byte) boundaries.  Bit number log2(<width>) in
  <align> is set if accesses with width <width> have to be aligned. Read
  operations should be performed using the <read> buffer and write
  operations should be performed using the <write> buffer. These might
  be the same, but need not.  If they are, read/write may be done to
  either buffer.  Please note, that either read or write may be NULL.
  These are write-only or read-only buffers, which might be caused by
  hardware limitations. Such buffers are not suited to do Read-Modify-
  Write operations, so take care.


  3.8.2.1.  Alignment

  If unaligned access is allowed, all bits to be accessed must belong to
  the buffer. The last access unit will be padded with meaningless bits
  so that an aligned access with broadest width is possible.  Performing
  unaligned accesses if alignment is required or access with unsupported
  widths will have an undefined effect Thus it may cause data
  corrruption or abnormal program termination.  In any case, this must
  not cause the machine to hang; neither temporarily nor permanently.
  Though the application might hang due to page fault race conditions.


  3.8.2.2.  Access Widths

  The access widths specified currently are 8 bit, 16 bit 32 bit and 64
  bit. Any combination of these widths may be supported, but need not.
  However, at least one access width is supported.  Bit log2(<width>) in
  <access> is set if this accesses wit width <width> are
  supported/allowed.


  3.8.2.3.  Swapping Requirements

  If the buffer is not stored with native bit and byte ordering,
  swapping operations have to be performed before writes and after reads
  according to the following scheme (shown for 16 bit access, <val>
  being the value being read, and <swap> being a bit mask that selects
  the swap operations to be performed):




  ______________________________________________________________________
          if (swap & 1) {

                  val = (val & 0x5555) << 1) | ((val & 0xAAAA) >> 1);
          }
          if (swap & 2) {

                  val = (val & 0x3333) << 2) | ((val & 0xCCCC) >> 2);
          }
          if (swap & 4) {

                  val = (val & 0x0F0F) << 4) | ((val & 0xF0F0) >> 4);
          }
          if (swap & 8) {

                  val = (val & 0x00FF) << 8) | ((val & 0xFF00) >> 8);
          }
  ______________________________________________________________________




  A generalized scheme has to be used for other access widths.  Note
  that only access widths not less than the biggest defined swap should
  be allowed to have consistent addressing guaranteed.


  3.8.2.4.  Paged Buffers

  Successive access to addresses <addr> and <addr2> of either read or
  write buffers with <addr0>  <page_size>  !=  <addr1> / <page_size>/
  may be very expensive compared to successive accesses with <addr0>
  <page_size>  ==  <addr1> / <page_size>/.  On i386 the penalty will be
  about 1500 cycles plus 4 cycles per to be remapped. Because of this,
  block transfer operations might become very inefficient for paged
  buffers. If there are two different buffers provided for read and
  write operations, you should do successive reads from one and do
  successive writes to the other. If not, it is recommended to copy
  pagewise into a temporary buffer and then to copy this temporary
  buffer back to screen.


  3.8.2.5.  Update Operations

  A write mask may be specified that indicates which bits within a pixel
  value should be affected by write operations. Bits not set in the
  write mask will not be affected by write accesses.  This write
  protection may be performed in hardware. If not, the application has
  to perform the neccessary read-modify-write cycles. Modifying bits not
  set in the write mask will have an undefined effect.


  3.8.3.  API Structures













  ______________________________________________________________________
  /*      Pixel Attributes
  **
  **      These can be controlled per pixel of an image. Any of the attributes
  **      may be missing, and there might be some not defined yet. To query
  **      information about which attributes can be controlled, use the
  **      ggiLFBAttributeMask() function that returns a pixel value bitmask
  **      of the bits that are used to contol a given attribute. If a bitmask
  **      of zero is returned, the attribute queried cannot be controlled.
  */
  typedef enum ggi_pixel_attribute {

          paPrivate,              /* Don't touch                          */
          paApplication,          /* store what you want in here          */
          paBackgroundIndex,      /* index of the color of the pixel      */
          paForegroundIndex,      /* index of the color of the texture    */
          paTextureIndex,         /* index of the texture                 */
          paBlink,                /* blink bit/frequency                  */
          paColor1,               /* intensity of color channel 1         */
          paColor2,               /* intensity of color channel 2         */
          paColor3,               /* intensity of color channel 3         */
          paAlpha,                /* alpha value (all channels)           */
          paAlpha1,               /* alpha value channel 1                */
          paAlpha2,               /* alpha value channel 2                */
          paAlpha3,               /* alpha value channel 3                */
          paZValue,               /* z-value                              */
          paStencil,              /* stencil buffer value                 */
          paBlendKey,             /* a key used for blending              */
          paBlendLow1,            /* keying low value channel 1           */
          paBlendHigh1,           /* keying high value channel 1          */
          paBlendLow2,            /* keying low value channel 2           */
          paBlendHigh2,           /* keying high value channel 2          */
          paBlendLow3,            /* keying low value channel 3           */
          paBlendHigh3,           /* keying high value channel 3          */

          paLastPixelAttribute    /* the last defined, must(!) be less 32 */

  } ggi_pixel_attribute;

  enum ggi_buffer_layout {

          blPixelLinearBuffer,

          blLastBufferLayout
  };

  typedef struct ggi_buffer
  {
          /*      administrative;
          */
          struct ggi_buffer       *next;

          void    *app_private;
          void    *lib_private;
          void    *drv_private;

          /*      access info
          */
          enum ggi_buffer_layout  layout;

          void    *read;                  /* buffer address for reads     */
          void    *write;                 /* buffer address for writes    */
          ggi_uint        page_size;      /* zero for true linear buffers */

          ggi_uint        access;         /* supported access widths      */
          ggi_uint        align;          /* alignment requirements       */
          ggi_uint        swap;           /* swapping requirements        */

          uintl   write_mask;

          /*      buffer layout
          */
          ggi_uint        bpp;                    /* bits per pixel               */
          ggi_sint        size_x, size_y;         /* size of application area     */
          ggi_sint        origin_x, origin_y;     /* application area origin      */
          ggi_sint        stride;                 /* pixels per row               */

          ggi_pixel_attribute     left_frame_last_attr[MAX_NR_FRAMES];
          ggi_uint        *left_frame_attr_mask[MAX_NR_FRAMES];

          ggi_pixel_attribute     right_frame_last_attr[MAX_NR_FRAMES];
          ggi_uint        *right_frame_attr_mask[MAX_NR_FRAMES];

  } ggi_buffer;
  ______________________________________________________________________





  3.8.4.  API Functions

  3.8.4.1.  ggi_uint frame, enum ggi_pixel_attribute attr); ggi_uint
  ggiLFBAttributeMask(struct ggi_buffer *fb, ggi_uint eye,

  This returns a bit mask for the given attribute defining the bits used
  to control a given attribute for a given frame.  If a mask is zero,
  the attribute for the given frame and eye cannot be controlled with
  this buffer. Masks are given for a pixel value are in host CPU native
  format and have <bpp> valid bits filled from LSB to MSB. This is the
  bit order within the attributes too.


  3.8.4.2.  ggi_error ggiLFBGetBuffer(ggi_context ctx, struct ggi_buffer
  **buf);

  This should initially be called with buf == NULL and will return the
  first 'public' buffer then. Subsequent calls will return anymore
  public buffers or NULL in buf if there are no buffers left.


  3.8.4.3.  void ggiLFBClaimBuffer(ggi_context ctx, struct ggi_buffer
  *buf);

  Tells the library that the application is using this buffer directly.
  Thus changing framebuffer parameters will not be done unless there are
  callback functions registered.


  3.8.4.4.  *buf); void ggiLFBReleaseBuffer(ggi_context ctx, struct
  ggi_buffer

  Tells the library that the application does not use the buffer any
  longer.


  3.8.4.5.  ggi_lfb_callback, void *entry);/ void ggiLFBCall-
  back(ggi_context ctx, ggi_buffer *fb,




  ______________________________________________________________________
  typedef enum ggi_lfb_callback
  {
          cbLastLFBCallback

  } ggi_lfb_callback;
  ______________________________________________________________________




  This can be used to register a callback when certain framebuffer
  parameters are changed. However, there are no call backs defined yet.


  3.8.5.  Example


  This is a simple example to get a linear framebuffer.



       ______________________________________________________________________
               ggi_visual_t            vis;
               ggi_directbuffer_t      db;
               ggi_pixellinearbuffer   *plb;
               char *                  fb;

               vis = ggiOpen(NULL);
               if(!vis) {
                       fprintf(stderr, "Cannot open visual.\n");
                       exit(1);
               }

               if(ggiSetGraphMode(vis, GGI_AUTO, GGI_AUTO,
                       GGI_AUTO, GGI_AUTO, GGI_AUTO))
               {
                       fprintf(stderr, "Cannot set mode.\n");
                       exit(1);
               }

               if(ggiDBGetBuffer(vis, &db) ||
                       (ggiDBGetLayout(db) != blPixelLinearBuffer))
               {
                       fprintf(stderr, "Cannot find a linear framebuffer.\n");
                       exit(1);
               }

               plb = ggiDBGetPLB(db);
               if(!plb) {
                       fprintf(stderr, "Cannot get a linear framebuffer.\n");
                       exit(1);
               }

               /* Now you can use fb to draw whatever you want */
               fb = plb->write;
       ______________________________________________________________________









  3.9.  Origin and splitline

  3.9.1.  int ggiSetOrigin(ggi_visual_t vis, int x, int y);


  Set the top-left corner of the displayed area to x/y.

  Return: 0 for OK, otherwise an error code.

  When using a larger virtual area, you can pan the visible area over
  the virtual one to do scrolling. Some targets have extemely efficient
  means to do this (i.e. they do it in hardware).

  Thus this is commonly used for double-buffering by requesting a
  double- height virtual screen (i.e. virtual size is double of the
  visible size), and then drawing on the upper/lower half alternatingly
  and displaying the currently "steady" buffer (the one which is not
  drawn to) using ggiSetOrigin().

  Example: Pan from the top to the bottom of the virtual screen


       ______________________________________________________________________
       for(i = 0; i<virt_y-visible_y; i++) {
               ggiSetOrigin(vis, 0, i);
       }
       ______________________________________________________________________




  Note that this call takes dot coordinates, not pixel coordinates as
  the drawing primitives do. This makes a difference in text mode.


  3.9.2.  int ggiSetSplitline(ggi_visual_t vis, int y);


  Splitline is a feature which originated from the IBM VGA which is able
  to display the start of the display-memory (i.e. position 0/0) at some
  arbitrary line. This is a hardware feature but may be emulated by some
  other targets (e.g. X).

  Return: 0 for OK, otherwise an error code.

  In other words, splitline is an IBM VGA feature which allows to
  overlay the lower parts of the screen with the graphics at 0/0. This
  is nice to e.g.  scroll in status lines or the like. It is not
  guaranteed to work and will return an error code stating this, if it
  is not supported. Please note, that there are some broken VGA clones
  which will silently ignore the command.

  In emulated splitlines, the image from the point specified by
  ggiSetOrigin is displayed at the top part of the image before the
  splitline.

  Example:









  ______________________________________________________________________
  for (i=vy;i>=0;i--)
  {
          ggiSetSplitline(vis,i);
          usleep(10000);
          if (ggiKbhit(vis)) break;
  }
  ______________________________________________________________________





  Note that this call takes a dot line, not a pixel value as the drawing
  primitives do. This makes a difference in text mode.



  3.10.  Event handling


  In addition to graphics operations, LibGGI provides several event
  handling functions.

  Events are of type ggi_event:


       ______________________________________________________________________
       typedef union ggi_event {

               uint8           size;           /* size of this event   */

               ggi_any_event   any;            /* access COMMON_DATA   */
               ggi_cmd_event   cmd;            /* command/broadcast    */
               ggi_raw_event   raw;            /* raw data event       */
               ggi_val_event   val;            /* valuator change      */
               ggi_key_event   key;            /* key press/release    */
               ggi_pmove_event pmove;          /* pointer move         */
               ggi_pbutton_event pbutton;      /* pointer buttons      */

       } ggi_event;
       ______________________________________________________________________




  First, size is the size of the given event. Then the COMMON_DATA
  follows:



       ______________________________________________________________________
               uint8   size;           /* size of event in bytes       */
               uint8   type;           /* type of this event           */
               uint8   focus;          /* focus this is reported from  */
               uint8   device;         /* who sent this                */
               uint32  time;           /* timestamp                    */
       ______________________________________________________________________




  Type is the type of event, which may be the following:



  ______________________________________________________________________
  typedef enum ggi_event_type {

          evNothing = 0,  /* event is not valid. (must be zero)   */
          evCommand,      /* report command/do action             */
          evBroadcast,    /* notification of general interest     */
          evDeviceInfo,   /* report input device information      */

          evRawData,      /* raw data received from device        */

          evKeyPress,     /* key has been pressed                 */
          evKeyRelease,   /* key has been released                */
          evKeyRepeat,    /* automatically repeated keypress      */
          evKeyState,     /* resynchronize keys state             */

          evPtrRelative,  /* pointer movements reported relative  */
          evPtrAbsolute,  /* pointer movements reported absolute  */
          evPtrButtonPress,       /* pointer button pressed       */
          evPtrButtonRelease,     /* pointer button released      */
          evPtrState,     /* resynchronize pointer state          */

          evValRelative,  /* valuator change (reported relative)  */
          evValAbsolute,  /* valuator change (reported absolute)  */
          evValState,     /* resynchronize valuator state         */

          evLast          /* must be less than 33                 */

  }  ggi_event_type;
  ______________________________________________________________________




  Use the appropriate member from the ggi_event union to access the
  event data, depending on the given type. See event.h and keyboard.h
  for more details. For example:



       ______________________________________________________________________
               ggi_event ev;

               /* ... get the event... */

               switch(ev.any.type) {
                       case evKeyPress:
                       case evKeyRepeat:
                               printf("Received key symbol: %x\n", ev.key.sym);
                               break;
                       case evKeyRelease:
                               /* ... ignore ... */ break;
                       case evPtrRelative:
                       case evPtrAbsolute:
                               printf("Moved the mouse! x: %d, y: %d\n",
                                       ev.pmove.x, ev.pmove.y);

                       /* ... etc ... */
       ______________________________________________________________________




  There is also ggi_event_mask which may be passed to various event
  handling functions to indicate which types of events the program is
  interested in. See ggi.h for possible masks.

  3.10.1.  *mask, struct timeval t); ggi_event_mask ggiEvent-
  Poll(ggi_visual_t vis, ggi_event_mask


  Check if any of the events given in EvMask is available. Using the
  struct timeval *t, you can control the timeout, like select(2). Give
  NULL to wait indefinitely or a filled out struct to wait for a given
  time (which may be 0 to get non-blocking behaviour).

  Return: a mask of events which are available (within the limits set by
  the mask parameter).


  3.10.2.  mask); int ggiEventRead(ggi_visual_t vis, ggi_event *ev,
  ggi_event_mask


  Read an Event from the queue. This call blocks, if there is no such
  Event present.


  3.10.3.  int ggiEventPut(ggi_event_buffer *buf, ggi_event *ev);

  3.10.4.  void ggiEventSkip(ggi_event_buffer *buf);

  3.10.5.  int ggiEventCopy(ggi_event_buffer *buf, ggi_event *ev);


  These functions manage a simple circular buffer of ggi_events.
  Although rarely used, they might be useful to applications requiring a
  simple queue of received events. In order to use these, first allocate
  and initialize ggi_event_buffer.

  ggiEventPut() puts the given event in the buffer. ggiEventCopy()
  copies the next event out of the buffer (though it will still be in
  the buffer). Use ggiEventSkip() to skip an event.


  3.11.  Input and Output


  LibGGI provides means to do basic graphical input and output.

  The input portion consists of convenience keyboard functions based on
  ggiEventPoll() and ggiEventRead(). If you need more complex things,
  use the event interface directly, described in the previous section.

  In graphics modes, ggiPutc() and ggiPuts() are limited to 8x8
  character fonts; a future LibGGI2D extension will incorporate more
  advanced text rendering.


  3.11.1.  int ggiKbhit(ggi_visual_t vis);


  Checks if a key has been hit on the keyboard. This does not consume
  the key. It is basically for easy porting of old DOS applications.

  Return: 0 if no key has been received yet, otherwise there is a key to
  be consumed.

  DO NOT poll like this: do while( ! ggiKbhit(vis) );. On a multitasking
  OS you are wasting ressources which could be available to other
  processes.  If you want to wait for a key, use the ggiGetc() call.


  3.11.2.  int ggiGetc(ggi_visual_t vis);


  Gets a character from the keyboard. Blocks if no key is available.

  Return: a 16-bit Unicode character.

  As a simple heuristic, you may use 0xff to convert the return code to
  ISO-Latin-1 for quickly porting an old application. Please do that
  right later using the K_* symbols.


  3.11.3.  int ggiPutc(ggi_visual_t vis, int x, int y, char c);


  Puts a single character on a graphical visual. This is only a very
  simple routine using a fixed-width 8x8 font. See the libGGI-2D manual
  for enhanced font rendering support.

  Return: 0 for OK, otherwise an error code.


  3.11.4.  int ggiPuts(ggi_visual_t vis, int x, int y, const char *str);


  Puts multiple characters at once. No special handling is applied to
  control characters like CR or LF. You will see the associated glyph
  being displayed, so do this yourself if you need.

  Return: 0 for OK, otherwise an error code.

  Don't use ggiPutc() repeatedly for multiple characters, as ggiPuts()
  might be able to optimize the output of muliple chars at once.


  4.  LibGGI usage guidelines

  4.1.  Synchronous and asynchronous drawing modes

  Some targets allow different modes with regard to when the screen is
  updated and the actual drawing takes place.

  The synchronous mode is default because it is what most programmers
  expect: When the drawing command returns, it is already or will be
  executed very shortly. So the visible effect is that everything is
  drawn immediately.  (It is not guaranteed in the strict sense that it
  is already drawn when the function call returns, but almost.)

  The asynchronous mode is (at least on the X) faster, but does not
  guarantee that the command is executed immediately. To make sure that
  all pending graphics operations are actually done and the screen is
  updated, you need to call ggiFlush(myvis);.

  (Side note: The screen refresh the X target does every 1/20 s can take
  about half the execution time of a program. So syncronous mode can
  really slow things down.)

  As it stands now, all operations are guaranteed to be performed in the
  order given in both modes.  Reordering has been discussed but is
  currently not done.

  So the recommendation for all graphics applications is to set the
  asynchronous mode. It will be far more efficient on some platforms and
  will never be worse. (If asynchronous mode is not supported by a
  target, setting it is still allowed, but has no effect.)

  How to set up asynchronous mode?


  o  ggiSetInfoFlags(myvis,GGIFLAG_ASYNC); switches to asynchronous
     mode,

  o  ggiFlush(myvis); updates the screen,

  o  ggiSetInfoFlags(myvis,GGIFLAG_SYNC); switches to synchronous mode.


  4.2.  LibGGI and threads

  It is strongly discouraged to draw to one visual from two (or more)
  different processes or threads at the same time. While serious damage
  is unlikely, corrupted graphics output might happen and a big
  performance penalty is almost guaranteed.

  If drawing from two threads is needed, the application is required to
  synchronise the threads so that not both draw simultanously.

  (Side note: Some cards need some sort of paging for accessing their
  video ram (banked framebuffer).  Two threads accessing different parts
  of the screen would require a page change on each process switch,
  which could slow them down to a crawl. State information that has to
  be reloaded to the accellerator engine after every switch would be
  another example.)


  4.3.  Mixing LibGGI and direct frame buffer access

  Some tricky spots have to be taken care of if you mix libggi calls and
  direct access to the frame buffer. While direct access is done
  immediately, execution of a libggi call might be delayed due to the
  accellerator architecture, so framebuffer access immediately after an
  accellerated libggi call could actually be executed before or while
  the accellerator accesses the frame buffer itself, which worst case
  could lock the card and give best case wrong pixels on the screen.

  To make sure that all pending accellerator commands are executed, you
  need to call ggiFlush(myvis); between a (series of) libGGI call(s) and
  direct frame buffer access.

  (Side note:  ggiFlush(myvis); does  more than just waiting for the
  accellerator to finish pending jobs, so there will be another call
  introduced for only this purpose. Stay tuned.)


  5.  LibGGI initialization example


  A primitive tutorial on how to start using LibGGI, since many people
  seem to have trouble with this. For more practical usage, please see
  demo.c.












  ______________________________________________________________________
  #include <ggi/libggi.h>

  int main(void)
  {
          ggi_visual_t vis;
          ggi_mode mode;
          int err;

          /* first initialize LibGGI */
          ggiInit();

          /* Get the default visual to work on */
          vis = ggiOpen(NULL);

          /* You can also do some drawing to memory, like this:
             (don't forget the ending NULL!)

          vis = ggiOpen("display-memory", NULL);
          */

          if(vis==NULL) {
                  fprintf(stderr, "No visual!\n");
                  exit(1);
          }

  #ifdef AUTO_SELECT_MODE
          /* This automatically selects the default mode */
          err = ggiSetGraphMode(vis,
                  GGI_AUTO, GGI_AUTO,     /* Visible resolution */
                  800, 600,               /* Virtual: perhaps you'd like a large area to scroll around in */
                  GGI_AUTO);              /* graphtype auto */

  #else
          /* OR you can select your own */

          /* Check for mode: 320x200x8 320x200.
             After this call, mode will now have our mode,
             OR the suggested mode if our mode cannot be satisfied.
          */
          ggiCheckGraphMode(vis, 320, 200, 320, 200, GT_8BIT,
                  &mode, NULL);

          /* Now set the mode */
          err = ggiSetMode(vis, &mode);
  #endif

          if(err) {
                  fprintf(stderr, "Cannot set mode!\n");
                  exit(2);
          }

          /* do some stuff */

          ggiClose(vis);

          ggiExit();

          return 0;
  }
  ______________________________________________________________________





  6.  API change log

  6.1.  Pending changes for the next release


  o  ggiDrawCircle is going to be moved to LibGGI2D. This gives
     currently a warning. So relinking with -lggi2d will then be
     necessary.

  o  ggiCrossBlit is most probably going to be moved to LibGGI2D as
     well.


  6.2.  1.3.0 to 1.4.0


  o  ggiMapColor takes now a pointer to a ggi_color struct as it's
     second argument instead of the struct itself.  This breaks binary
     compatibility for about every program!

  o  ggi*Sprite functions, that had never been implemented, are removed.

  o  The ggi_mode struct members virt and visible now do contain the
     number of pixels, not dots (which makes a difference for text mode.
     One character is one pixel but e.g. 9x16 dots). It is unclear what
     it had to contain before. So it might be a change, it might be a
     bugfix.


  7.  Overview of how to write a LibGGI display target


  [This article is NOT a substitute for not looking at the existing
  display target code. This (unfinished) article does not explain every
  detail (yet).]

  Actually, most of the work of displaying and servicing an application
  has been done for the display target writer. For example, there is
  reasonably optimized code for linear framebuffers of most bit-types,
  and stubs exist to do a few non-crucial operations such as ggiPutc()
  by calling ggiSetPixel() individually. "Convenient" functions such as
  ggi{Set/Check}{Text/Graph}Mode() simply call the "master" function,
  ggi{Set/Check}Mode(), with different arguments, and the display target
  writer only needs to supply "master" functions for these to work.

  When the application requests a visual (by name), LibGGI looks it up
  in its configuration file, and loads and initializes the appropriate
  library. On initialization, the display target's GGIdlinit() is
  called. This function should do whatever set up is necessary to begin
  using the target, e.g.  initializing Xlib in the display-X target. But
  do NOT set the mode here yet.  GGIdlinit() should also indicate which
  functions it implements by setting the various fields of the operation
  structs (the main one being opdisplay).  (It does not have to
  implement all of the possible functions; if it doesn't then stubs are
  used or the function fails.)

  The return codes for these functions are the same as if they were
  called directly by LibGGI-using applications.

  GGIsetmode() is used to set the mode. If it fails, GGIsetmode() should
  suggest a mode, although this change may not be propagated back to
  ggiSet{Text/Graph}Mode because they don't take a ggi_mode pointer.
  GGIsetmode() implementations usually use _GGIdomode(), which sets up
  "suggestions". This function is used to load any additional libraries
  used by the target, such as the linear framebuffer libraries, and
  stubs.
  GGIgetmode() is used to check the mode. Usually the display target can
  simply grab the mode stored in the given ggi_visual.

  GGIcheckmode() is used to check if the mode in question is valid. If
  not, the mode passed to it should be changed to the suggested mode.