bitplane.icn: Procedures for bitplane manipulation

procedure AlcPlane:        allocate colors for bitplane
procedure FrontPlane:      move bitplane to front
procedure BackPlane:       move bitplane to back
procedure PlaneOp:         set context for bitplane operation

link bitplane
May 2, 2001; Gregg M. Townsend
Requires: Version 9 graphics
This file is in the public domain.

These procedures allow a window to be treated as a series of
overlapping, independent layers, subject to some fairly severe
restrictions.

AlcPlane(W n)           allocates planes.

FrontPlane(W bp, color) moves a layer to the front.

BackPlane(W bp, color)  moves a layer to the back.

PlaneOp(W bp, op)       initializes layer operations.

Deplane(W color)        restores a window to normal.
____________________________________________________________

   These procedures allow drawing and erasing in individual bitplanes of
a window.  One way to use bitplanes is to think of them as transparent
panes in front of a solid background.  Each pane can be drawn with a
single color, obscuring the panes beyond (and the background).  A pane
can also be erased, wholly or selectively, exposing what is beyond; and
a pane need not be visible to be drawn or erased.  Panes can be restacked
in a different order, and the color of a pane (or the background) can be
changed.

   For example, the pane in back could be drawn with a city map.  The
pane in front of that could be used to lay out bus routes, and the paths
could be erased and rerouted without having to redraw the map.  Using a
third plane in front of those, buses could be moved along the routes
without having to redraw either the routes or the map behind them.

   Bitplanes that are allocated together and interact with each other
form a bitplane group.  A bitplane group need not fill the window;
indeed, it can be used in discontiguous portions of a window or even
in multiple windows on the same display.  On the other hand, multiple
bitplane groups can be used different parts of the same window.

   Bitplanes are implemented using Icon's mutable colors, and they
are gluttonous of color map entries.  A set of n bitplanes requires
at least 2^n color map entries, so the practical limit of n is 5 or 6.
On the other hand, sets of 2 or 3 bitplanes are relatively cheap and
using several of them is not unreasonable.

   Each bitplane group is identified by a base index b, which is the
index of the mutable color representing the background.  The individual
bitplanes are referenced as b+1, b+2, b+4 etc. using powers of two.
Other indices between b and b+2^n (exclusive) control the colors used
used when multiple bitplanes are drawn.  The FrontPlane and BackPlane
procedures provides simple control of these, and more sophisticated
effects (such as making a bitplane partially transparent) are possible
by setting them individually.



AlcPlane([win,] n) -- alc colors for n bitplanes

   AlcPlane allocates a set of 2^n mutable colors chosen to be suitable
for the bitplane manipulations described below.  The colors are
consecutively indexed, and the base value b (the most negative index
value) is returned.  The base color is initialized to the current
background color, and the others are initialized to the foreground color.

   A sequence of AlcPlane calls with different values of n is more
likely to succeed if the larger sets are allocated first.



FrontPlane([win,] bp, color) -- move indexed plane to "front"

   FrontPlane sets the pixels in a bitplane to the given color and
moves the bitplane in front of the others in the set.  The color is
optional.

   bp is the index (base+1, base+2, base+4, or whatever) denoting a
particular bitplane.  The move-to-the-front effect is accomplished by
calling Color() for all colors in the bitplane group whose index
after subtracting the base includes the particular bit.



BackPlane([win,] bp, color) -- move indexed plane to "back"

   BackPlane sets the pixels in a bitplane to the given color and
moves the bitplane in back of the others in the set.  The color is
optional.

   bp is the index (base+1, base+2, base+4, or whatever) denoting a
particular bitplane.  The move-to-the-back effect is accomplished by
calling Color() for all colors in the bitplane group whose index
after subtracting the base includes the particular bit.

   A plane can be effectively rendered invisible by calling
BackPlane(win, bp, base);  this moves it to the back and sets
its color to the color of the background plane.



PlaneOp([win,] bp, op) -- set graphics context for plane operation

   PlaneOp initializes the graphics context for drawing or erasing in
a particular bitplane.  bp is a bitplane index, as for FrontPlane;
multiple bits can be set to draw or erase several bitplanes
simultaneously.  op is usually one of two strings:

     "set"   to draw the bits in a bitplane
     "clear" to erase the bits in a bitplane

Subsequent drawing operations will affect only the bits in the selected
bitplane.  Foreground operations are used for both drawing and erasure:
use FillRectangle, not EraseArea.

   After calling PlaneOp with "set" or "clear", be SURE to draw only
in portions of the screen previously initialized with pixel values
from the same bitplane group.  Drawing anywhere else is liable to
produce strange, unwanted results.  Deplane (below) resets the window
for normal operation.

   The op parameter can also be "copy", in which case the previous
contents of the window are immaterial and the drawn pixels are
initialized with the bitplanes specified.


Deplane([win,] color) -- restore normal drawop and set foreground

   Deplane is called to restore normal drawing operations after setting
or clearing bits in a particular bitplane.  The foreground color can be
changed optionally.



Example:

     b := AlcPlane(win, 3)                   # get 3 planes
     Color(win, b, "white")                  # background will be white
     FrontPlane(win, 1, "gray")              # city map will be gray
     FrontPlane(win, 2, "navy")              # routes will be dark blue
     FrontPlane(win, 4, "red")               # buses will be red
     Fg(win, b)
     DrawRectangle(win, x, y, w, h)          # initialize background
     PlaneOp(win, b+1, "set")
     drawmap()                               # draw map
     repeat {
        PlaneOp(win, b+2, "clear")
        DrawRectangle(x, y, w, h)            # clear old routes
        PlaneOp(win, b+2, "set")
        drawroutes()                         # draw new routes
        while routes_ok() do
           runbuses()                        # run buses using plane b+4
        }



Caveats

   AlcPlane must repeatedly ask for new mutable colors until it gets a
set that is suitable.  Unwanted colors cannot be returned or freed, so
some color table entries are usually wasted.

   No more than 7 bitplanes can be requested, and even that is chancy.

   These routines will be confused by multiple displays.  Multiple
windows on a single display, or multiple bitplane sets in a window,
are no problem.

   These routines depend on the internals of Icon, specifically the
mapping of window-system pixel values to mutable color indices.

   The use of unusual "and" and "or" drawops makes the code hard to
understand.

Source code | Program Library Page | Icon Home Page