pg2d - PenguinGraphics 2d.
A mid-high level 2d graphics library for the PenguinPlay SDK.


What?
-----
pg2d is a graphics library layered on top of the libGGI.  Because
of this layering, it will work on any (sensible) libGGI target,
including X, SVGAlib, KGI, Win32 etc.  The pg2d interface has no
libGGI dependent aspects, and the code is designed such that
it could be ported away from GGI if necessary.  This should not
be necessary.

It is only in a very early stage of development, so much remains
to be found out. pg2d currently weighs in around 37kb, decide for
yourself whether that is good enough.  


Why?
----

There exist many good graphics libraries.  So why pg2d?
  - its C++.  This is only an issue of you use C++.  C++
    made much of the design much easier for me, so hopefully
    pg2d's C++ interface will be useful for you.
  - flexible surface support.  A surface in pg2d is something which
    you draw into, it need not be representable as some sort of
    memory buffer, and if it is, it could be in either system or 
    video memory (or wherever).  Surface  types implemented/planned include
        * memory buffers - implemented.
        * regions of GGI visuals - implemented.
	* scanline buffers - planned/under consideration.
	* drawlists - planned/under consideration.
	* image files = planned/under consideration.
	* user defined - ????
  - While things like libGGI visuals offer similar functionality, they are 
    to large and complex to be used to represent manifold sprites or textures.
    pg2d makes it practical to just draw into a sprite.
  - Scaling/Rotation, transparency and other sugar on drawing 
    ops can be implemented in a clean, transparent manner, but
    can be efficiently turned of if necessary.
 


Actual Description
------------------

Here is my conceptual model for what happens in pg2d, it underwent some change
during pg2d's development, and is now simpler than it used to be.  

There are three key classes in the pg2d interface:
   Surfaces (ppgSurface), graphics contexts (ppgGC) and devices
   (ppgDevice).


Surfaces (ppgSurface)
--------
The key idea of pg2d is the surface.  As shown above there exist many
kinds of surfaces.  Things are drawn into surface.  The ppgSurface class
itself is just a very simple hierarchy of plain-old-data types.  You
drawing into surfaces using draw commands.  The actual drawing, and all
the rest of the real work is not done by ppgSurface objects, but by
devices and draw contexts.  ppgSurface merely holds info needed for
such objects to do their work, for example:
   - width and height
   - framebuffer memory pointer (for memory surfaces)_
   - layout in memory (of the pixels themselves, not of bits within pixels).
   - coords of origin within GGI visual.
   - ?the GGI visual itself? - no sure here, an implementation issue.
   

GC's (ppgGC)
----
The actual draw command (DC) handling routines use this info, along with
other context info gleaned form the graphics context (GC) through which
they are invoked.  The most important role of the GC is to wrap
a function pointer table of DC handlers, and store state information
(drawing colour, stipple, transformation state etc.) used by these handlers.

GC's do not exist in any fancy class hierarchy or anything.  Polymorphism
(wrt surface types) is achieved through manipulation of the DC table.
GC's are constructed by the Devices, which know what CDC's to plug
in, but the table is subject to further modification and even
to user defined DC functions can be used.

In case you haven't already figured it out, DC invocation is done
by calling an inline GC member function which forwards the message
onto the underlying DC handler.  To facilitate things like drawlists,
the DC<->DC handler argument passing format is a little stylized, 
see ppgDrawCmd.h for details.


Devices (ppgDevice)
-------
While GC state info should be things like current pen, which are changeable
at the whim of the programmer, Devices hold other state info, such as
video mode.  Here are some examples:
   - GGI devices, front ends to a GGI visual.  The device arranges for any
   attempt to draw into a surface to invoke GGI primitives on the underlying
   visual.  Video mode negation is dealt with here.
   - Memory devices.  Not much to say here really.

In some cases, a surface can be said to exist _on_ a device.  For example
a GGI surface exists within a GGI device.  Similarly a sprite which is 
potentially stored in video memory might be associated with a Device
representing the video card.  Other surfaces however can be more promiscuous,
and it may be profitable to use multiple devices on the same surfaces.
Hopefully not though, since multiple GCs exist to do this sort of thing.

For a GC to become active, it must be _focused_ (and later unfocused) onto a
device, via ppgGC::BeginDraw(ppgDevice& target). This allows for
synchronization with devices (such as GGI visuals) which store GC state data
themselves.  Exactly where the GC ends and the device begins, is dependent on
the device.


ColourModes (ppgColourMode)
-----------
ColorModes are essentially the same sort of thing as X visuals, but
not quite the same.  They store information such as:
   Colour model(RGBA, Colour Indexed, Greyscale etc).
   Depth.
   Bytes per pixel.
   Bit layout of pixels in case of RGBA.
   Colourmap in case of CI.

CModes can be used for describing what you want to a device, or for
it to describe the way the world is.  Actual manipulation of things
like the colourmap is done through interface exported by the device.

CModes are intimately related to the idea of the ppgPixel.  A ppgPixel
is a single datum of colour, I haven't yet decided if it should be 32 bits
guaranteed, or one machine word.  The actual colour represented by
a particular bit pattern stored in a ppgPixel depends on its context,
a ppgColourMode describes the mapping from ppgPixel to a real colour.



ColourMode Conversion
---------------------

You will find colours expressed in different modes.  For example, you might
be conservative and use 4 bit colour indexed data in your data file, and find
yourself running on a 32 bit truecolour display.  Sometimes you will want
to do the conversions yourself, but PPlay can help.  For leisurely
conversions, as might be done for setting the fill colour, we use
Canonical pixels.  Canonical pixels are pixels stored in "Canonical"
format, this is 8b8r8g8a.  ColourModes will have methods for 
converting to and from the format it describes and canonical.
     [Note: for CI modes decononicalization is slow.  Probably can't
     be designed around]
     [Note: X and GGI use 48 bit canonical colours, does that mean we
     should use 64 instead of 32?]
     

For bulk conversions, of the type used for blitting, see blitting.



Blitting
--------

The quintessential task of a 2d graphics system is blitting.
pg2d plans to  provide four types of blits (so far, hopefully 
more won't be needed).

* Plain old 2d rectangular blits
* 2d blits of RLE transparency encoded data. (hmmm, is this a gain nowadays?)
* single line span blits.
* single bit blits which aren't really blits, but are called that anyway.


The other aspect is colourmode conversion.

Every devices have a native colourmodes.  In the case of a GGI surface
that is determined by the video mode, in the case of memory devices,
it determines the format of the pixels sorted in the buffer surfaces.
Data might not come _into_ the surface in the same format though.

One of the goals of play is that you can view the moving of an image from a
surface (even an exotic one like a file) of one type to a surface of another
as a blitting operation (not for arbitrary surface types though).

To facilitate this, pg2d provides two kinds of blits.  Raw ones, in which
input data is in the same format as output data and the blit is done by 
memcpy on something like, and nonraw ones, which involve conversion.

A GC, therefore contains primitives of the form ppgGC::BlitRaw() for
raw blits, and ppgGC::Blit(), the behaviour of which depends on the
GC state.  For example if you want to load sprites from a file, a
GC can be constructed to take File surfaces as input for Blit() operations.

    [Question: should Raw  blits be abolished in favour of making raw blitting
    a matter of GC state?  I think there was some reason why I didn't do this,
    I must read my notes].

GC's will probably expect linear buffer surfaces in cannonical format
by default.  Currently this aspect of the design has been in flux
and I don't actually know what the code does, except that my test
program works (at least on my computer, under a 32 bit X display).
